Script di Bash per configurare un tunnel SSH temporaneo


132

Su Cygwin, voglio uno script Bash per:

  1. Creare un tunnel SSH su un server remoto.
  2. Fai un po 'di lavoro a livello locale che utilizza il tunnel.
  3. Quindi chiudere il tunnel.

La parte di spegnimento mi ha lasciato perplesso.

Attualmente, ho una soluzione scadente. In una shell eseguo quanto segue per creare un tunnel:

# Create the tunnel - this works! It runs forever, until the shell is quit.
ssh -nNT -L 50000:localhost:3306 jm@sampledomain.com

Quindi, in un'altra finestra della shell, faccio il mio lavoro:

# Do some MySQL stuff over local port 50000 (which goes to remote port 3306)

Alla fine, quando ho finito, chiudo la prima finestra della shell per uccidere il tunnel.

Mi piacerebbe fare tutto questo in uno script come:

# Create tunnel
# Do work
# Kill tunnel

Come posso tenere traccia del processo del tunnel, quindi so quale uccidere?


Ho scritto una sceneggiatura che potrebbe aiutare a fare tunneling ssh, puoi verificarlo su: github.com/gdbtek/ssh-tunneling.git
Nam Nguyen,

Risposte:


324

Puoi farlo in modo pulito con un 'control socket' ssh. Per parlare con un processo SSH già in esecuzione e ottenerne il pid, ucciderlo ecc. Utilizzare il 'control socket' (-M per master e -S per socket) come segue:

$ ssh -M -S my-ctrl-socket -fnNT -L 50000:localhost:3306 jm@sampledomain.com
$ ssh -S my-ctrl-socket -O check jm@sampledomain.com
Master running (pid=3517) 
$ ssh -S my-ctrl-socket -O exit jm@sampledomain.com
Exit request sent. 

Nota che my-ctrl-socket sarà un vero file creato.

Ho ricevuto queste informazioni da una risposta molto RTFM sulla mailing list di OpenSSH .


6
Questa è la risposta migliore che ho visto finora sull'argomento. Grazie mille, dovrebbe essere quello accettato. Lo uso per connettermi alla mia VM Vagrant ed eseguire uno script di aggiornamento FlywayDB.
Christian,

2
Apparentemente le prese di controllo non funzionano ovunque. Ad esempio, ottengo Operation not permittedun ambiente di integrazione continua drone.io:muxserver_listen: link mux listener ssh-ctrl-socket.wsASkszgSBlK7kqD => ssh-ctrl-socket: Operation not permitted
Mikko Ohtamaa,

Quindi cosa succede al my-ctrl-socketfile dopo averlo eseguito? Quando lo faccio ls -lanella cartella corrente non riesco più a vedere il file.
sachinruk,

2
Se lo si utilizza in uno script, è necessario attendere che il socket di controllo diventi disponibile per alcuni secondi. La mia soluzione:while [ ! -e $ctrl_socket ]; do sleep 0.1; done
Adam Wallner,

quando lo faccio ottengo open failed: administratively prohibited: open failede non penso che stia aprendo il tunnel
Andy Ray

21

Puoi dire a SSH di fare lo sfondo con l'opzione -f ma non otterrai il PID con $ !. Inoltre, invece di far sospendere lo script per un periodo di tempo arbitrario prima di utilizzare il tunnel, è possibile utilizzare -o ExitOnForwardFailure = yes con -f e SSH attenderà che tutte le porte remote vengano inoltrate correttamente prima di posizionarsi in background. Puoi ottenere l'output di ps per ottenere il PID. Ad esempio puoi usare

...
ssh -Cfo ExitOnForwardFailure=yes -NL 9999:localhost:5900 $REMOTE_HOST
PID=$(pgrep -f 'NL 9999:')
[ "$PID" ] || exit 1
...

ed essere abbastanza sicuri di ottenere il PID desiderato


Potresti non rendertene conto, ma questa è una specie di genio. Stavo cercando un modo per tracciare i PID del tunnel SSH e ho quasi finito con gli script di servizio systemd. Non più: posso accedere al processo SSH di cui ho bisogno usando il nome del tunnel. Questa idea mi ha completamente ignorato. Molte grazie!
aexl,

19
  • Puoi dire sshdi andare in background con &e non creare una shell sull'altro lato (basta aprire il tunnel) con un flag da riga di comando (vedo che l'hai già fatto con -N).
  • Salvare il PID con PID=$!
  • Fai le tue cose
  • kill $PID

EDIT: fisso $? a $! e aggiunto il &


3
Se la mia sceneggiatura muore da qualche parte prima che arrivi a KILL, devo fare attenzione a gestirla.
jm.

2
@jm: trap 'kill $PID' 1 2 15coprirà molti casi di fallimento dello script.
Norman Ramsey,

3
Perché questo funzioni in modo affidabile, ho dovuto "dormire" un po 'DOPO aver creato il tunnel, ma prima di usarlo.
jm.

@NormanRamsey Penso che intendi trap "kill $PID", perché bash interpolerà solo le variabili all'interno di stringhe tra virgolette doppie
JuanCaicedo

1
@JuanCaicedo La distinzione sarebbe importante solo se la PIDvariabile fosse ridefinita in seguito. La variabile viene espansa quando trapviene chiamato il built-in (approccio dell'OP) o quando viene catturato un segnale (il tuo approccio); entrambi gli approcci producono lo stesso risultato qui.
Witiko,

4

Preferisco lanciare una nuova shell per compiti separati e utilizzo spesso la seguente combinazione di comandi:

  $ sudo bash; exit

o talvolta:

  $ : > sensitive-temporary-data.txt; bash; rm -f sensitive-temporary-data.txt; exit

Questi comandi creano una shell nidificata in cui posso fare tutto il mio lavoro; quando ho finito premo CTRL-D e la shell genitore si ripulisce ed esce pure. Potresti facilmente buttare bash;nel tuo script ssh tunnel appena prima della killparte in modo che quando esci dalla shell nidificata il tuo tunnel verrà chiuso:

#!/bin/bash
ssh -nNT ... &
PID=$!
bash
kill $PID

Molto interessante. Questo potrebbe gestire meglio il problema "trap". Dovrò provarlo.
jm.

2

Potresti lanciare il carattere sshcon un &fine, per metterlo in background e afferrare il suo ID quando lo fai. Quindi devi solo fare uno killdi quell'ID quando hai finito.


Fare attenzione se si utilizza la e commerciale ("&"). È un brutto approccio poiché dovrai determinare l'effettiva connessione stabilita per te stesso. Può causare l'esecuzione di ulteriore codice che non è in attesa di stabilire completamente la connessione effettiva. Inoltre, la connessione non verrà interrotta automaticamente se lo script si interrompe.
Jonathan,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.