¿Cómo puedo reenviar una clave gpg a través de ssh-agent?
29
Puedo usar el archivo de configuración ssh para habilitar el reenvío de claves ssh agregadas a ssh-agent. ¿Cómo puedo hacer lo mismo con las claves gpg?
Ambas respuestas sugieren ejecutar socat para exponer el socket GPX del agente GPG en un puerto tcp. Sin embargo, a diferencia de los sockets Unix, los puertos TCP no tienen el mismo nivel en el control de acceso. En particular, cada usuario en el mismo host ahora puede conectarse a su agente GPG. Esto probablemente esté bien si tiene una computadora portátil de un solo usuario, pero si otros usuarios también pueden iniciar sesión en el mismo sistema (el sistema donde se ejecuta el agente GPG), también pueden acceder a su agente GPG, lo que representa un problema de seguridad significativo. Permitir que socat inicie directamente SSH usando el tipo de dirección EXEC es probablemente la mejor manera de solucionar esto.
EDITAR: Esta respuesta es obsoleta ahora que se ha implementado el soporte adecuado en OpenSSH, vea la respuesta de Brian Minton.
SSH solo es capaz de reenviar conexiones TCP dentro del túnel.
Sin embargo, puede usar un programa como socatretransmitir el socket de Unix a través de TCP, con algo así (necesitará socat tanto en el cliente como en los hosts del servidor):
# 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) &
Prueba si funciona gpg-connect-agent. Asegúrese de que GPG_AGENT_INFO no esté definido en el host remoto, de modo que vuelva al $HOME/.gnupg/S.gpg-agentsocket.
¡Ahora con suerte todo lo que necesita es una forma de ejecutar todo esto automáticamente!
Bueno, las claves del agente ssh se reenvían automáticamente cuando el reenvío se establece en el archivo de configuración. Probaré esto.
txwikinger
Tienes razón, ssh-agent también usa un socket Unix, pero tiene un soporte especial para él (un poco cansado aquí :) Sin embargo, la solución aún debería funcionar.
b0fh
1
Para esta solución, mi gpg-agent sería de acceso público a través del puerto 12345 si no estuviera detrás de un firewall / NAT. Esto debería mencionarse en la respuesta, por favor.
Jonas Schäfer
¿Supongo que tu última edición solucionó ese problema, Jonas? solo es vinculante hasta localhostahora.
jmtd
Esta falla para mí con el siguiente argumento desde el host remoto de gpg-connect-agent: can't connect to server: ec=31.16383 gpg-connect-agent: error sending RESET command: Invalid value passed to IPC. El control remoto socatluego muere. El local socatmuere y pronuncia socat[24692] E connect(3, AF=1 "", 2): Invalid argument. Esta página me lleva a creer que esto nunca funcionará, porque el agente no almacena la clave (solo la frase de contraseña). ¿Alguien ha confirmado que esto funciona?
jmtd
17
El nuevo reenvío de socket de dominio Unix de OpenSSH puede hacer esto directamente a partir de la versión 6.7.
Encontré un detalle crítico requerido: en la máquina remota (sin clave privada), la clave pública de la identidad de firma debe estar presente. Local gpg versión 2.1.15 OS X, remoto 2.1.11 linux.
phs
4
En las nuevas versiones de distribuciones GnuPG o Linux, las rutas de los sockets pueden cambiar. Estos se pueden encontrar a través de
En caso de que el host remoto ejecute una versión actual de Debian, parece que systemctl --global mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socketes necesario para evitar que systemd lance un socket que robe el agente gpg remoto. Según bugs.debian.org/850982, este es el comportamiento previsto.
sampi
3
Tuve que hacer lo mismo, y basé mi script en la solución de b0fh, con algunas pequeñas modificaciones: atrapa las salidas y elimina los procesos en segundo plano, y utiliza las opciones "fork" y "reuseaddr" para socat, lo que le ahorra loop (y hace que el fondo socat sea fácilmente eliminable).
Todo esto configura todos los reenvíos de una sola vez, por lo que probablemente se acerque a una configuración automatizada.
Tenga en cuenta que en el host remoto, necesitará:
Los llaveros que piensa usar para firmar / es / descifrar cosas.
Dependiendo de la versión de gpg en el control remoto, una GPG_AGENT_INFOvariable falsa . Prefiero el mío con ~/.gnupg/S.gpg-agent:1:1: el primer 1 es un PID para el agente gpg (lo simulo como "init", que siempre se está ejecutando), el segundo es el número de versión del protocolo del agente. Esto debería coincidir con el que se ejecuta en su máquina 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'
Creo que también hay una solución que involucra solo una invocación de comando SSH (conexión desde el host remoto al local) usando -o LocalCommand, pero no pude averiguar cómo matar eso convenientemente al salir.
¿No te falta algún argumento 'user @ host' antes de socat, en el último comando? De todos modos, incluso después de arreglar eso, esto falla para mí con "socat [6788] E connect (3, AF = 2 127.0.0.1:0, 16): la conexión rechazada" aparece localmente, al intentar gpg-connect-agent de forma remota.
David Faure el
1
De acuerdo con GnuPG Wiki , debe reenviar el socket remoto al socket S.gpg-agent.extralocal S.gpg-agent. Además, debe habilitar StreamLocalBindUnlinken el servidor.
Tenga en cuenta que también necesita la parte pública de su clave disponible en GnuPG remoto .
Use gpgconf --list-dir agent-socketrespectivamente gpgconf --list-dir agent-extra-socketen el control remoto para obtener las rutas reales.
Resumen
Configuración agregada en remoto /etc/sshd_config:
@brian minton: no funciona para mí si no se reenvía al socket adicional.
doak
0
Como alternativa a la modificación /etc/ssh/sshd_configcon StreamLocalBindUnlink yes, en su lugar puede impedir la creación de los archivos de socket que necesitan ser reemplazados:
En mi caso, la ruta a la que se accedía coincidía perfectamente ${remote_sock}, pero ese socket no fue creado sshdcuando inicié sesión, a pesar de agregar StreamLocalBindUnlink yesa mi /etc/ssh/sshd_config. Fui creado por systemd al iniciar sesión.
(Tenga en cuenta que era demasiado cobarde para reiniciar sshd, ya que no tengo acceso físico al host en este momento. service reload sshdClaramente no era suficiente ...)
Respuestas:
EDITAR: Esta respuesta es obsoleta ahora que se ha implementado el soporte adecuado en OpenSSH, vea la respuesta de Brian Minton.
SSH solo es capaz de reenviar conexiones TCP dentro del túnel.
Sin embargo, puede usar un programa como
socat
retransmitir el socket de Unix a través de TCP, con algo así (necesitará socat tanto en el cliente como en los hosts del servidor):Prueba si funciona
gpg-connect-agent
. Asegúrese de que GPG_AGENT_INFO no esté definido en el host remoto, de modo que vuelva al$HOME/.gnupg/S.gpg-agent
socket.¡Ahora con suerte todo lo que necesita es una forma de ejecutar todo esto automáticamente!
fuente
localhost
ahora.gpg-connect-agent
:can't connect to server: ec=31.16383 gpg-connect-agent: error sending RESET command: Invalid value passed to IPC
. El control remotosocat
luego muere. El localsocat
muere y pronunciasocat[24692] E connect(3, AF=1 "", 2): Invalid argument
. Esta página me lleva a creer que esto nunca funcionará, porque el agente no almacena la clave (solo la frase de contraseña). ¿Alguien ha confirmado que esto funciona?El nuevo reenvío de socket de dominio Unix de OpenSSH puede hacer esto directamente a partir de la versión 6.7.
Deberías poder hacer algo como:
fuente
En las nuevas versiones de distribuciones GnuPG o Linux, las rutas de los sockets pueden cambiar. Estos se pueden encontrar a través de
y
Luego agregue estas rutas a su configuración SSH:
Solución rápida para copiar las claves públicas:
En la máquina remota, active el agente GPG:
En la máquina remota, también modifique la configuración del servidor SSH y agregue este parámetro (/ etc / ssh / sshd_config):
Reinicie el servidor SSH, vuelva a conectarse a la máquina remota, entonces debería funcionar.
fuente
systemctl --global mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socket
es necesario para evitar que systemd lance un socket que robe el agente gpg remoto. Según bugs.debian.org/850982, este es el comportamiento previsto.Tuve que hacer lo mismo, y basé mi script en la solución de b0fh, con algunas pequeñas modificaciones: atrapa las salidas y elimina los procesos en segundo plano, y utiliza las opciones "fork" y "reuseaddr" para socat, lo que le ahorra loop (y hace que el fondo socat sea fácilmente eliminable).
Todo esto configura todos los reenvíos de una sola vez, por lo que probablemente se acerque a una configuración automatizada.
Tenga en cuenta que en el host remoto, necesitará:
GPG_AGENT_INFO
variable falsa . Prefiero el mío con~/.gnupg/S.gpg-agent:1:1
: el primer 1 es un PID para el agente gpg (lo simulo como "init", que siempre se está ejecutando), el segundo es el número de versión del protocolo del agente. Esto debería coincidir con el que se ejecuta en su máquina local.Creo que también hay una solución que involucra solo una invocación de comando SSH (conexión desde el host remoto al local) usando
-o LocalCommand
, pero no pude averiguar cómo matar eso convenientemente al salir.fuente
De acuerdo con GnuPG Wiki , debe reenviar el socket remoto al socket
S.gpg-agent.extra
localS.gpg-agent
. Además, debe habilitarStreamLocalBindUnlink
en el servidor.Tenga en cuenta que también necesita la parte pública de su clave disponible en GnuPG remoto .
Use
gpgconf --list-dir agent-socket
respectivamentegpgconf --list-dir agent-extra-socket
en el control remoto para obtener las rutas reales.Resumen
Configuración agregada en remoto
/etc/sshd_config
:Importe su clave pública en el control remoto:
Comando para conectarse a través de SSH con reenvío de agente gpg habilitado: (rutas para mi Debian)
fuente
Como alternativa a la modificación
/etc/ssh/sshd_config
conStreamLocalBindUnlink yes
, en su lugar puede impedir la creación de los archivos de socket que necesitan ser reemplazados:Tenga en cuenta que esto afecta a todos los usuarios en el host.
Bonificación: cómo probar el reenvío de agentes GPG está funcionando:
ssh -v -o RemoteForward=${remote_sock}:${local_sock} ${REMOTE}
${remote_sock}
se muestra en la salida detallada de sshls -l ${remote_sock}
gpg --list-secret-keys
debug1
mensajes de ssh que muestran el tráfico reenviadoSi eso no funciona (como no lo hizo para mí), puede rastrear a qué socket GPG está accediendo:
Salida de muestra:
En mi caso, la ruta a la que se accedía coincidía perfectamente
${remote_sock}
, pero ese socket no fue creadosshd
cuando inicié sesión, a pesar de agregarStreamLocalBindUnlink yes
a mi/etc/ssh/sshd_config
. Fui creado por systemd al iniciar sesión.(Tenga en cuenta que era demasiado cobarde para reiniciar sshd, ya que no tengo acceso físico al host en este momento.
service reload sshd
Claramente no era suficiente ...)Probado en Ubuntu 16.04
fuente