Vault SSH secrets engine permet de signer des certificats SSH ou de générer des OTP pour l'accès aux serveurs. Plus de clés permanentes à distribuer : chaque accès est temporaire et traçable.
Ce guide couvre le mode signed certificates (recommandé) et le mode OTP (cas spécifiques).
Pourquoi Vault pour l'accès SSH
Section intitulée « Pourquoi Vault pour l'accès SSH »Le modèle classique dépose une clé publique dans le fichier authorized_keys
de chaque compte, sur chaque serveur. Le problème n'est pas cryptographique, il
est organisationnel : rien ne relie durablement une clé à une identité, et
retirer un accès suppose de repasser sur toutes les machines. Vault remplace
cette distribution par une autorité de certification (CA, l'entité qui
signe et dont la signature fait foi) dont la clé publique n'est déposée qu'une
seule fois par serveur.
| Clés SSH classiques | Avec Vault SSH |
|---|---|
| Clé permanente sur le poste | Certificat valide quelques heures |
| authorized_keys à maintenir | CA trusted, pas de liste à gérer |
| Révocation = supprimer la clé partout | TTL courts ; révocation SSH moins intégrée que TLS |
| Audit : "quelle clé ?" | Audit : "quel user Vault, quand" |
| Rotation = redistribution | Rotation = nouveau certificat |
Modes supportés : signed certificates vs OTP
Section intitulée « Modes supportés : signed certificates vs OTP »Le moteur SSH expose deux modes qui ne reposent pas sur le même mécanisme de
vérification. Les certificats signés sont validés localement par OpenSSH,
sans appel réseau. Les OTP (One-Time Password, mot de passe à usage unique)
exigent un composant supplémentaire installé sur chaque serveur. Le mode se
choisit au niveau du rôle, via le paramètre key_type.
| Mode | Comment ça marche | Recommandation |
|---|---|---|
| Signed certificates | Vault signe la clé publique de l'utilisateur | Recommandé |
| OTP | Vault génère un mot de passe à usage unique | Cas spécifiques (vieux SSH, contraintes sshd) |
Prérequis
Section intitulée « Prérequis »- Vault installé et démarré
- Accès admin pour configurer le moteur
- Serveurs SSH accessibles avec droits root/sudo pour la configuration
Mode signed certificates
Section intitulée « Mode signed certificates »Dans ce mode, Vault tient le rôle d'autorité de certification SSH. La clé privée de l'utilisateur ne quitte jamais son poste : Vault reçoit uniquement la clé publique, la signe, et retourne un certificat de courte durée. Les cinq étapes qui suivent s'exécutent dans l'ordre : les trois premières se font côté Vault et une seule fois, les deux dernières concernent l'utilisateur et le serveur cible.
Architecture
Section intitulée « Architecture »Le schéma résume les trois échanges : l'utilisateur demande la signature de sa clé publique, Vault renvoie un certificat horodaté, et le serveur le valide hors ligne à partir de la clé publique de la CA qu'il détient déjà.
Étape 1 : activer le moteur SSH
Section intitulée « Étape 1 : activer le moteur SSH »Le moteur est monté sur un chemin explicite, ssh-client-signer. Ce chemin
apparaît ensuite dans toutes les policies et dans les commandes de
signature : le fixer maintenant évite de tout réécrire plus tard.
vault secrets enable -path=ssh-client-signer sshÉtape 2 : générer la CA SSH
Section intitulée « Étape 2 : générer la CA SSH »generate_signing_key=true demande à Vault de créer lui-même la paire de clés
de la CA. La clé privée reste dans Vault et n'est jamais exposée ; seule la
partie publique est lisible.
vault write ssh-client-signer/config/ca generate_signing_key=trueRécupérer la clé publique de la CA :
vault read -field=public_key ssh-client-signer/config/ca > vault-ca.pubÉtape 3 : créer un rôle de signature
Section intitulée « Étape 3 : créer un rôle de signature »Le rôle définit ce qu'un porteur de token a le droit de faire signer : quels comptes Unix, quelles extensions SSH, et pour combien de temps. C'est le point de contrôle principal côté Vault.
Alternative CLI (sans default_extensions, les extensions seront
demandées à la signature) :
vault write ssh-client-signer/roles/admin \ key_type="ca" \ allowed_users="*" \ allow_user_certificates=true \ allowed_extensions="permit-pty,permit-port-forwarding" \ ttl="30m" \ max_ttl="24h"| Paramètre | Description | Exemple |
|---|---|---|
key_type | Type de signature | ca pour certificats |
allowed_users | Users Unix autorisés | ubuntu,ec2-user ou * |
allowed_extensions | Extensions SSH autorisées | permit-pty,permit-agent-forwarding |
default_extensions | Extensions par défaut (via API) | {"permit-pty": ""} |
ttl | Durée de vie du certificat | 30m, 4h |
max_ttl | Durée maximale | 24h |
Rôle restrictif (exemple production)
Section intitulée « Rôle restrictif (exemple production) »Ce rôle dev énumère les comptes Unix autorisés au lieu du joker, et n'accorde
que l'extension permit-pty, c'est-à-dire l'ouverture d'un terminal
interactif, sans redirection de port ni transfert d'agent.
vault write ssh-client-signer/roles/dev \ key_type="ca" \ allowed_users="ubuntu,ec2-user" \ allow_user_certificates=true \ allowed_extensions="permit-pty" \ default_extensions='{"permit-pty": ""}' \ ttl="4h" \ max_ttl="8h"Étape 4 : signer une clé publique
Section intitulée « Étape 4 : signer une clé publique »L'utilisateur génère (ou utilise) sa paire de clés :
# Si pas de clé existantessh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""Demander la signature à Vault :
vault write -field=signed_key ssh-client-signer/sign/dev \ public_key=@$HOME/.ssh/id_ed25519.pub \ valid_principals="ubuntu" \ > ~/.ssh/id_ed25519-cert.pubVérifier le certificat :
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pubSortie :
/home/user/.ssh/id_ed25519-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com user certificate Public key: ED25519-CERT SHA256:abc123... Signing CA: ED25519 SHA256:xyz789... Key ID: "vault-token-abc123" Serial: 1234567890 Valid: from 2026-03-16T10:00:00 to 2026-03-16T14:00:00 Principals: ubuntu Critical Options: (none) Extensions: permit-ptyÉtape 5 : configurer le serveur SSH
Section intitulée « Étape 5 : configurer le serveur SSH »Sur chaque serveur cible :
# Copier la CA publiquesudo cp vault-ca.pub /etc/ssh/vault-ca.pub
# Configurer sshdecho "TrustedUserCAKeys /etc/ssh/vault-ca.pub" | sudo tee -a /etc/ssh/sshd_config
# Redémarrer sshdsudo systemctl restart sshdConnexion SSH
Section intitulée « Connexion SSH »Aucune option supplémentaire n'est nécessaire : OpenSSH cherche
automatiquement le fichier id_ed25519-cert.pub à côté de la clé privée
passée à -i.
ssh -i ~/.ssh/id_ed25519 ubuntu@server.example.comSSH présente automatiquement le certificat id_ed25519-cert.pub avec
la clé privée id_ed25519.
Principals : le pivot de l'autorisation SSH
Section intitulée « Principals : le pivot de l'autorisation SSH »Le certificat signé ne dit pas seulement "cette clé est valide". Il embarque des principals qui déterminent en tant que quel user Unix le porteur peut se connecter.
| Niveau de contrôle | Qui décide | Paramètre |
|---|---|---|
| Rôle Vault | Admin Vault | allowed_users |
| Demande de signature | Utilisateur | valid_principals |
| Serveur SSH | Admin système | AuthorizedPrincipalsFile |
Exemple de chaîne de validation
Section intitulée « Exemple de chaîne de validation »La séquence suivante montre où chaque filtre intervient, depuis la restriction posée dans le rôle Vault jusqu'à la décision finale du serveur.
- Le rôle
devautoriseallowed_users="ubuntu,ec2-user" - L'utilisateur demande un certificat avec
valid_principals="ubuntu" - Le certificat contient
Principals: ubuntu - Le serveur vérifie que
ubuntuest dans/etc/ssh/auth_principals/ubuntu - Connexion autorisée
Helper : vault ssh
Section intitulée « Helper : vault ssh »Vault fournit une commande intégrée qui automatise tout :
vault ssh -role=dev -mode=ca ubuntu@server.example.comCette commande :
- Signe votre clé publique locale
- Lance ssh avec le certificat
- Nettoie après déconnexion
Quand choisir certificats signés ou OTP
Section intitulée « Quand choisir certificats signés ou OTP »La différence décisive tient à l'endroit où se fait la vérification. Avec un certificat signé, OpenSSH valide seul la signature : Vault peut être indisponible, les connexions continuent tant que les certificats en circulation n'ont pas expiré. Avec l'OTP, chaque connexion interroge Vault, ce qui en fait une dépendance de disponibilité au moment précis de l'authentification.
| Critère | Certificats signés | OTP |
|---|---|---|
| Vérification | Locale (OpenSSH) | Réseau (Vault) |
| Dépendance Vault | À la signature | À chaque connexion |
| Prérequis serveur | TrustedUserCAKeys | vault-ssh-helper + PAM |
| Version OpenSSH | 5.6+ (certificats) | Toutes |
| Cas d'usage | Défaut | Vieux SSH, contraintes sshd, migration |
Mode OTP (cas spécifiques)
Section intitulée « Mode OTP (cas spécifiques) »Le mode OTP génère un mot de passe à usage unique. Le serveur doit
exécuter un helper (vault-ssh-helper) qui valide l'OTP auprès de Vault.
Quand utiliser OTP
Section intitulée « Quand utiliser OTP »Trois situations justifient encore ce mode, toutes liées à une contrainte sur le serveur plutôt qu'à un choix d'architecture.
- Serveurs sans support certificats (très vieux OpenSSH)
- Environnements où vous ne pouvez pas modifier
sshd_config - Transition depuis des mots de passe classiques
Configuration basique OTP
Section intitulée « Configuration basique OTP »Un rôle OTP ne signe rien : il déclare le compte Unix cible et la plage
d'adresses (cidr_list) depuis laquelle les mots de passe générés seront
acceptés.
# Activer le moteurvault secrets enable -path=ssh ssh
# Créer un rôle OTPvault write ssh/roles/otp-role \ key_type=otp \ default_user=ubuntu \ cidr_list=10.0.0.0/8Obtenir un OTP :
vault write ssh/creds/otp-role ip=10.0.1.50Sortie :
Key Value--- -----lease_id ssh/creds/otp-role/abc123key 3f4e-a2b1-c9d8-e7f6username ubuntuip 10.0.1.50Sur le serveur, configurez vault-ssh-helper (voir documentation
HashiCorp pour le déploiement du helper PAM).
Policy pour l'accès SSH
Section intitulée « Policy pour l'accès SSH »Une policy Vault autorise des chemins, pas des rôles. Pour cantonner un
utilisateur au rôle dev, on lui accorde l'écriture sur
ssh-client-signer/sign/dev et rien d'autre : il ne pourra pas demander une
signature avec un rôle plus permissif. La lecture de config/ca reste utile
pour comparer l'empreinte de la CA depuis le poste client.
# Signer des certificats avec le rôle devpath "ssh-client-signer/sign/dev" { capabilities = ["create", "update"]}
# Lire la clé publique de la CA (pour vérification)path "ssh-client-signer/config/ca" { capabilities = ["read"]}vault policy write ssh-dev policy-ssh-dev.hclIntégration : ssh-agent et renouvellement
Section intitulée « Intégration : ssh-agent et renouvellement »Un certificat à TTL court doit être renouvelé, sinon la connexion échoue en
pleine session de travail. Deux briques se complètent : ssh-agent, qui évite
de ressaisir la passphrase de la clé privée, et un renouvellement déclenché
avant l'expiration plutôt qu'après l'échec.
Avec ssh-agent
Section intitulée « Avec ssh-agent »On ajoute la clé privée, pas le certificat : ssh-add charge
automatiquement le fichier -cert.pub correspondant s'il se trouve dans le
même répertoire.
# Ajouter la clé et le certificat à l'agentssh-add ~/.ssh/id_ed25519
# Le certificat est automatiquement utiliséssh ubuntu@server.example.comScript de renouvellement automatique
Section intitulée « Script de renouvellement automatique »Le script compare la date d'expiration du certificat courant à l'heure système et ne redemande une signature que s'il reste moins de dix minutes de validité, ce qui évite de solliciter Vault à chaque connexion.
#!/bin/bashset -e
ROLE="dev"PRINCIPAL="ubuntu"KEY_PATH="$HOME/.ssh/id_ed25519"
# Vérifier si le certificat existe et est encore valideif [[ -f "${KEY_PATH}-cert.pub" ]]; then EXPIRY=$(ssh-keygen -L -f "${KEY_PATH}-cert.pub" 2>/dev/null | grep "Valid:" | grep -oP 'to \K[^ ]+') if [[ -n "$EXPIRY" ]]; then EXPIRY_TS=$(date -d "$EXPIRY" +%s 2>/dev/null || echo 0) NOW_TS=$(date +%s) # Renouveler si expire dans moins de 10 minutes if (( EXPIRY_TS - NOW_TS > 600 )); then echo "Certificat encore valide jusqu'à $EXPIRY" exit 0 fi fifi
# Obtenir un nouveau certificatecho "Renouvellement du certificat SSH..."vault write -field=signed_key "ssh-client-signer/sign/${ROLE}" \ public_key=@"${KEY_PATH}.pub" \ valid_principals="$PRINCIPAL" \ > "${KEY_PATH}-cert.pub"
echo "Certificat renouvelé"ssh-keygen -L -f "${KEY_PATH}-cert.pub" | grep "Valid:"Dépannage
Section intitulée « Dépannage »Les échecs d'authentification par certificat renvoient presque tous le même
message côté client, Permission denied (publickey), quel que soit le motif
réel : certificat expiré, CA inconnue du serveur ou principal refusé. Le
tableau relie les symptômes observables aux causes probables, à confirmer avec
les commandes de diagnostic qui suivent.
| Symptôme | Cause probable | Solution |
|---|---|---|
Permission denied (publickey) | Certificat expiré | Renouveler le certificat |
no matching key | CA non trusted sur le serveur | Vérifier TrustedUserCAKeys |
certificate not valid for user | Principal incorrect | Vérifier valid_principals |
certificate has expired | TTL trop court | Augmenter le TTL ou renouveler |
| Connexion lente | OTP + latence réseau Vault | Passer aux certificats |
Debug côté serveur
Section intitulée « Debug côté serveur »Le journal de sshd indique si un certificat a été présenté et pour quelle
raison il a été rejeté ; ssh-keygen -L relit son contenu en clair, principals
et dates comprises.
# Logs sshd détailléssudo journalctl -u sshd -f
# Tester manuellement la validation du certificatssh-keygen -L -f /tmp/user-cert.pubDebug côté client
Section intitulée « Debug côté client »Le mode verbeux liste les clés et certificats proposés au serveur, dans l'ordre, avant même la réponse de celui-ci.
# Connexion verbeusessh -vvv ubuntu@server.example.com
# Vérifier que le certificat est présenté# Chercher "Offering public key: ... cert" dans la sortieCe que le moteur SSH ne fait pas
Section intitulée « Ce que le moteur SSH ne fait pas »Vault couvre l'émission des certificats et leur expiration. Tout ce qui
relève de la distribution de la confiance et de la configuration de sshd
reste à votre charge, et c'est précisément là que se concentrent les erreurs de
mise en production. Le tableau ci-dessous partage explicitement les
responsabilités.
| Responsabilité | Vault | Vous |
|---|---|---|
| Signer des certificats | ✅ | Rien à faire |
| Gérer les TTL | ✅ | Rien à faire |
| Distribuer la CA publique | ❌ | ✅ |
| Configurer sshd | ❌ | ✅ |
| Gérer la clé privée utilisateur | ❌ | ✅ |
| Gérer les principals autorisés | ✅ (rôles) | ✅ (AuthorizedPrincipalsFile) |
| Révocation (CRL SSH) | ⚠️ Limité | ✅ |
| Remplacer un bastion / PAM | ❌ | ✅ |
| Distribuer automatiquement la confiance OpenSSH | ❌ | ✅ |
CE vs Enterprise : CA SSH et HSM
Section intitulée « CE vs Enterprise : CA SSH et HSM »Tout ce qui précède fonctionne en Community Edition : la génération de la CA, la signature de certificats et le mode OTP n'exigent aucune licence. Seule la délégation des opérations de signature à un matériel cryptographique externe relève de l'édition Enterprise.
| Fonctionnalité | Community Edition | Enterprise |
|---|---|---|
| Générer une CA SSH dans Vault | ✅ | ✅ |
| Signer des certificats | ✅ | ✅ |
| Mode OTP | ✅ | ✅ |
| Managed keys (HSM/KMS externe) | ❌ | ✅ |
| Déléguer la signature à un HSM | ❌ | ✅ |
À retenir
Section intitulée « À retenir »- Signed certificates : mode recommandé, pas d'authorized_keys à gérer
- CA SSH : Vault génère et détient la CA, distribuer la clé publique
- Principals : pivot de l'autorisation, à configurer côté Vault ET serveur
- TTL courts : 30 min - 4h, meilleure stratégie de "révocation" pour SSH
- TrustedUserCAKeys : configuration serveur pour faire confiance à Vault
- OTP : cas spécifiques, introduit une dépendance réseau à chaque connexion
- Enterprise : managed keys pour déléguer la signature à un HSM
- Vault n'est pas un bastion : il signe, mais ne gère pas les sessions