Comment puis-je transférer une clé gpg via ssh-agent?

29

Je peux utiliser le fichier de configuration ssh pour permettre le transfert des clés ssh ajoutées à ssh-agent. Comment puis-je faire de même avec les clés gpg?

txwikinger
la source
3
Les deux réponses suggèrent d'exécuter socat pour exposer le socket unix de l'agent GPG sur un port tcp. Cependant, contrairement aux sockets Unix, les ports TCP n'ont pas le même niveau sur le contrôle d'accès. En particulier, chaque utilisateur sur le même hôte peut désormais se connecter à votre agent GPG. Cela est probablement correct si vous avez un ordinateur portable mono-utilisateur, mais si d'autres utilisateurs peuvent également se connecter au même système (le système sur lequel l'agent GPG s'exécute), ils peuvent également accéder à votre agent GPG, ce qui pose un problème de sécurité important. Laisser socat démarrer directement SSH en utilisant le type d'adresse EXEC est probablement le meilleur moyen de résoudre ce problème.
Matthijs Kooijman
Pour une autre présentation de la solution openssh 6.7+, voir 2015.rmll.info/IMG/pdf/an-advanced-introduction-to-gnupg.pdf
phs
Cela m'a été utile.
phs

Réponses:

16

EDIT: Cette réponse est obsolète maintenant qu'un support approprié a été implémenté dans OpenSSH, voir la réponse de Brian Minton.

SSH est uniquement capable de transmettre des connexions TCP dans le tunnel.

Vous pouvez, cependant, utiliser un programme comme socatpour relayer la socket unix sur TCP, avec quelque chose comme ça (vous aurez besoin de socat à la fois sur le client et les hôtes du serveur):

# Get the path of gpg-agent socket:
GPG_SOCK=$(echo "$GPG_AGENT_INFO" | cut -d: -f1)

# Forward some local tcp socket to the agent
(while true; do
    socat TCP-LISTEN:12345,bind=127.0.0.1 UNIX-CONNECT:$GPG_SOCK;
done) &

# Connect to the remote host via ssh, forwarding the TCP port
ssh -R12345:localhost:12345 host.example.com

# (On the remote host)
(while true; do
    socat UNIX-LISTEN:$HOME/.gnupg/S.gpg-agent,unlink-close,unlink-early TCP4:localhost:12345;
done) &

Testez si cela fonctionne avec gpg-connect-agent. Assurez-vous que GPG_AGENT_INFO n'est pas défini sur l'hôte distant, afin qu'il retombe dans le $HOME/.gnupg/S.gpg-agentsocket.

Avec un peu de chance, tout ce dont vous avez besoin est un moyen d'exécuter tout cela automatiquement!

b0fh
la source
Eh bien, les clés d'agent ssh sont transmises automatiquement lorsque la redirection est définie dans le fichier de configuration. Je vais essayer ça.
txwikinger
Vous avez raison, ssh-agent utilise également un socket Unix, mais a un support spécial pour cela (un peu fatigué ici :) Néanmoins, la solution devrait toujours fonctionner.
b0fh
1
Pour cette solution, mon agent gpg serait accessible au public via le port 12345 si je n'étais pas derrière un pare-feu / NAT. Cela devrait être mentionné dans la réponse s'il vous plaît.
Jonas Schäfer
Je suppose que votre dernière modification a résolu ce problème, Jonas? c'est seulement obligatoire pour localhostmaintenant.
jmtd
Cela ne me l'argument suivant de l'hôte distant de gpg-connect-agent: can't connect to server: ec=31.16383 gpg-connect-agent: error sending RESET command: Invalid value passed to IPC. La télécommande socatmeurt alors. Le local socatmeurt et prononce socat[24692] E connect(3, AF=1 "", 2): Invalid argument. Cette page me fait croire que cela ne fonctionnera jamais, car l'agent ne stocke pas la clé (juste la phrase secrète). Est-ce que cela a été confirmé par quelqu'un?
jmtd
17

Le nouveau transfert de socket de domaine Unix d'OpenSSH peut le faire directement à partir de la version 6.7.

Vous devriez pouvoir faire quelque chose comme:

ssh -R /home/bminton/.gnupg/S.gpg-agent:/home/bminton/.gnupg/S-gpg-agent -o "StreamLocalBindUnlink=yes" -l bminton 192.168.1.9
Brian Minton
la source
@DrewR. Content de l'entendre.
Brian Minton
2
J'ai trouvé un détail critique requis: sur la machine distante (sans clé privée), la clé publique de l'identité de signature doit être présente. Version gpg locale 2.1.15 OS X, Linux 2.1.11 distant.
phs
4

Dans les nouvelles versions des distributions GnuPG ou Linux, les chemins des sockets peuvent changer. Ceux-ci peuvent être trouvés via

$ gpgconf --list-dirs agent-extra-socket

et

$ gpgconf --list-dirs agent-socket

Ajoutez ensuite ces chemins à votre configuration SSH:

Host remote
  RemoteForward <remote socket> <local socket>

Solution rapide pour copier les clés publiques:

scp .gnupg/pubring.kbx remote:~/.gnupg/

Sur la machine distante, activez l'agent GPG:

echo use-agent >> ~/.gnupg/gpg.conf

Sur la machine distante, modifiez également la configuration du serveur SSH et ajoutez ce paramètre (/ etc / ssh / sshd_config):

StreamLocalBindUnlink yes

Redémarrez le serveur SSH, reconnectez-vous à la machine distante - alors cela devrait fonctionner.

MaLo
la source
Un didacticiel plus détaillé, y compris un dépannage, peut être trouvé ici: mlohr.com/gpg-agent-forwarding
MaLo
1
Si l'hôte distant exécute une version actuelle de Debian, il semble que l'exécution systemctl --global mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socketsoit nécessaire pour empêcher systemd de lancer un socket volant l'agent gpg distant. Selon bugs.debian.org/850982, c'est le comportement prévu.
sampi
3

J'ai dû faire de même, et j'ai basé mon script sur la solution de b0fh, avec quelques petites modifications: il intercepte les sorties et tue les processus d'arrière-plan, et il utilise les options "fork" et "reuseaddr" pour socat, ce qui vous évite boucle (et rend le socat d'arrière-plan proprement tuable).

Le tout se configure en une seule fois, donc cela se rapproche probablement d'une configuration automatisée.

Notez que sur l'hôte distant, vous aurez besoin de:

  1. Les porte-clés que vous avez l'intention d'utiliser pour signer / fr / décrypter des éléments.
  2. Selon la version de gpg sur la télécommande, une fausse GPG_AGENT_INFOvariable. Je préremplit le mien avec ~/.gnupg/S.gpg-agent:1:1- le premier est un PID pour l'agent gpg (je le simule comme "init", qui est toujours en cours d'exécution), le second est le numéro de version du protocole de l'agent. Cela devrait correspondre à celui qui s'exécute sur votre ordinateur local.

#!/bin/bash -e

FORWARD_PORT=${1:-12345}

trap '[ -z "$LOCAL_SOCAT" ] || kill -TERM $LOCAL_SOCAT' EXIT

GPG_SOCK=$(echo "$GPG_AGENT_INFO" | cut -d: -f1)
if [ -z "$GPG_SOCK" ] ; then
    echo "No GPG agent configured - this won't work out." >&2
    exit 1
fi

socat TCP-LISTEN:$FORWARD_PORT,bind=127.0.0.1,reuseaddr,fork UNIX-CONNECT:$GPG_SOCK &
LOCAL_SOCAT=$!

ssh -R $FORWARD_PORT:127.0.0.1:$FORWARD_PORT socat 'UNIX-LISTEN:$HOME/.gnupg/S.gpg-agent,unlink-close,unlink-early,fork,reuseaddr TCP4:localhost:$FORWARD_PORT'

Je crois qu'il existe également une solution qui implique une seule invocation de commande SSH (se reconnecter de l'hôte distant à l'hôte local) -o LocalCommand, mais je n'arrivais pas à comprendre comment le supprimer facilement à la sortie.

antifuchs
la source
Ne manquez-vous pas un argument 'user @ host' avant socat, dans la dernière commande? Quoi qu'il en soit, même après avoir corrigé cela, cela échoue pour moi avec "socat [6788] E connect (3, AF = 2 127.0.0.1:0, 16): Connexion refusée" apparaissant localement, lors de l'essai à distance de gpg-connect-agent.
David Faure
1

Selon GnuPG Wiki , vous devez transmettre le socket distant au socket S.gpg-agent.extralocal S.gpg-agent. De plus, vous devez activer StreamLocalBindUnlinksur le serveur.
Gardez à l'esprit que vous avez également besoin de la partie publique de votre clé disponible sur GnuPG distant .

Utilisez gpgconf --list-dir agent-socketrespectivement gpgconf --list-dir agent-extra-socketsur la télécommande pour obtenir les chemins réels.


Sommaire

  1. Configuration ajoutée sur la télécommande /etc/sshd_config:

    StreamLocalBindUnlink yes
    
  2. Importez votre clé publique à distance:

    gpg --export <your-key> >/tmp/public
    scp /tmp/public <remote-host>:/tmp/public
    ssh <remote-host> gpg --import /tmp/public
    
  3. Commande pour se connecter via SSH avec le transfert d'agent gpg activé: (chemins pour mon Debian)

    ssh -R /run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent.extra <remote-host>
    
doak
la source
@brian minton: Cela ne fonctionne pas pour moi s'il n'est pas transféré vers la prise supplémentaire.
doak
0

Comme alternative à la modification /etc/ssh/sshd_configavec StreamLocalBindUnlink yes, vous pouvez empêcher la création des fichiers socket qui doivent être remplacés:

systemctl --global mask --now \
  gpg-agent.service \
  gpg-agent.socket \
  gpg-agent-ssh.socket \
  gpg-agent-extra.socket \
  gpg-agent-browser.socket

Notez que cela affecte tous les utilisateurs de l'hôte.

Bonus: Comment tester le transfert d'agent GPG fonctionne:

  • Local: ssh -v -o RemoteForward=${remote_sock}:${local_sock} ${REMOTE}
  • Vérifiez que cela ${remote_sock}est indiqué dans la sortie détaillée de ssh
  • Éloigné: ls -l ${remote_sock}
  • Éloigné: gpg --list-secret-keys
    • Vous devriez voir beaucoup de debug1messages de ssh montrant le trafic transféré

Si cela ne fonctionne pas (comme cela ne l'a pas été pour moi), vous pouvez tracer le socket auquel GPG accède:

strace -econnect gpg --list-secret-keys

Exemple de sortie:

connect(5, {sa_family=AF_UNIX, sun_path="/run/user/14781/gnupg/S.gpg-agent"}, 35) = 0

Dans mon cas, le chemin d'accès était parfaitement adapté ${remote_sock}, mais ce socket n'a pas été créé sshdlorsque je me suis connecté, malgré l'ajout StreamLocalBindUnlink yesà mon /etc/ssh/sshd_config. J'ai été créé par systemd lors de la connexion.

(Notez que j'étais trop lâche pour redémarrer sshd, car je n'ai pas d'accès physique à l'hôte pour le moment. service reload sshdN'était clairement pas suffisant ...)

Testé sur Ubuntu 16.04

RobM
la source