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?


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!


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

@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ć.


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.


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>
    

@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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.