Jak mogę przekazać klucz gpg przez ssh-agent?

29

Mogę użyć pliku konfiguracyjnego ssh, aby umożliwić przekazywanie kluczy ssh dodanych do ssh-agent. Jak mogę zrobić to samo z kluczami gpg?

txwikinger
źródło
3
Obie odpowiedzi sugerują uruchomienie socat, aby odsłonić gniazdo unix agenta GPG na porcie TCP. Jednak w przeciwieństwie do gniazd unix, porty TCP nie mają tego samego poziomu kontroli dostępu. W szczególności każdy użytkownik na tym samym hoście może teraz połączyć się z agentem GPG. Jest to prawdopodobnie w porządku, jeśli masz laptopa dla jednego użytkownika, ale jeśli inni użytkownicy mogą również zalogować się do tego samego systemu (systemu, w którym działa agent GPG), mogą również uzyskać dostęp do Twojego agenta GPG, co stanowi poważny problem z bezpieczeństwem. Umożliwienie socat bezpośredniego uruchomienia SSH przy użyciu typu adresu EXEC jest prawdopodobnie najlepszym sposobem na rozwiązanie tego problemu.
Matthijs Kooijman
Na innej prezentacji roztworu OpenSSH 6.7+, zobacz 2015.rmll.info/IMG/pdf/an-advanced-introduction-to-gnupg.pdf
PHS
To mi się przydało.
phs

Odpowiedzi:

16

EDYCJA: Ta odpowiedź jest już nieaktualna, ponieważ odpowiednie wsparcie zostało zaimplementowane w OpenSSH, patrz odpowiedź Briana Mintona.

SSH jest w stanie przekazywać połączenia TCP w tunelu.

Możesz jednak użyć programu takiego jak socatprzekaźnik gniazda unixowego przez TCP, z czymś takim (będziesz potrzebował socat zarówno na kliencie, jak i na serwerach):

# 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) &

Sprawdź, czy to działa gpg-connect-agent. Upewnij się, że GPG_AGENT_INFO jest niezdefiniowany na zdalnym hoście, aby spadł z powrotem do $HOME/.gnupg/S.gpg-agentgniazda.

Teraz, mam nadzieję, wszystko czego potrzebujesz to sposób, aby uruchomić to wszystko automatycznie!

b0fh
źródło
Cóż, klucze agenta ssh są przekazywane automatycznie, gdy przekazywanie jest ustawione w pliku konfiguracyjnym. Spróbuję tego.
txwikinger
Masz rację, ssh-agent używa również gniazda unix, ale ma specjalne wsparcie dla niego (tutaj trochę zmęczone :) Niemniej jednak rozwiązanie powinno nadal działać.
b0fh
1
W przypadku tego rozwiązania mój gpg-agent byłby publicznie dostępny przez port 12345, gdybym nie był za firewallem / NAT. Należy o tym wspomnieć w odpowiedzi.
Jonas Schäfer
Chyba ostatnia edycja rozwiązała ten problem, Jonas? jest to wiążące tylko localhostteraz.
jmtd
To nie dla mnie z następującym argumentem ze zdalnego hosta gpg-connect-agent: can't connect to server: ec=31.16383 gpg-connect-agent: error sending RESET command: Invalid value passed to IPC. Pilot socatnastępnie umiera. Miejscowi socatginą i mówią socat[24692] E connect(3, AF=1 "", 2): Invalid argument. Ta strona prowadzi mnie do przekonania, że ​​to nigdy nie zadziała, ponieważ agent nie przechowuje klucza (tylko hasło). Czy ktoś potwierdził, że to działa?
jmtd
17

Nowe Unixowe przekazywanie gniazd domenowych OpenSSH może to zrobić bezpośrednio, począwszy od wersji 6.7.

Powinieneś być w stanie zrobić coś takiego:

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
źródło
@DrewR. Cieszę się, że to słyszę.
Brian Minton
2
Znalazłem wymagany krytyczny szczegół: na zdalnym komputerze (bez klucza prywatnego) klucz publiczny tożsamości podpisującej musi być obecny. Lokalna wersja gpg 2.1.15 OS X, zdalny linuks 2.1.11.
phs
4

W nowych wersjach dystrybucji GnuPG lub Linux ścieżki gniazd mogą się zmieniać. Można je znaleźć za pośrednictwem

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

i

$ gpgconf --list-dirs agent-socket

Następnie dodaj te ścieżki do konfiguracji SSH:

Host remote
  RemoteForward <remote socket> <local socket>

Szybkie rozwiązanie do kopiowania kluczy publicznych:

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

Na zdalnym komputerze aktywuj agenta GPG:

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

Na komputerze zdalnym zmodyfikuj również konfigurację serwera SSH i dodaj ten parametr (/ etc / ssh / sshd_config):

StreamLocalBindUnlink yes

Zrestartuj serwer SSH, połącz się ponownie ze zdalnym komputerem - to powinno działać.

MaLo
źródło
Bardziej szczegółowy samouczek, w tym niektóre rozwiązywanie problemów, można znaleźć tutaj: mlohr.com/gpg-agent-forwarding
MaLo
1
W przypadku, gdy zdalny host uruchamia bieżącą wersję Debiana, wydaje się, że systemctl --global mask --now gpg-agent.service gpg-agent.socket gpg-agent-ssh.socket gpg-agent-extra.socket gpg-agent-browser.socketjest on wymagany, aby systemd nie uruchomił zdalnego kradnącego gniazda agenta gpg. Według bugs.debian.org/850982 jest to zamierzone zachowanie.
sampi,
3

Musiałem zrobić to samo i oparłem swój skrypt na rozwiązaniu autorstwa b0fh, z kilkoma drobnymi modyfikacjami: przechwytuje wyjścia i zabija procesy w tle, i używa opcji „fork” i „reuseaddr” do socat, co oszczędza ci pętli (i sprawia, że ​​tło w tle może zostać zabite).

Całość ustawia wszystkie naprzód za jednym razem, więc prawdopodobnie zbliża się do automatycznej konfiguracji.

Pamiętaj, że na zdalnym hoście potrzebujesz:

  1. Breloki, których zamierzasz używać do podpisywania / en / deszyfrowania rzeczy.
  2. W zależności od wersji gpg na pilocie, fałszywa GPG_AGENT_INFOzmienna. Wypełniam moją kopią ~/.gnupg/S.gpg-agent:1:1- pierwsza 1 to PID dla agenta gpg (sfałszuję go jako „init”, który zawsze działa), druga to numer wersji protokołu agenta. To powinno pasować do tego uruchomionego na twoim komputerze lokalnym.

#!/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'

Uważam, że istnieje również rozwiązanie, które polega na użyciu tylko jednego wywołania komendy SSH (połączenie z hosta zdalnego do lokalnego) -o LocalCommand, ale nie mogłem do końca wymyślić, jak wygodnie zabić to po wyjściu.

środki przeciwporostowe
źródło
Czy w ostatnim poleceniu nie brakuje jakiegoś argumentu „użytkownik @ host” przed socat? W każdym razie nawet po naprawieniu tego, dla mnie to się nie powiodło z pojawieniem się „socat [6788] E connect (3, AF = 2 127.0.0.1:0, 16): Połączenie odrzucone” lokalnie, gdy próbuję zdalnie gpg-connect-agent.
David Faure,
1

Zgodnie z GnuPG Wiki , musisz przekazać zdalne gniazdo S.gpg-agent.extrado gniazda lokalnego S.gpg-agent. Ponadto musisz włączyć StreamLocalBindUnlinkna serwerze.
Pamiętaj, że potrzebujesz także publicznej części klucza dostępnej na zdalnym GnuPG .

Użyj gpgconf --list-dir agent-socketodpowiednio gpgconf --list-dir agent-extra-socketna pilocie, aby uzyskać rzeczywiste ścieżki.


Podsumowanie

  1. Dodano konfigurację na pilocie /etc/sshd_config:

    StreamLocalBindUnlink yes
    
  2. Zaimportuj swój klucz publiczny na pilocie:

    gpg --export <your-key> >/tmp/public
    scp /tmp/public <remote-host>:/tmp/public
    ssh <remote-host> gpg --import /tmp/public
    
  3. Polecenie połączenia przez SSH z włączonym przekazywaniem agenta gpg: (ścieżki dla mojego Debiana)

    ssh -R /run/user/1000/gnupg/S.gpg-agent:/run/user/1000/gnupg/S.gpg-agent.extra <remote-host>
    
doak
źródło
@brian minton: Nie działa dla mnie, jeśli nie przekierowuję do dodatkowego gniazda.
doak
0

Zamiast modyfikowania za /etc/ssh/sshd_configpomocą StreamLocalBindUnlink yesmożna zamiast tego zapobiec tworzeniu plików gniazd, które wymagają wymiany:

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

Pamiętaj, że wpływa to na wszystkich użytkowników na hoście.

Bonus: Jak przetestować przekazywanie agentów GPG:

  • Lokalny: ssh -v -o RemoteForward=${remote_sock}:${local_sock} ${REMOTE}
  • Sprawdź, czy ${remote_sock}jest to pokazane w pełnym danych wyjściowych z ssh
  • Zdalny: ls -l ${remote_sock}
  • Zdalny: gpg --list-secret-keys
    • Powinieneś zobaczyć wiele debug1wiadomości z ssh pokazujących przekierowany ruch

Jeśli to nie zadziała (tak jak dla mnie), możesz sprawdzić, do którego gniazda GPG ma dostęp:

strace -econnect gpg --list-secret-keys

Przykładowe dane wyjściowe:

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

W moim przypadku dostęp do ścieżki jest idealnie dopasowany ${remote_sock}, ale to gniazdo nie zostało utworzone, sshdkiedy się zalogowałem, pomimo dodania StreamLocalBindUnlink yesdo mojego /etc/ssh/sshd_config. Zostałem stworzony przez systemd po zalogowaniu.

(Uwaga: byłem zbyt tchórzliwy, aby zrestartować sshd, ponieważ nie mam teraz fizycznego dostępu do hosta. service reload sshdNajwyraźniej nie było wystarczające ...)

Testowane na Ubuntu 16.04

RobM
źródło