Journal Dédier une clé SSH au rebond sur un serveur

Posté par  (site web personnel) . Licence CC By‑SA.
42
8
déc.
2023

Sommaire

Bonjour nal,

Pour du développement, j'ai besoin d'administrer en SSH un serveur cible accessible depuis un serveur bastion. Dans ce document, j'explique comment dédier une clé SSH pour se connecter au bastion sans que cette clé ne puisse servir à rien d'autre qu'à rebondir vers d'autres serveurs.

On va parler de plein d'autres choses avant d'arriver au résultat.

Rebondir avec ProxyJump

On connaît l'option -J de SSH (ou ProxyJump dans ~/.ssh/config) qui permet de faire ça simplement :

ssh -J bastion cible

Ça ouvre une connexion SSH sur bastion et, à travers cette connexion, on ouvre une connexion SSH depuis mon PC vers la cible.

Parenthèse : Je rappelle au passage que l'idée alternative, consistant à utiliser ForwardAgent pour rendre accessible l'agent SSH qui tourne sur mon poste au programme SSH qui tourne sur bastion pour accéder à la clé privée permettant d'ouvrir la connexion vers cible est une très mauvaise idée : elle permet à celui qui administre le bastion d'utiliser toutes vos clés privées SSH pour se connecter à tout ce qu'il veut (c'est ce qui est arrivé à Matrix.org en avril 2019). On fait les choses bien, on utilise ProxyJump (qui est un wrapper autour de ProxyCommand, et voici comment fonctionne ProxyCommand), fin de la parenthèse.

Séparer les clés par niveau de sécurité

Je distingue mes clés SSH par niveau de sécurité :
- peu sécurisée : des clés sous forme de fichiers à plat (~/.ssh/id_...) sans mot de passe. Attaque: pour accéder à ma clé, le programme malveillant a juste besoin d'avoir accès en lecture au fichier.
- mieux sécurisée : des clés sous forme de fichiers à plat (~/.ssh/id_...), simplement protégées par mot de passe et chargées dans l'agent SSH pour ne pas avoir à retaper le mot de passe à chaque fois. Attaque: pour accéder à ma clé, le programme malveillant doit exécuter du code dans mon contexte et parler à mon agent SSH. Il ne peut pas extraire la clé mais peut l'utiliser pour se connecter sans mon accord. Il peut aussi essayer de trouver mon mot de passe en remplaçant la commande ssh-agent.
- mieux sécurisée (bis) : des clés dont la partie privée est non extractible car stockée sur un périphérique matériel dédié, par exemple sur un TPM ou une smartcard GPG ou x509. Attaque: idem.
- très sécurisée : une clé dont la partie privée est non extractible car stockée sur une yubikey qui me demande de confirmer chaque connexion par un appui tactile. Attaque: pour utiliser ma clé, le programme malveillant doit tenter d'ouvrir une connexion juste avant moi, attendre que je clique sur le bouton et faire ses dégâts sur le serveur distant avant que je ne réalise que mon appui ne m'a pas permis d'ouvrir la connexion que je voulais.

Se connecter à la cible est une opération plus ou moins sensible, selon ce qui est hébergé sur ce serveur (données de tests ou données de production, données triviales ou données sensibles …). Je choisis le niveau de sécurité de la clé en fonction de ce niveau de sensibilité.

Rebondir n'est pas une opération "sensible"

Mais se connecter au bastion pour rebondir ne doit pas être une opération sensible en soi : il n'y a pas de raison de taper deux fois sur ma yubikey pour parvenir à ma cible.

Sauf que, par défaut, la clé qui me sert à rebondir sert aussi à me connecter en SSH au bastion : à exécuter des commandes, à copier des fichiers, etc.

Mon soucis est donc le suivant : comment faire pour que la clé qui me sert à me connecter au bastion ne puisse pas servir à autre chose qu'à rebondir vers d'autres serveurs ?
Autrement dit, comment bloquer tous les autres usages de SSH spécifiquement pour cette clé de rebond ?

La solution : command=ssh,restrict,permit-open

Le problème semble simple, mais je n'ai trouvé nulle part la réponse. La configuration que j'ai trouvée, et que je soumets à votre sagacité, consiste à indiquer dans ~/.ssh/authorized_keys sur bastion :

command="ssh",restrict,port-forwarding ssh-rsa AAAAB3Nza......  ma-cle-peu-securisee
  • command="ssh" force l'exécution de ssh dès qu'on se connecte à la machine. Je ne comprends pas bien pourquoi ça suffit pour exécuter ssh cible <options_ésotériques_utilisées_par_ProxyJump>, mais ça marche
  • restrict interdit a peu près tout
  • port-forwarding réautorise le passage de port entre bastion et ma machine, nécessaire pour atteindre cible

Dès lors :

  • ✅ Le rebond via -J fonctionne
  • ssh bastion -i ma-cle-peu-securisee -> PTY allocation request failed on channel 0. Connection to bastion closed.
  • scp bastion:~/.ssh/authorized_keys ./ -> scp: Connection closed (et le fichier n'est pas récupéré)

Objectif atteint.

Et si je dois administrer bastion avec une clé plus sécurisée ?

J'ai aussi une ligne dans .ssh/authorized_keys sur bastion qui m'autorise à me connecter avec ma yubikey pour l'administrer. Mais ma clé peu sécurisée est tentée la première, elle est acceptée et la connexion se ferme, sans que les clés suivantes ne soient pas tentées (contrairement à ce qui se serait passé si la clé peu sécurisée avait été rejetée d'emblée).

Pour contourner le problème, il faut exporter la clé publique SSH associée à la clé privée yubikey dans un fichier (par exemple, s'il s'agit d'une clé GPG sur la yubikey, avec gpg --export-ssh-key <KEYID> > ~/.ssh/yubikey.pub), puis indiquer cette identité lors de la connexion :

ssh -i ~/.ssh/yubikey.pub bastion

Voilà, comme j'ai passé un temps non nul sur ce que je pensais être assez trivial et que je n'ai pas trouvé de gens ayant documenté ça ailleurs (j'ai peut-être mal cherché), je me suis permis de partager ça ici. N'hésitez pas à corriger ou signaler des points aveugles en commentaire.

  • # Merci

    Posté par  . Évalué à 5.

    Merci pour ces explications, c'est chouette !

    Est-ce que ça contourne le bridage de commandes si tu fais : ssh -J bastion bastion ?

    Pour le dernier point (ssh -i) j'utilise beaucoup des directives Host dans mon .ssh/config, ça pourrait donner par exemple :

    Host bastion
    IdentityFile cleA
    
    Host bastion-adm
    IdentityFile cleB
    

    Enfin, je me demande comment ça se passe si la clé sur le bastion a besoin d'un déverrouillage via Smartcard ou Yubikey justement. Le Forwarding d'agent, malgré ses défauts, ne sert-il pas à cela ? (j'ai pas trop creusé, juste curieux).

    • [^] # Re: Merci

      Posté par  (site web personnel) . Évalué à 3.

      Est-ce que ça contourne le bridage de commandes si tu fais : ssh -J bastion bastion

      Non : la première connexion au bastion fonctionne, mais la seconde tente d'ouvrir un shell et elle ne peut pas, elle échoue.

      Enfin, je me demande comment ça se passe si la clé sur le bastion a besoin d'un déverrouillage via Smartcard ou Yubikey justement.

      Je ne comprends pas la situation que tu as en tête. "la clé sur le bastion" = la clé publique autorisée à se connecter, celle présente dans authorized_keys ? Ou une clé privée permettant de se connecter à un serveur cible ?

      Dans tous les cas, si tu as une clé qui demande une confirmation physique pour chaque utilisation, elle ne peut pas être utilisée sans ton accord par l'agent SSH même en cas de forwarding d'agent sur le bastion. Cependant, le bastion peut tout de même utiliser toutes les clés auxquelles l'agent a accès pour se connecter ailleurs, donc ça reste une situation risquée. À moins de n'avoir que des clés stockées sur des yubikey et soumises à confirmation, auquel cas l'agent ne sert à rien.

      Bref, je ne vois pas de situation où le forwarding d'agent serait une bonne idée.

      • [^] # Re: Merci

        Posté par  . Évalué à 4.

        En effet, j'aurais du lire le lien que tu as donné. Je n'avais pas compris que le ProxyJump faisait un tunnel entre la machine d'origine et la cible, sans que le bastion n'ai besoin de s'authentifier lui-même. Je pensais qu'il y avait une authentification par clé également depuis le bastion.

        Pour résumer, l'hypothétique "clé sur le bastion" de ma question n'existe pas. Contrairement à ce qu'il se passe avec The Bastion, par exemple.

        Merci pour les éclaircissements !

  • # wireguard

    Posté par  . Évalué à 3.

    J'ai eu à faire du reverse SSH pour administrer des linux embarqués avec une connectivité 4g mais sans IP public.
    jusqu'au jour au j'ai trouvé wireguard et là ma vie est devenue tellement plus simple.

    est ce que l'utilisation de wireguard ne permettrait pas même chose sans les clés avec différent niveau de criticité ?

    merci encore pour le partage

  • # Parenthèse et ForwardAgent

    Posté par  (site web personnel) . Évalué à 5. Dernière modification le 11 décembre 2023 à 18:36.

    Je suis d'accord sur le cas : laptop -> bastion(s) -> cible, avec la clé privée uniquement sur laptop, -J est la meilleure solution pour se protéger de l'accès à la socket ssh sur le bastion ou la cible, ou pour éviter d'avoir une clé privée qui serait sur le bastion ou la cible. (C'est ce que dit man ssh d'ailleurs)

    Maintenant, si je ne me gourre pas, si la cible mentionnée devient plus tard l'origine de nouvelles connexions ssh (ex: par exemple cible sert de contrôleur ansible pour aller déployer sur d'autres destinations), le -J fait depuis laptop n'aidera pas, et il faudra soit du ForwardAgent, soit stocker une clé privée (qui peut être distincte de la précédente) sur cible. (L'échappement ~~ permet de rajouter des tunnels pour des ports donnés, mais ça n'aidera pas non plus pour utiliser la clé ssh de laptop). Avec la problématique de faire confiance soit pour la clé, soit pour le ForwardAgent… ou de ne pas faire ça du tout.

    laptop -> bastion(s) -> cible
    Puis
    cible -> serveur(s)

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.