¿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?

txwikinger
fuente
3
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.
Matthijs Kooijman
Para otra presentación de la solución openssh 6.7+, consulte 2015.rmll.info/IMG/pdf/an-advanced-introduction-to-gnupg.pdf
phs
Esto me fue útil.
phs

Respuestas:

16

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!

b0fh
fuente
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.

Deberías poder hacer algo como:

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
fuente
@DrewR. Me alegra escuchar eso.
Brian Minton
2
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

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

y

$ gpgconf --list-dirs agent-socket

Luego agregue estas rutas a su configuración SSH:

Host remote
  RemoteForward <remote socket> <local socket>

Solución rápida para copiar las claves públicas:

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

En la máquina remota, active el agente GPG:

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

En la máquina remota, también modifique la configuración del servidor SSH y agregue este parámetro (/ etc / ssh / sshd_config):

StreamLocalBindUnlink yes

Reinicie el servidor SSH, vuelva a conectarse a la máquina remota, entonces debería funcionar.

MaLo
fuente
Aquí puede encontrar un tutorial más detallado que incluye algunos problemas: mlohr.com/gpg-agent-forwarding
MaLo
1
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á:

  1. Los llaveros que piensa usar para firmar / es / descifrar cosas.
  2. 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.

antifuchs
fuente
¿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

  1. Configuración agregada en remoto /etc/sshd_config:

    StreamLocalBindUnlink yes
    
  2. Importe su clave pública en el control remoto:

    gpg --export <your-key> >/tmp/public
    scp /tmp/public <remote-host>:/tmp/public
    ssh <remote-host> gpg --import /tmp/public
    
  3. Comando para conectarse a través de SSH con reenvío de agente gpg habilitado: (rutas para mi Debian)

    ssh -R /run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent.extra <remote-host>
    
doak
fuente
@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:

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

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:

  • Local: ssh -v -o RemoteForward=${remote_sock}:${local_sock} ${REMOTE}
  • Compruebe que ${remote_sock}se muestra en la salida detallada de ssh
  • Remoto: ls -l ${remote_sock}
  • Remoto: gpg --list-secret-keys
    • Debería ver muchos debug1mensajes de ssh que muestran el tráfico reenviado

Si eso no funciona (como no lo hizo para mí), puede rastrear a qué socket GPG está accediendo:

strace -econnect gpg --list-secret-keys

Salida de muestra:

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

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 ...)

Probado en Ubuntu 16.04

RobM
fuente