ubuntuusers.de

ssh-agent über Script starten und mit bash nutzen

Status: Gelöst | Ubuntu-Version: Server 16.04 (Xenial Xerus)
Antworten |

hghtch

Anmeldungsdatum:
29. Juli 2019

Beiträge: Zähle...

Hallo ich bin noch sehr frisch in der Thematik und hoffe ich kann hier etwas Hilfe bekommen.

Ich möchte den ssh-agent per Script starten und mit ssh-add einen key hinzufügen, so dass spätere bash-sessions mit dem agent kommunizieren können.

Das war der erste Versuch:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11

if pgrep -x ssh-agent >/dev/null  
  then  
  echo "ssh-agent is running"  
else  
  echo "ssh-agent stopped"  
  echo "starting ssh-agent"  
  eval $(ssh-agent -s)  
  read -p "Which key do you want to add? " -i ~/.ssh/server_rsa -e rsakey  
  ssh-add $rsakey  
fi  

aber hier kann nur das Script auf den Agent zugreifen. Zwar kann ich nachdem das Script abgeschlossen wurde mit

pidof ssh-agent

sehen, dass der Agent läuft, aber wenn ich dann z.B. git clone 'GitHubSSHlink' ausführen will bekomme ich ein "permission denied (public key)".

Nun habe auch schon die technische Lösung (https://askubuntu.com/a/36302/658360)dafür gefunden, die direkt beim boot überprüft ob der Agent läuft, ihn falls nötig startet, überprüft ob ssh-keys hinterlegt sind und entsprechend ssh-add ausführt, und dabei durch die bash nutzbar ist, aber verstehen tue ich sie nicht:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# File: ~/.bash_profile

# source ~/.profile, if available
if [[ -r ~/.profile ]]; then
  . ~/.profile
fi

# start agent and set environment variables, if needed
agent_started=0
if ! env | grep -q SSH_AGENT_PID >/dev/null; then
  echo "Starting ssh agent"
  eval $(ssh-agent -s)
  agent_started=1
fi

# ssh become a function, adding identity to agent when needed
ssh() {
  if ! ssh-add -l >/dev/null 2>&-; then
    ssh-add ~/.ssh/id_dsa
  fi
  /usr/bin/ssh "$@"
}
export -f ssh

# another example: git
git() {
  if ! ssh-add -l >/dev/null 2>&-; then
    ssh-add ~/.ssh/id_dsa
  fi
  /usr/bin/git "$@"
}
export -f git

Ich habe mich etwas zu export -f erkundigt, aber ich verstehe noch nicht wieso das funktioniert. Immerhin ist die bash, die nachdem das Script ausgeführt wurde, gestartet wird doch kein Child von dem Script-Prozesses, und sollte deshalb doch genauso wenig Zugriff auf den ssh-agent wie vorher haben.

Edit:

Ich werde mich nochmal ausführlich mit child/parten foreground/background und sessions beschäftigen müssen.

Warum kann man nicht einfach eval $(ssh-add key) nutzen? Was unterscheidet ssh-agent und ssh-add? Warum muss ssh-agent nicht exportiert werden?

Immerhin macht es Sinn, dass wenn ein Script als Child einer Bash ausgeführt wird, und dann nachdem es abgeschlossen ist wieder zurück zur Bash wechselt, die Child-Prozesse des Scripts nicht von der Parent-Bash genutzt werden können.

Aber es wird ja mit -f exportiert, also werden die Variablennamen als Funktionen exportiert. Was das aber zu bedeuten hat verstehe ich nicht. Auch das "$@" ist mir ein Rätsel, und warum überhaupt eine ssh() oder git () definiert wird.

Und warum wird der ssh-agent nicht über einen systemd service gestartet und verwaltet?

Für eine Erklärung wäre ich sehr dankbar ☺

mfg hghtch

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11250

Wohnort: München

Hallo,

hghtch schrieb:

Ich habe mich etwas zu export -f erkundigt, aber ich verstehe noch nicht wieso das funktioniert. Immerhin ist die bash, die nachdem das Script ausgeführt wurde, gestartet wird doch kein Child von dem Script-Prozesses, und sollte deshalb doch genauso wenig Zugriff auf den ssh-agent wie vorher haben.

Die ~/.bash_profile wird von der Shell gesourced (also der darin enthaltene Code im Kontext der Shell ausgeführt), dafür wird keine extra Subshell gestartet.

Warum kann man nicht einfach eval $(ssh-add key) nutzen? Was unterscheidet ssh-agent und ssh-add?

ssh-agent startet den ssh-agent, ssh-add fügt Schlüssel zum Agent hinzu - vgl. https://manpages.ubuntu.com/manpages/bionic/en/man1/ssh-agent.1.html und https://manpages.ubuntu.com/manpages/bionic/en/man1/ssh-add.1.html

Warum muss ssh-agent nicht exportiert werden?

Schau dir mal an, was ssh-agent -s ausgibt, da sind Variablen-Exporte dabei und die werden durch das eval ausgeführt.

Aber es wird ja mit -f exportiert, also werden die Variablennamen als Funktionen exportiert. Was das aber zu bedeuten hat verstehe ich nicht.

Die Funktionen überlagern die gleichnamigen Programme im PATH. Aufrufe von git führen also dazu, dass die Funktion git() aufgerufen wird, nicht das Programm /usr/bin/git

Auch das "$@" ist mir ein Rätsel, und warum überhaupt eine ssh() oder git () definiert wird.

"$@" repräsentiert alle Argumente, die der Funktion übergeben wurden. Die Funktionen dienen als Wrapper, um sicherzustellen, dass der ssh-agent auf jeden Fall gestartet wurde, bevor der jeweilige Befehl aufgerufen wurde.

Und warum wird der ssh-agent nicht über einen systemd service gestartet und verwaltet?

Hast du mal auf das Datum des verlinkten Posts geschaut? 2013 war Ubuntu noch bei Upstart als Init-System...

Mit Systemd macht es am ehesten Sinn den ssh-agent über Systemd zu starten, wenn das im Rahmen einer Systemd User-Session im Kontext einer Desktop-Sitzung passiert, wie in SSH_keys beschrieben. Wenn du dich nur an einer Shell am Server anmeldest, hast du das Problem, die von der Systemd-Unit ggf. ausgelöste Passwortabfrage zum Entsperren des Keys zu Gesicht zu bekommen, daher sind das Skripte praktischer, die beim Start der Shell ausgeführt werden.

Wenn du dem Server vertraust, könntest du dir auch überlegen SSH-Agent Forwarding von deinem Desktop-Rechner aus einzuschalten, vgl. z.B. https://dev.to/levivm/how-to-use-ssh-and-ssh-agent-forwarding-more-secure-ssh-2c32 oder https://developer.github.com/v3/guides/using-ssh-agent-forwarding/, damit du die privaten Schlüssel nicht auf dem Server vorhalten musst.

hghtch

(Themenstarter)

Anmeldungsdatum:
29. Juli 2019

Beiträge: 2

Zum Thema eval und export:

Der ssh-agent nutzt export um seine Variablen an seine Child-Prozesse weiterzugeben.

Nun wird eval benutzt um SSH_AUTH_SOCK und SSH_AGENT_PID dem Parent Prozess der eval ausführt mitzuteilen.

Ohne eval würden nur Childs von ssh-agent auf die Variablen zugreifen können, nichtmal der Parent von ssh-agent (systemd).

Im Falle meines scripts:

eval $(ssh-agent -s) → startet den ssh-agent und gibt dem script die nötigen variablen um mit ihm zu kommunizieren ssh-add key → fügt den key für den prozess/script hinzu.

Nun kann aber nur das script, das ja eval ausgeführt hat, auf den Key zugreifen. Der parent, der Prozess der das Script aufgerufen hat (in meinem Beispiel erstmal Bash), dagegen hat keinen Zugriff.

seahawk1986 schrieb:

Die ~/.bash_profile wird von der Shell gesourced (also der darin enthaltene Code im Kontext der Shell ausgeführt), dafür wird keine extra Subshell gestartet.

Das heißt also wenn das Script in .bash_profile ist, wird es nicht als Child von Bash ausgeführt, sondern quasi mit Bash zusammen?

Wäre es möglich das Script selber durch eval ausführen zu lassen, um nicht in .bash_profile schreiben zu müssen? z.B. mit eval $(cat myscript)?

(nur des Verständnis halber)

"$@" repräsentiert alle Argumente, die der Funktion übergeben wurden. Die Funktionen dienen als Wrapper, um sicherzustellen, dass der ssh-agent auf jeden Fall gestartet wurde, bevor der jeweilige Befehl aufgerufen wurde.

Also wenn ich nun z.B. git clone link ausführe, sorgt das "$@" dafür, dass die argumente die ich der "git" funktion gegeben habe (clone link), mittels der Funktion git() { /usr/bin/git "$@" } an /usr/bin/git geparst wird, als ob der Befehl direct an /usr/bin/git gegangen wäre

Ich nehme an er erkennt automatisch jedes vom Funktionsnamen mit Leerzeichen getrennte Wort als Argument.

Und warum wird der ssh-agent nicht über einen systemd service gestartet und verwaltet?

Hast du mal auf das Datum des verlinkten Posts geschaut? 2013 war Ubuntu noch bei Upstart als Init-System...

Nein, ich werd nächstes Mal darauf achten.

Mit Systemd macht es am ehesten Sinn den ssh-agent über Systemd zu starten, wenn das im Rahmen einer Systemd User-Session im Kontext einer Desktop-Sitzung passiert, wie in SSH_keys beschrieben. Wenn du dich nur an einer Shell am Server anmeldest, hast du das Problem, die von der Systemd-Unit ggf. ausgelöste Passwortabfrage zum Entsperren des Keys zu Gesicht zu bekommen, daher sind das Skripte praktischer, die beim Start der Shell ausgeführt werden.

D.H. wenn der Agent über .bashrc oder .bash_profile gestartet wird, ist der dienst global aktiv, und jeder Nutzer kann auf ihn zugreifen, während mit systemd der Dienst auf eine Usersession beschränkt ist, die üblicherweise eine x-session ist?

Wenn du dem Server vertraust, könntest du dir auch überlegen SSH-Agent Forwarding von deinem Desktop-Rechner aus einzuschalten, vgl. z.B. https://dev.to/levivm/how-to-use-ssh-and-ssh-agent-forwarding-more-secure-ssh-2c32 oder https://developer.github.com/v3/guides/using-ssh-agent-forwarding/, damit du die privaten Schlüssel nicht auf dem Server vorhalten musst.

Das werde ich mir später genauer ansehen.

Vielen Dank für deine Hilfe, das hat mich ein großes Stück weitergebracht! Ich werde das jetzt alles mal implementieren und danach setz ich hier solved.

vg hghtch

seahawk1986

Anmeldungsdatum:
27. Oktober 2006

Beiträge: 11250

Wohnort: München

hghtch schrieb:

Das heißt also wenn das Script in .bash_profile ist, wird es nicht als Child von Bash ausgeführt, sondern quasi mit Bash zusammen?

es wird von der Bash so interpretiert wie denn jemand die darin enthaltenen Befehle eingeben hätte.

Wäre es möglich das Script selber durch eval ausführen zu lassen, um nicht in .bash_profile schreiben zu müssen? z.B. mit eval $(cat myscript)?

(nur des Verständnis halber)

Du kannst den Befehl source (bzw. die Kurzform .) nutzen, um beliebige Dateien auf diese Art einzulesen.

"$@" repräsentiert alle Argumente, die der Funktion übergeben wurden. Die Funktionen dienen als Wrapper, um sicherzustellen, dass der ssh-agent auf jeden Fall gestartet wurde, bevor der jeweilige Befehl aufgerufen wurde.

Also wenn ich nun z.B. git clone link ausführe, sorgt das "$@" dafür, dass die argumente die ich der "git" funktion gegeben habe (clone link), mittels der Funktion git() { /usr/bin/git "$@" } an /usr/bin/git geparst wird, als ob der Befehl direct an /usr/bin/git gegangen wäre

Genau, dadurch werden einfach die Argumente durchgereicht.

Ich nehme an er erkennt automatisch jedes vom Funktionsnamen mit Leerzeichen getrennte Wort als Argument.

Die Shell trennt die Argumente am IFS auf, der standardmäßig nicht nur Leerzeichen, sondern auch anderen Whitespace (wie z.B. Tabs) umfasst.

D.H. wenn der Agent über .bashrc oder .bash_profile gestartet wird, ist der dienst global aktiv, und jeder Nutzer kann auf ihn zugreifen, während mit systemd der Dienst auf eine Usersession beschränkt ist, die üblicherweise eine x-session ist?

Nein, das will man aus Sicherheitsgründen eigentlich in keinem Fall haben. Wenn du eine Systemd-Unit in einer User-Session nutzt, kann diese beim Start der Session gestartet werden, nicht erst wenn du eine Shell aufmachst - und da man auf einem Desktop-System das Passwort für den SSH-Key in den Schlüsselbund packen kann, der automatisch bei der Benutzeranmeldung entsperrt werden kann, besteht so eine Möglichkeit so zu einem funktionsfähigen ssh-agent zu kommen, ohne selbst eine Shell geöffnet zu haben.

Antworten |