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?
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.
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!
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.
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:
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:
Les porte-clés que vous avez l'intention d'utiliser pour signer / fr / décrypter des éléments.
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.
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
Configuration ajoutée sur la télécommande /etc/sshd_config:
@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:
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 ...)
Réponses:
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
socat
pour 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):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-agent
socket.Avec un peu de chance, tout ce dont vous avez besoin est un moyen d'exécuter tout cela automatiquement!
la source
localhost
maintenant.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écommandesocat
meurt alors. Le localsocat
meurt et prononcesocat[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?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:
la source
Dans les nouvelles versions des distributions GnuPG ou Linux, les chemins des sockets peuvent changer. Ceux-ci peuvent être trouvés via
et
Ajoutez ensuite ces chemins à votre configuration SSH:
Solution rapide pour copier les clés publiques:
Sur la machine distante, activez l'agent GPG:
Sur la machine distante, modifiez également la configuration du serveur SSH et ajoutez ce paramètre (/ etc / ssh / sshd_config):
Redémarrez le serveur SSH, reconnectez-vous à la machine distante - alors cela devrait fonctionner.
la source
systemctl --global mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socket
soit 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.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:
GPG_AGENT_INFO
variable. 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.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.la source
Selon GnuPG Wiki , vous devez transmettre le socket distant au socket
S.gpg-agent.extra
localS.gpg-agent
. De plus, vous devez activerStreamLocalBindUnlink
sur 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-socket
respectivementgpgconf --list-dir agent-extra-socket
sur la télécommande pour obtenir les chemins réels.Sommaire
Configuration ajoutée sur la télécommande
/etc/sshd_config
:Importez votre clé publique à distance:
Commande pour se connecter via SSH avec le transfert d'agent gpg activé: (chemins pour mon Debian)
la source
Comme alternative à la modification
/etc/ssh/sshd_config
avecStreamLocalBindUnlink yes
, vous pouvez empêcher la création des fichiers socket qui doivent être remplacés:Notez que cela affecte tous les utilisateurs de l'hôte.
Bonus: Comment tester le transfert d'agent GPG fonctionne:
ssh -v -o RemoteForward=${remote_sock}:${local_sock} ${REMOTE}
${remote_sock}
est indiqué dans la sortie détaillée de sshls -l ${remote_sock}
gpg --list-secret-keys
debug1
messages 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:
Exemple de sortie:
Dans mon cas, le chemin d'accès était parfaitement adapté
${remote_sock}
, mais ce socket n'a pas été créésshd
lorsque je me suis connecté, malgré l'ajoutStreamLocalBindUnlink 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 sshd
N'était clairement pas suffisant ...)Testé sur Ubuntu 16.04
la source