Retour d’expérience sur le déploiement de deux solutions de bastion SSH avec SSO Keycloak : Teleport et Warpgate. Comparaison, problèmes rencontrés, et automatisation RBAC avec Ansible.
Contexte
Objectif : sécuriser l’accès SSH aux VMs Azure (PROD et DEV) avec :
- Authentification centralisée via Keycloak SSO
- Gestion des rôles (RBAC) par environnement
- Audit des connexions
- Support VSCode Remote-SSH
Teleport vs Warpgate : Comparaison
| Fonctionnalité | Teleport OSS | Warpgate |
|---|---|---|
| Terminal web | ✅ Oui | ❌ Non |
| VSCode Remote-SSH | ✅ Transparent | ⚠️ Approbation manuelle |
| SSO OIDC (Keycloak) | ❌ Enterprise only | ✅ Gratuit |
| SSH standard | Via tsh |
✅ Direct |
| VMs derrière VPN | ✅ Agent outbound | ❌ Proxy doit atteindre VMs |
Verdict
- Teleport : Meilleur pour VSCode et terminal web, mais SSO payant
- Warpgate : SSO gratuit, mais expérience VSCode dégradée
Problèmes rencontrés
1. Teleport + Keycloak : OIDC non supporté en OSS
Problème : Teleport OSS ne supporte pas OIDC/SAML (réservé à Enterprise).
Solution : Utiliser des utilisateurs locaux Teleport avec tctl users add.
# Créer un utilisateur local
tctl users add alice --roles=vm-admin-global,access2. Warpgate + VSCode : URL non cliquable
Problème : L’URL d’approbation SSO n’apparaît pas dans VSCode Remote-SSH.
Tentatives échouées :
{
"remote.SSH.showLoginTerminal": true,
"remote.SSH.useLocalServer": false
}Ces settings causent des blocages après approbation.
Workaround : Garder un onglet Warpgate ouvert dans le navigateur pour approuver manuellement.
3. Teleport : “Too many authentication failures”
Problème : SSH échoue avec trop de clés dans l’agent.
Solution : Ajouter IdentitiesOnly yes dans ~/.ssh/config :
Host teleport-*
ProxyCommand tsh proxy ssh %r@%h:%p
IdentitiesOnly yes
4. Teleport : Version mismatch agents/serveur
Problème : Agents en 14.4.1, serveur en 14.3.36 → comportements incohérents.
Solution : Aligner toutes les versions :
# jobs/infra/teleport.nomad.hcl
image = "public.ecr.aws/gravitational/teleport:14.4.1"
5. VMs DEV (VPN) : Accès via Teleport sans VPN
Problème : Les VMs DEV sont sur IPs privées (172.x.x.x), accessibles uniquement via VPN.
Solution : L’agent Teleport se connecte en outbound vers le proxy public. Une fois l’agent installé, plus besoin de VPN.
VM DEV (172.x.x.x) ──outbound──▶ teleport.example.com
(agent) (proxy public)
Installation one-time (nécessite VPN) :
ssh -i ~/.ssh/key-dev.pem ubuntu@172.30.16.28 "bash -s" < install-agent.sh6. Scripts Windows : Line endings CRLF
Problème : Scripts bash avec fins de ligne Windows → $'\r': command not found
Solution :
# Convertir localement
sed -i 's/\r$//' script.sh
# Ou ajouter .gitattributes
*.sh text eol=lfRBAC avec Ansible
Structure
ansible/teleport/
├── users.yml # Définition des utilisateurs et rôles
├── sync-users.yml # Playbook de synchronisation
└── README.md
users.yml
users:
- name: alice
roles:
- vm-admin-global
email: alice@example.com
- name: bob
roles:
- vm-user-dev-server1
email: bob@example.com
- name: charlie
roles:
- vm-readonly-global
email: charlie@example.comPlaybook sync-users.yml
- name: Sync Teleport Users
hosts: localhost
tasks:
- name: Load users from YAML
include_vars:
file: users.yml
name: config
- name: Update existing users
shell: |
ssh bastion "nomad alloc exec {{ alloc }} tctl users update {{ item.name }} --set-roles={{ item.roles | join(',') }},access"
loop: "{{ config.users }}"
when: item.name in existing_users
- name: Create new users
shell: |
ssh bastion "nomad alloc exec {{ alloc }} tctl users add {{ item.name }} --roles={{ item.roles | join(',') }},access"
loop: "{{ config.users }}"
when: item.name not in existing_usersUsage
# Mode dry-run
ansible-playbook ansible/teleport/sync-users.yml --check
# Appliquer
ansible-playbook ansible/teleport/sync-users.ymlRésultat
TASK [Summary]
ok: [localhost] => {
"msg": "Sync completed:\n- Total users in config: 10\n- Existing users updated: 10\n- New users created: 0\n"
}
Commandes Azure utiles
Récupérer les infos des VMs sans VPN (via API Azure) :
# Lister les VMs DEV
az vm list --subscription MY-SUBSCRIPTION -d -o table \
--query "[].{Name:name, Hostname:osProfile.computerName, PrivateIP:privateIps}"
# Démarrer les VMs
az vm start --subscription MY-SUBSCRIPTION -g MY-RG -n my-vm --no-wait
# Éteindre les VMs
az vm deallocate --subscription MY-SUBSCRIPTION -g MY-RG -n my-vm --no-waitMonitoring avec Grafana
Dashboard Grafana pour monitorer Teleport :

Métriques disponibles (Teleport OSS)
| Métrique | Description |
|---|---|
teleport_connected_resources{type="node"} |
Nodes connectés |
teleport_active_connections |
Connexions actives |
teleport_registered_servers |
Serveurs enregistrés |
teleport_audit_emit_events |
Événements d’audit |
teleport_user_certificates_generated |
Certificats générés |
Configuration Prometheus
scrape_configs:
- job_name: 'teleport'
static_configs:
- targets: ['teleport:3434']Note : Teleport OSS expose des métriques différentes de la version Enterprise. Les métriques comme teleport_audit_events_total n’existent pas en OSS.
Architecture finale
Internet
│
▼
┌───────────────────────────────────────────────────────┐
│ teleport.example.com:443 │
│ (Proxy + Auth sur Nomad) │
└───────────────────────────────────────────────────────┘
▲ ▲ ▲ ▲
│ │ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐ outbound
│ server1 │ │ server2 │ │ server3 │ HTTPS
│ (PROD) │ │ (PROD) │ │ (DEV) │ │
└─────────┘ └─────────┘ └─────────┘ │
┌────┴────┐
│ dev-vm │
│(DEV/VPN)│
└─────────┘
Conclusion
| Critère | Recommandation |
|---|---|
| VSCode Remote-SSH | Teleport |
| Terminal web | Teleport |
| SSO gratuit | Warpgate |
| VMs derrière VPN | Teleport (agents outbound) |
| RBAC automatisé | Ansible + YAML |
Teleport est le meilleur choix malgré l’absence de SSO gratuit, car l’expérience utilisateur (VSCode, terminal web) est bien meilleure.