Aller au contenu
Sécurité medium

Vault SSH : accès sécurisé aux serveurs

21 min de lecture

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).

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 classiquesAvec Vault SSH
Clé permanente sur le posteCertificat valide quelques heures
authorized_keys à maintenirCA trusted, pas de liste à gérer
Révocation = supprimer la clé partoutTTL courts ; révocation SSH moins intégrée que TLS
Audit : "quelle clé ?"Audit : "quel user Vault, quand"
Rotation = redistributionRotation = nouveau certificat

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.

ModeComment ça marcheRecommandation
Signed certificatesVault signe la clé publique de l'utilisateurRecommandé
OTPVault génère un mot de passe à usage uniqueCas spécifiques (vieux SSH, contraintes sshd)
  • Vault installé et démarré
  • Accès admin pour configurer le moteur
  • Serveurs SSH accessibles avec droits root/sudo pour la configuration

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.

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à.

Flux de signature de certificats SSH par Vault

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.

Fenêtre de terminal
vault secrets enable -path=ssh-client-signer 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.

Fenêtre de terminal
vault write ssh-client-signer/config/ca generate_signing_key=true

Récupérer la clé publique de la CA :

Fenêtre de terminal
vault read -field=public_key ssh-client-signer/config/ca > vault-ca.pub

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) :

Fenêtre de terminal
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ètreDescriptionExemple
key_typeType de signatureca pour certificats
allowed_usersUsers Unix autorisésubuntu,ec2-user ou *
allowed_extensionsExtensions SSH autoriséespermit-pty,permit-agent-forwarding
default_extensionsExtensions par défaut (via API){"permit-pty": ""}
ttlDurée de vie du certificat30m, 4h
max_ttlDurée maximale24h

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.

Fenêtre de terminal
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"

L'utilisateur génère (ou utilise) sa paire de clés :

Fenêtre de terminal
# Si pas de clé existante
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""

Demander la signature à Vault :

Fenêtre de terminal
vault write -field=signed_key ssh-client-signer/sign/dev \
public_key=@$HOME/.ssh/id_ed25519.pub \
valid_principals="ubuntu" \
> ~/.ssh/id_ed25519-cert.pub

Vérifier le certificat :

Fenêtre de terminal
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub

Sortie :

/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

Sur chaque serveur cible :

Fenêtre de terminal
# Copier la CA publique
sudo cp vault-ca.pub /etc/ssh/vault-ca.pub
# Configurer sshd
echo "TrustedUserCAKeys /etc/ssh/vault-ca.pub" | sudo tee -a /etc/ssh/sshd_config
# Redémarrer sshd
sudo systemctl restart sshd

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.

Fenêtre de terminal
ssh -i ~/.ssh/id_ed25519 ubuntu@server.example.com

SSH présente automatiquement le certificat id_ed25519-cert.pub avec la clé privée id_ed25519.

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ôleQui décideParamètre
Rôle VaultAdmin Vaultallowed_users
Demande de signatureUtilisateurvalid_principals
Serveur SSHAdmin systèmeAuthorizedPrincipalsFile

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.

  1. Le rôle dev autorise allowed_users="ubuntu,ec2-user"
  2. L'utilisateur demande un certificat avec valid_principals="ubuntu"
  3. Le certificat contient Principals: ubuntu
  4. Le serveur vérifie que ubuntu est dans /etc/ssh/auth_principals/ubuntu
  5. Connexion autorisée

Vault fournit une commande intégrée qui automatise tout :

Fenêtre de terminal
vault ssh -role=dev -mode=ca ubuntu@server.example.com

Cette commande :

  1. Signe votre clé publique locale
  2. Lance ssh avec le certificat
  3. Nettoie après déconnexion

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èreCertificats signésOTP
VérificationLocale (OpenSSH)Réseau (Vault)
Dépendance VaultÀ la signatureÀ chaque connexion
Prérequis serveurTrustedUserCAKeysvault-ssh-helper + PAM
Version OpenSSH5.6+ (certificats)Toutes
Cas d'usageDéfautVieux SSH, contraintes sshd, migration

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.

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

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.

Fenêtre de terminal
# Activer le moteur
vault secrets enable -path=ssh ssh
# Créer un rôle OTP
vault write ssh/roles/otp-role \
key_type=otp \
default_user=ubuntu \
cidr_list=10.0.0.0/8

Obtenir un OTP :

Fenêtre de terminal
vault write ssh/creds/otp-role ip=10.0.1.50

Sortie :

Key Value
--- -----
lease_id ssh/creds/otp-role/abc123
key 3f4e-a2b1-c9d8-e7f6
username ubuntu
ip 10.0.1.50

Sur le serveur, configurez vault-ssh-helper (voir documentation HashiCorp pour le déploiement du helper PAM).

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.

policy-ssh-dev.hcl
# Signer des certificats avec le rôle dev
path "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"]
}
Fenêtre de terminal
vault policy write ssh-dev policy-ssh-dev.hcl

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.

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.

Fenêtre de terminal
# Ajouter la clé et le certificat à l'agent
ssh-add ~/.ssh/id_ed25519
# Le certificat est automatiquement utilisé
ssh ubuntu@server.example.com

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/bash
set -e
ROLE="dev"
PRINCIPAL="ubuntu"
KEY_PATH="$HOME/.ssh/id_ed25519"
# Vérifier si le certificat existe et est encore valide
if [[ -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
fi
fi
# Obtenir un nouveau certificat
echo "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:"

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ômeCause probableSolution
Permission denied (publickey)Certificat expiréRenouveler le certificat
no matching keyCA non trusted sur le serveurVérifier TrustedUserCAKeys
certificate not valid for userPrincipal incorrectVérifier valid_principals
certificate has expiredTTL trop courtAugmenter le TTL ou renouveler
Connexion lenteOTP + latence réseau VaultPasser aux certificats

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.

Fenêtre de terminal
# Logs sshd détaillés
sudo journalctl -u sshd -f
# Tester manuellement la validation du certificat
ssh-keygen -L -f /tmp/user-cert.pub

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.

Fenêtre de terminal
# Connexion verbeuse
ssh -vvv ubuntu@server.example.com
# Vérifier que le certificat est présenté
# Chercher "Offering public key: ... cert" dans la sortie

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éVaultVous
Signer des certificatsRien à faire
Gérer les TTLRien à 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

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 EditionEnterprise
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
  1. Signed certificates : mode recommandé, pas d'authorized_keys à gérer
  2. CA SSH : Vault génère et détient la CA, distribuer la clé publique
  3. Principals : pivot de l'autorisation, à configurer côté Vault ET serveur
  4. TTL courts : 30 min - 4h, meilleure stratégie de "révocation" pour SSH
  5. TrustedUserCAKeys : configuration serveur pour faire confiance à Vault
  6. OTP : cas spécifiques, introduit une dépendance réseau à chaque connexion
  7. Enterprise : managed keys pour déléguer la signature à un HSM
  8. Vault n'est pas un bastion : il signe, mais ne gère pas les sessions

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn