Je suppose que pour vous connecter via SSH, vous avez l’habitude de copier votre clef sur vos serveurs. C’est ok pour vos serveurs persos mais si vous avez tout un parc de serveurs et d’utlisateurs à gérer, cela peut vite devenir problématique. Vous pouvez bien sûr utiliser un outil comme ansible pour pousser les clefs publiques de vos utilisateurs, j’ai écrit un rôle pour ça et qui prend également en compte l’authentification 2FA mais ce n’est pas le sujet.
On va aborder aujourd’hui une manière beaucoup plus sexy de gérer les connexions de vos utilisateurs sur votre parc de serveurs. La connexion par certificat, gérée par Hashicorp Vault.
Comment ça fonctionne ?
Au lieu de copier les clefs publiques de tous vos utilisateurs sur vos serveurs, vous allez juste copier un certificat généré par Vault et dire au daemon SSH de faire confiance à ce certificat.
Et lorsque vous voudrez vous connecter sur vos serveurs, il faudra préalablement demander à Vault de signer votre clef SSH avec ledit certificat. Cette signature vous permettra de vous authentifier, car le daemon SSH fera confiance au certificat de Vault.
L’avantage de cette solution est que vous n’aurez plus à copier (ou supprimer) les clefs de vos utilisateurs manuellement sur vos serveurs. Vous aurez juste à copier une seule fois le certificat fourni par vault et c’est tout.
La signature de clef ayant une durée de validité très courte (c’est configurable), vos utilisateurs auront à demander une signature avant chaque tentative de connexion. Pour révoquer l’accès de vos utilisateurs, il suffira de révoquer leur certificat Vault.
Et si pour une raison X ou Y, Vault n’est pas joignable ? Je ne pourrai plus me connecter sur mes serveurs ?
Si, vous pourrez, vous avez toujours la possibilité de copier les clefs de vos utilisateurs de confiance, à l’ancienne :p
Voyons maintenant comment mettre tout ça en place.
Mise en place
Je pars du principe ici que vous avez déjà un serveur Vault à disposition. Si ce n’est pas le cas et que vous voulez juste tester, je vous renvoie à la documentation de Vault.
Activation du secret engine SSH pour la signature
Vault dispose de plusieurs secrets engines. Je vous invite à aller faire un tour sur la documentation pour en savoir plus.
Nous allons tout d’abord activer le secret engine ssh sur le path ssh-client-signer:
vault secrets enable -path=ssh-client-signer ssh
Créez ensuite un nouveau couple de clefs SSH pour la signature
ssh-keygen -a 50 -t ed25519 -f ssh-ca-signer -q -N ""
Cette commande va vous générer 2 fichiers:
- une clef privée: ssh-ca-signer
- et sa clef publique: ssh-ca-signer.pub
Créez le certificat vault qui va signer les clefs SSH de vos utilisateurs
Ce certificat se base sur les clefs ssh-ca-signer que vous avez créé précédemment, et fait partie de la configuration de votre secret engine ssh monté sur le path ssh-client-signer:
vault write ssh-client-signer/config/ca \
private_key="$(cat ssh-ca-signer)" \
public_key="$(cat ssh-ca-signer.pub)"
Exportez le certificat public
vault read -field=public_key ssh-client-signer/config/ca > trusted-user-ca-keys.pem
C’est ce certificat que vous allez devoir copier sur tous vos serveurs.
Placez ce fichier sur votre serveur dans /etc/ssh/trusted-user-ca-keys.pem et ajoutez à votre fichier de configuration /etc/ssh/sshd_config:
TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
C’est donc cette ligne qui va dire à votre serveur SSH: Laisse entrer les utilisateurs dont la clef a été signée avec ce certificat.
Il faut bien entendu relancer votre service ssh afin que ce soit pris en compte: systemctl restart sshd.service
Je vous laisse le soin de scripter ça dans un playbook ansible ou autre :-)
Création de rôles dans Vault
Afin de gérer vos utilisateurs et leur connexion SSH à vos serveurs, nous allons maintenant créer des rôles dans le path ssh-client-signer.
rôle ssh-all-user
Voici par exemple un rôle ssh-all-user qui va permettre à vos utilisateurs de se connecter avec n’importe quel utilisateur, grâce au paramètre "allowed_users": "*"
:
vault write ssh-client-signer/roles/ssh-all-users -<<"EOH"
{
"algorithm_signer": "default",
"allow_user_certificates": true,
"allowed_users": "*",
"allowed_extensions": "permit-pty,permit-port-forwarding,permit-user-rc,permit-X11-forwarding,permit-agent-forwarding",
"default_extensions": {
"permit-pty": ""
},
"key_type": "ca",
"ttl": "1m0s"
}
EOH
rôle ssh-ubuntu-user
Un autre exemple de création de rôle qui n’autorisera que les connexions en tant qu’utilisateur dont le login est ubuntu, grâce au paramètre "allowed_users": "ubuntu"
:
vault write ssh-client-signer/roles/ssh-ubuntu-user -<<"EOH"
{
"algorithm_signer": "default",
"allow_user_certificates": true,
"allowed_users": "ubuntu",
"allowed_extensions": "permit-pty,permit-port-forwarding,permit-user-rc,permit-X11-forwarding,permit-agent-forwarding",
"default_extensions": {
"permit-pty": ""
},
"key_type": "ca",
"ttl": "1m0s"
}
EOH
A noter que j’ai défini dans la commande ci-dessus le ttl à une minute ("ttl": "1m0s"
). Ce qui signifie que tout certificat signé par vault sera valide une minute. Au dela d’une minute, vous ne pourrez plus vous authentifier et il faudra redemander un certificat. Libre à vous d’augmenter ou diminuer ce ttl.
Je pense que vous avez compris le principe. Encore une fois, je vous renvoie à la documentation du secret engine SSH si vous souhaitez en savoir plus concernant les différentes options disponibles.
Création des policy
Vous devez donner les autorisation create et update sur les roles ssh que nous venons de créer. Ce sont des policy.
Pour le rôle ssh-all-users:
vault policy write ssh-all-users - << EOF
path "ssh-client-signer/sign/ssh-all-users" {
capabilities = ["create", "update"]
}
EOF
Pour le rôle ssh-ubuntu-user:
vault policy write ssh-ubuntu-user - << EOF
path "ssh-client-signer/sign/ssh-ubuntu-user" {
capabilities = ["create", "update"]
}
EOF
Si vous voulez en savoir plus, allez lire la documentation :-)
Création des tokens utilisateurs
Pour pouvoir signer leurs clefs, vous devez donner à vos utilisateurs un token vault afin qu’ils soient en mesure de demander un certificat avant chaque connexion.
Vous pouvez définir plusieurs policy pour un token donné:
vault token create -field token -policy=ssh-all-users -policy=ssh-ubuntu-user
Donnez ensuite ce token à votre utilisateur afin qu’il puisse signer sa clef SSH personnelle et s’authentifier sur vos serveurs.
Je vous renvoie à la documentation si vous souhaitez en savoir plus sur comment gérer les tokens de Vault.
Mise en place côté client.
Ça y est, tout à été configuré côté serveur SSH et côté Vault, votre administrateur vous a donné un token pour signer votre clef avec Vault, mais concrètement comment allez vous vous connecter ?
connexion avec vault ssh
Vous devez tout d’abord avoir configuré le client vault sur votre poste avec le token donné par votre administrateur.
Il vous faut également un couple de clef SSH personnel :-) J’ai personnellement l’habitude d’utiliser des clefs elliptiques ed25519 qui se trouvent par défaut dans ~/.ssh/id_ed25519
, il faudra le dire à vault car par défault, il va chercher des clefs RSA (par défaut ~/.ssh/rsa
).
Admettons donc que vous souhaitez vous connecter en tant qu’utilisateur ubuntu sur le serveur dev.ubuntu.com, et que votre admin a tout correctement configuré, il vous suffit de vous connecter avec cette commande:
vault ssh \
-mode=ca \
-role=ssh-ubuntu-user \
-mount-point=ssh-client-signer \
-private-key-path=~/.ssh/id_ed25519 \
-public-key-path=~/.ssh/id_ed25519.pub \
-valid-principals=ubuntu \
[email protected]
Si vous souhaitez plutôt vous connecter en tant qu’utilisateur admin, vous utiliserez plutôt le rôle ssh-all-users, il faudra également spécifier le bon principal avec -valid-principals=admin
, ce qui donne:
vault ssh \
-mode=ca \
-role=ssh-all-users \
-mount-point=ssh-client-signer \
-private-key-path=~/.ssh/id_ed25519 \
-public-key-path=~/.ssh/id_ed25519.pub \
-valid-principals=admin \
[email protected]
Méthode alternative
Vous pouvez également demander à Vault de vous afficher votre certificat que vous sauvegarderez par exemple dans un fichier signed-cert.pub
vault write \
-field=signed_key \
ssh-client-signer/sign/ssh-all-users \
public_key=@$HOME/.ssh/id_ed25519.pub \
valid_principals=ubuntu > signed-cert.pub
Vous pouvez afficher les informations de ce certificat (on voit que mon certificat est valide 30 secondes):
ssh-keygen -Lf signed-cert.pub
signed-cert.pub:
Type: [email protected] user certificate
Public key: ED25519-CERT SHA256:h6QTOpFCtIJoNzuT5HgrVp3lksq7F3xbGgKOtvNkkX4
Signing CA: ED25519 SHA256:6wUjUVmnrHg+3aqwYjDXMgMOF49o3VqFNVYrY7H0Bkg (using ssh-ed25519)
Key ID: "vault-token-87a4133a9142b48268373b93e4782b569de592cabb177c5b1a028eb6f364917e"
Serial: 8428675053565845939
Valid: from 2022-10-05T15:00:04 to 2022-10-05T15:01:34
Principals:
ubuntu
Critical Options: (none)
Extensions:
permit-pty
Pour vous connecter, vous devez à la fois spécifier votre clef ssh + votre certificat:
ssh -i signed-cert.pub -i ~/.ssh/id_ed25519 [email protected]
Autres manières de faire
Toutes les commandes ci-dessous permettent de demander un certificat signé:
vault write \
-field=signed_key \
ssh-client-signer/sign/ssh-all-users \
public_key=@$HOME/.ssh/id_ed25519.pub \
valid_principals=ubuntu > signed-cert.pub
vault write -field=signed_key ssh-client-signer/sign/ssh-all-users -<<"EOH" > signed-cert.pub
{
"public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFLbVuUe9JVpHfd4l50sGQoCtZvXuYvNuVpMRheT8+5G",
"valid_principals": "ubuntu"
}
EOH
vault write -field=signed_key ssh-client-signer/sign/ssh-all-users -<<"EOH" > signed-cert.pub{
"public_key": "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFLbVuUe9JVpHfd4l50sGQoCtZvXuYvNuVpMRheT8+5G",
"valid_principals": "ubuntu",
"extensions": {
"permit-pty": "",
"permit-port-forwarding": ""
}
}
EOH
Aller encore plus loin
Nous avons vu comment signer une clef SSH d’un utilisateur ce qui est déjà bien mais pour encore plus de sécurité, vous pouvez en plus activer la signature des clefs SSH du serveur sur lequel vous allez vous connecter.
Lorsque cette fonctionnalité est activée, votre client SSH va vérifier que le serveur distant est bien celui qu’il prétend être, ce qui évite de se connecter accidentellement sur une machine compromise.
Les commandes ci-dessous sont à executer idéalement depuis le serveur distant.
Activation du secret engine SSH pour l’hôte distant
Nous allons activer le secret engine SSH sur un autre path: ssh-host-signer
vault secrets enable -path=ssh-host-signer ssh
Créez ensuite un nouveau couple de clefs SSH
ssh-keygen -a 50 -t ed25519 -f ssh-ca-host -q -N ""
Créez le certificat pour signer les requêtes clientes
vault write ssh-host-signer/config/ca \
private_key="$(cat ssh-ca-host)" \
public_key="$(cat ssh-ca-host.pub)"
Augmentez le TTL du certificat
vault secrets tune -max-lease-ttl=87600h ssh-host-signer
Créez un role pour signer les clefs de votre serveur
vault write ssh-host-signer/roles/hostrole \
key_type=ca \
algorithm_signer=default \
ttl=87600h \
allow_host_certificates=true \
allowed_domains="localdomain,example.com" \
allow_subdomains=true
Signez la clef publique de votre serveur
vault write ssh-host-signer/sign/hostrole \
cert_type=host \
public_key=@/etc/ssh/ssh_host_ecdsa_key.pub
Exportez le certificat signé
vault write -field=signed_key ssh-host-signer/sign/hostrole \
cert_type=host \
public_key=@/etc/ssh/ssh_host_ecdsa_key.pub > /etc/ssh/ssh_host_ecdsa_key-cert.pub
Fixez les permissions
chmod 0640 /etc/ssh/ssh_host_ecdsa_key-cert.pub
Mettez à jour votre fichier de configuration SSH
Modifiez /etc/ssh/sshd_config
en ajoutant ces lignes:
HostKey /etc/ssh/ssh_host_ecdsa_key
HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub
Puis relancez le service SSH.