Wie kann der Bildschirm automatisch mit dem aktuellen SSH-Agenten verbunden werden, wenn er erneut an einen vorhandenen Bildschirm angehängt wird?


47

Wenn Sie eine Bildschirmsitzung starten, während ssh-agent ausgeführt wird (über die Weiterleitung von ssh-A-agent), funktioniert der Zugriff auf ssh-agent einwandfrei. Wenn Sie sich jedoch von dieser Sitzung trennen, sich abmelden, erneut anmelden (mit der Weiterleitung von ssh-agent) und eine neue Verbindung zu Ihrer Bildschirmsitzung herstellen, funktioniert der Zugriff auf ssh-agent nicht.

Wie kann das behoben werden?

Antworten:


41

1) In Ihrem SSH rc-Skript (~ / .ssh / rc) richten Sie eine symbolische Verbindung von einem kanonischen Speicherort zum "aktuellen" SSH_AUTH_SOCK ein. So mache ich es in Bash (Inhalt von ~ / .ssh / rc):

#!/bin/bash
if test "$SSH_AUTH_SOCK" ; then
    ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
fi

(und stellen Sie sicher, 755 ~ / .ssh / rc zu chmod). Der "Test" soll nur verhindern, dass ein Fehler angezeigt wird, wenn Sie nicht ssh-agent ausführen (dh Sie ssh ohne -A). Die zweite Hälfte dieses Befehls richtet einen Symlink an einem kanonischen Speicherort ein, der sich beim Anmelden auf den "echten" SSH_AUTH_SOCK aktualisiert. Dies ist unabhängig von der Verwendung einer Shell in ssh oder dem direkten Aufruf eines Befehls und funktioniert auch mit "ssh -t screen -RRD".

Hinweis: Die Existenz von ~ / .ssh / rc ändert das Verhalten von sshd. Insbesondere wird xauth nicht aufgerufen. Weitere Informationen finden Sie unter man sshd.

Außerdem sollten Sie "-v" nicht mit ln verwenden, sobald es rsync-over-ssh mit folgender Diagnose unterbricht:

$ rsync -n addr.maps.dev.yandex.net: .
protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(173) [Receiver=3.0.7]

2) In Ihrem .screenrc müssen Sie nur SSH_AUTH_SOCK an der kanonischen Position überschreiben:

setenv SSH_AUTH_SOCK $HOME/.ssh/ssh_auth_sock

Beachten Sie, dass Sie setenv unabhängig von der verwendeten Shell verwenden. Ich denke, dass setenv Bildschirmsyntax ist, nicht die Shell.

Lösung ursprünglich aus diesem Beitrag angepasst , die nicht funktioniert, aber die richtige Idee hat.


Dies setzt voraus, dass Sie sich zuerst anmelden und dann den Bildschirm starten. Richtig?
24.

1
Wie kann es anders sein? Wie würden Sie den Bildschirm starten, ohne angemeldet zu sein?

1
Du hast recht. Die Frage wurde dumm formuliert. Aber müssen Sie sich einloggen, eine Shell starten und von dort aus den Startbildschirm öffnen? Ich mache oft etwas wie "ssh -t some.machine screen -R".
24.

1
Ach ok Nun, ich habe es gerade versucht und es funktioniert nicht (dh ssh-agent ist nicht verbunden). Ich vermute, dass ssh bei dieser Verwendung nicht die richtigen Sockets einrichtet. Vielleicht könnte mehr argument-foo das aufräumen?

SSH richtet die Sockets ein, es startet einfach nie die Shell. Aber dieser Tipp ist so nützlich, dass ich denke, ich könnte nur meine Gewohnheiten ändern.
26.

23

Ich denke, dass dies eine Vereinfachung der Antwort von @ sandip-bhattacharya ist. Fügen Sie dies in Ihre ~/.bashrcDatei ein und führen Sie den Exportbefehl in allen derzeit ausgeführten Bildschirmsitzungen aus.

if [ -S "$SSH_AUTH_SOCK" ] && [ ! -h "$SSH_AUTH_SOCK" ]; then
    ln -sf "$SSH_AUTH_SOCK" ~/.ssh/ssh_auth_sock
fi
export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock

Dies lautet "Wenn $SSH_AUTH_SOCKes sich um einen Socket ( -S) und nicht um eine symbolische Verknüpfung ( ! -h) handelt, erstellen Sie eine neue symbolische Verknüpfung auf dem bekannten Pfad. Definieren Sie in allen Fällen neu SSH_AUTH_SOCK, um auf den bekannten Pfad zu verweisen.

Das ! -hvermeidet das Erstellen eines Zirkelverweises, wenn Sie diesen mehrmals ausführen.

Wenn Sie dies verwenden byobu, wird dies auch automatisch durchgeführt, ohne dass Konfigurationsdateien bearbeitet werden müssen.

Der einzige Fehler, den ich darin gefunden habe ( byobuhat es auch), ist, wenn Sie eine Sekunde öffnen ssh -Aoder eine ForwardAgentVerbindung herstellen, die den ersten Socket überschreibt, und wenn Sie die zweite Verbindung vor der ersten schließen, verlieren Sie Ihren einzigen guten Socket.


1
Das funktioniert tmuxauch.
Dag Høidahl

Funktioniert hervorragend, funktioniert aber nicht, wenn remote gemountete Basisordner verwendet werden. In diesem Fall verwenden Sie ~/.ssh/ssh_auth_sock_"$(hostname)"für Ihren Symlink. Es werden separate Authentifizierungssockets für jeden Host eingerichtet.
Kibber

4

"ssh -t some.machine screen -R" führt bash nicht aus und führt daher nicht das Skript .bash_profile aus, in dem der Symlink erstellt wird.

Sie könnten versuchen: ssh -t some.machine bash -c "screen -R"

(vorausgesetzt, Sie verwenden bash als Shell)

Edit: Diese "Antwort" ist eigentlich ein Kommentar zu der ersten oben gegebenen Antwort :)


"Erste Antwort oben" hat keine Bedeutung, da sich die Reihenfolge der Antworten ändert, wenn über sie abgestimmt wird. Bitte geben Sie den Link zum Teilen der Antwort an, auf die Sie sich beziehen, da sich dies nicht ändert.
rjmunro

3

Ich denke du brauchst Autossh. Ich benutze es seit Jahren und in Kombination mit dem Bildschirm werden alle meine Terminalsitzungen vollständig portabel und transparent. Ich schließe lappy einfach, gehe an einen neuen Ort, öffne lappy und alle meine Bildschirme und verschachtelten Bildschirme verbinden sich automatisch. Ich denke nicht einmal mehr darüber nach.

http://www.linux.com/archive/feature/134133

ist die Grundlagen ... Ich habe ein kleines Skript erstellt, um den Prozess in meinem .screenrc für einen bestimmten Host zu automatisieren. (Tut auch meine SSH-Weiterleitung, so dass ich an all diesen verschiedenen Orten meine Verbindung über meine Server tunneln kann.)

in der autossh Distribution sollte es ein Programm namens rscreen geben (und .. da ist es!)

#!/bin/sh                                                                       
#
# sample script to use autossh to open up a remote screen
# session, or reconnect to an existing one. 
#
# $Id: rscreen,v 1.4 2002/05/07 17:54:13 harding Exp $
#
if [ "X$1" = "X" ]; then
    echo "usage: `basename $0` <host>"
    exit 1
fi

if [ "X$SSH_AUTH_SOCK" = "X" ]; then
    eval `ssh-agent -s`
    ssh-add $HOME/.ssh/id_rsa
fi

#AUTOSSH_POLL=600
#AUTOSSH_PORT=20000
#AUTOSSH_GATETIME=30
#AUTOSSH_LOGFILE=$HOST.log
#AUTOSSH_DEBUG=yes 
#AUTOSSH_PATH=/usr/local/bin/ssh
export AUTOSSH_POLL AUTOSSH_LOGFILE AUTOSSH_DEBUG AUTOSSH_PATH AUTOSSH_GATETIME 

autossh -M 20004 -t $1 "screen -e^Zz -D -R"

Dies sollte bei Problemen mit ssh / screen helfen

Um meinen ssh-Agenten am Laufen zu halten, verwende ich schließlich den Schlüsselbund, da ich eine Art Shell-Kopf bin ... Ich denke, OSX hat etwas, das Ihren Agenten am Laufen hält ...


2

Hier ist die Methode, die ich benutze:

SOCK=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep SSH_AUTH_SOCK) ; eval $SOCK ; export SSH_AUTH_SOCK
DISP=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep DISPLAY) ; eval $DISP ; export DISP

Normalerweise richte ich mit diesen Befehlen einen Alias ​​oder eine Shell-Funktion ein:

function ssh-screen-auth() {
  SOCK=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep SSH_AUTH_SOCK)
  eval $SOCK
  export SSH_AUTH_SOCK
  DISP=$(sudo cat /proc/$(pgrep -f "screen -(r|DR)")/environ | tr "\0" "\n" | grep DISPLAY)
  eval $DISP
  export DISPLAY
}

Möglicherweise müssen Sie den regulären Ausdruck ' screen - (r | DR) ' an die genauen Befehle anpassen, die Sie zum erneuten Anschließen Ihres Bildschirms verwenden.

  • In der ersten Zeile wird die Umgebungsvariable SSH_AUTH_SOCK im Prozessbereich des soeben eingegebenen Befehls " screen -r " gelesen und der Wert in Ihrer aktuellen Shell aktualisiert.
  • Die zweite Zeile ist erforderlich, wenn Sie X11-Verbindungen mit " ssh -X " weiterleiten: Die Variable DISPLAY wird auf die gleiche Weise aktualisiert .

Eine Einschränkung bei meiner Methode: Wenn auf dem Computer ein anderer " Bildschirm " -Befehl ausgeführt wird, können Probleme auftreten.


-1 für die unnötige Verwendung von sudo.
0xC0000022L

1

Ich halte normalerweise längerfristige (6+ Monate) Sitzungen an meinem Arbeitsplatz auf verschiedenen Servern ab. Daher war es problematisch, immer wieder einen SSH-Spediteur anzuschließen und zu haben. Das habe ich auf meinen Systemen eingerichtet:

if [ -z "${STY}" -a -t 0 -a X${USER} = Xmyusername ]; then
    reattach () {
        if [ -n "${SSH_AUTH_SOCK}" ]; then
            ln -snf "${SSH_AUTH_SOCK}" "${HOME}/.ssh/agent-screen"
            SSH_AUTH_SOCK="${HOME}/.ssh/agent-screen" export SSH_AUTH_SOCK
        fi
        exec screen -A -D -RR ${1:+"$@"} ;
    }

    screen -wipe
    echo 'starting screen... (type Cntl-C to abort)'
    sleep 5 && reattach
fi

Wenn ich mich nur beim Remote-Server anmelde, ohne den Bildschirm zu starten / neu zu verbinden, werden zwei "Sockets" angezeigt, screeneiner von der neuen Shell und einer von der neuen Shell. Es sollten keine zwei "Start" -Sitzungen stattfinden, aber eine zweite Sitzung kann noch gestartet werden reattach -S new. In diesem Fall wird der Agent mit dem ~/.ssh/agent-screenWert geteilt. Um einen funktionierenden Weiterleitungsagenten wieder herzustellen, würde ich mich abmelden und wieder anmelden. Dadurch wird X${USER} = Xmyusernamesichergestellt, dass der Code nicht sudoauf demselben Server aufgerufen wird .


1

Ich verwende eine Variante dessen, was @apinstein für meinen .bashrc verwendet .

case "$TERM" in
    screen)
           export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sock
        ;;
         *)
           if [[ -n "$SSH_AUTH_SOCK" ]]; then
               ln -sf $SSH_AUTH_SOCK ~/.ssh/ssh_auth_sock
           fi
        ;;
esac

Dies funktioniert für alle Apps, die in meiner Bildschirmsitzung ausgeführt werden. Dies würde für alle neuen Shells in Ihrer Bildschirmsitzung funktionieren. Für vorhandene Shells müssen Sie export SSH_AUTH_SOCK=~/.ssh/ssh_auth_sockdie Host-Shell ausführen , damit sie funktioniert.

PS Es tut mir leid, dass Sie dies als unabhängige Antwort hinzugefügt haben, obwohl es nur auf der Antwort von @apinstein aufbaut. Musste dies tun, da Kommentare im Stackoverflow keine Codeblöcke unterstützen.


Warum nicht immer symlinken und immer exportieren?
Collin Anderson

@CollinAnderson Zwei verschiedene Verhaltensweisen. eine innerhalb einer Screen-Shell und eine innerhalb der regulären Login-Shell. Die Umgebungsvariable in einer Login-Shell wird von ssh und damit der dortige Symlink gesetzt. Wenn wir dies innerhalb einer Bildschirmsitzung tun, verursachen wir eine Symlink-Schleife.
Sandip Bhattacharya

Ahh, richtig. Sie müssten nur verlinken, wenn $ SSH_AUTH_SOCK noch kein Link ist. Siehe meinen Beitrag superuser.com/a/424588/134212
Collin Anderson

0

Ich habe diesen einfachen Einzeiler ausprobiert, wie auf " Lass uns Freunde für Bildschirm und SSH-Agent werden" vorgeschlagen. Er funktioniert für mich.

Erstmalige Anmeldung bei Target. Muss nur einmal durchgeführt werden.

ssh -o StrictHostKeyChecking=no -C <userid>@<server>

Bildschirm zum ersten Mal starten. Muss nur einmal ausgeführt werden.

eval `ssh-agent`; /usr/bin/screen -D -R -h 10000
ssh-add

Wenn die Verbindung getrennt oder getrennt wurde, melden Sie sich mit diesem Befehl an, um eine Verbindung zum Ausgangsbildschirm herzustellen.

ssh -o StrictHostKeyChecking=no -C -t <userid>@<server> ssh-agent /usr/bin/screen -D -R -h 10000

0

Das sind alles wirklich gute Antworten, ich mache es etwas anders. Nachdem ich eine neue SSH-Sitzung gestartet und den Bildschirm erneut angefügt habe, setze ich die SSH_AUTH_SOCKUmgebungsvariable basierend auf dem Inhalt der Root-Bash-Umgebung zurück. Ich benötige nur gelegentlich ssh-agent-Zugriff, wenn ich svn verwende. Deshalb setze ich das SSH_AUTH_SOCKin diesen Shells erforderliche zurück.

Dies verwendet das Proc-Dateisystem, ist also Linux-spezifisch. Ich habe dies nur auf einer kopflosen Linux-Box getestet, auf die nur ich zugreifen kann. Möglicherweise müssen einige Anpassungen vorgenommen werden, damit es in anderen Umgebungen funktioniert.

Zum Zurücksetzen von SSH_AUTH_SOCK (dies könnte zu einem Alias ​​gemacht werden).

$ . ~/bin/screen_auth.sh

screen_auth.sh sieht so aus

# Find the pid of putty's bash shell
tty=`who | awk '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ { print substr($2, 5) }'`
pid=`ps -t $tty | grep bash | awk '{print $1}'`
# Find the SSH_AUTH_SOCK variable in its enviornment
auth_sock=`xargs --null --max-args=1 echo < /proc/$pid/environ | grep SSH_AUTH_SOCK`
eval "export $auth_sock"

0

Alle oben genannten Lösungen leiden unter Rennbedingungen (entweder in mehreren SCREEN-Sitzungen oder in mehreren SSH-Verbindungen). Die einzige universelle Lösung, die ich mir vorstellen kann, ist, zuerst SSH_AUTH_SOCK an den SCREEN-Serverprozess zu senden screen -rund ihn dann vor jedem interaktiven, nicht eingebauten Befehl in die BASH-Sitzung zu ziehen. Leider wurden SCREEN und BASH ohne Kenntnis derartiger Probleme entwickelt, so dass eine ordnungsgemäße Implementierung ziemlich schwierig ist (obwohl es nie zu spät ist, Feature-Anfragen an beide Projekte zu senden). Ich habe versucht, dieses Problem für BASH-Sitzungen zu lösen, die hier zu finden sind:

Installieren:

  1. Fügen Sie beide Skripte hinzu $HOME/binund fügen Sie ein ausführbares Bit hinzu.
  2. stellen Sie sicher , dass $HOME/binvor geht /usr/binin PFAD:

    PATH = $ HOME / bin: $ PATH

  3. füge dies zu deinem hinzu .bashrc:

    source $ HOME / bin / screen-helper setup

Jetzt können Sie versuchen, eine SCREEN-Sitzung in einer SSH-Sitzung zu erstellen, die Verbindung zu trennen, die Verbindung herzustellen und erneut herzustellen, und hoffentlich ssh-add -lsollten Ihre Schlüssel korrekt angezeigt werden.


Beachten Sie, dass der permanente ssh-agentDaemon (wie hier vorgeschlagen superuser.com/a/412052/376867 ) nicht unter Rennbedingungen leidet, sondern unter einem veralteten Schlüsselring. Und was noch wichtiger ist, es ist nicht sehr sicher, alle Ihre Schlüssel zusammen mit der Bildschirmsitzung auf dem Remote-Host zu belassen (oder sogar länger, bis sie bei dem genannten Beitrag neu gestartet werden).
Midenok

0

Ich überflog andere Antworten und konnte meine nicht finden. Hier ist was ich benutze. Erstellen Sie eine Datei ~/.screenrc-wrappermit folgendem Inhalt:

escape ^xx
bindkey ^Ad detach

Und füge dies zu deinem hinzu ~/.bashrc(oder ~/.zshrcwenn du das verwendest):

  if echo $TERM | grep -v 'screen' && ! screen -x -SU wrapper; then
      if echo $TERM | grep -v 'screen' && ! screen -x -SU main; then
      screen -c ~/.screenrc-wrapper -SU wrapper ssh-agent screen -SU main
      fi
  fi

Auf diese Weise würden Sie zwei Bildschirmsitzungen verwenden - eine ist "Wrapper" und eine ist die innere. Dadurch bleibt Letzteres auch dann am Leben, wenn Sie sich abmelden, und ssh-agent wird weiterhin aktiviert. Ein weiteres nettes Feature ist, dass es sich an Ihre Fensterkonfiguration erinnert - wenn Sie geteilte Fenster verwenden, kann es sehr praktisch sein.

Sie finden diese Funktion im Kontext in meinen Punktedateien .

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.