Frage Wie kann ich beliebig komplexen Befehl mit Sudo über SSH ausführen?


Ich habe ein System, bei dem ich mich nur unter meinem Benutzernamen (myuser) anmelden kann, aber ich muss Befehle als anderer Benutzer ausführen (scriptuser). Bis jetzt habe ich Folgendes entwickelt, um die Befehle auszuführen, die ich brauche:

ssh -tq myuser@hostname "sudo -u scriptuser bash -c \"ls -al\""

Wenn ich jedoch versuche, einen komplexeren Befehl auszuführen, wie z [[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory" Ich bekomme schnell Probleme mit Zitaten. Ich bin nicht sicher, wie ich diesen Beispielkomplexbefehl weitergeben könnte bash -c, wann \" Begrenzt bereits die Grenzen des Befehls, den ich übergebe (und daher weiß ich nicht, wie ich / tmp / irgendein Verzeichnis angeben soll, das Leerzeichen enthält.

Gibt es eine allgemeine Lösung, die es mir erlaubt, jeden Befehl zu übergeben, egal wie komplex / verrückt das Zitat ist, oder ist das eine Art von Einschränkung, die ich erreicht habe? Gibt es andere mögliche und vielleicht besser lesbare Lösungen?


76
2017-09-02 09:21


Ursprung


Kopieren Sie ein Skript nach $ remote und führen Sie es dann aus. - Iain
Das würde funktionieren, aber ich finde eine Lösung, die keine Skriptdateien zurücklässt (falls etwas schief geht usw.) wäre ein bisschen sauberer. - VoY
Habe das Skript selbst am Ende jedes Laufes - thanasisk
Erwägen Sie, Stoff zu verwenden fabfile.org. Kann Ihnen das Leben viel einfacher machen, wenn Sie oft remote surfen müssen. - Nils Toedtmann
Wenn Sie Ansible installiert haben, zeigt dieser Befehl die Dokumentation für Ihren Anwendungsfall: ansible-doc script - bbaassssiiee


Antworten:


Ein Trick, den ich manchmal benutze, ist, base64 zu benutzen, um die Befehle zu codieren, und es an die andere Seite zu übertragen:

MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"

Dadurch wird das Skript mit beliebigen Kommas, Backslashs, Anführungszeichen und Variablen innerhalb einer sicheren Zeichenfolge codiert und an den anderen Server gesendet. (-w0 ist erforderlich, um Zeilenumbruch zu deaktivieren, was standardmäßig in Spalte 76 geschieht. Auf der anderen Seite, $(base64 -d) entschlüsselt das Skript und füttert es in bash zur Ausführung.

Ich habe nie ein Problem damit gehabt, egal wie komplex das Skript war. Löst das Problem mit der Flucht, weil Sie nichts entgehen müssen. Es erstellt keine Datei auf dem Remote-Host, und Sie können sehr komplizierte Skripte mit Leichtigkeit ausführen.


138
2017-09-02 13:10



Oder auch: ssh user@remotehost "echo `base64 -w0 script.sh` | base64 -d | sudo bash" - Niklas B.
Es ist erwähnenswert, dass Sie in den meisten Fällen lzop oder gzip für base64 ersetzen können, um schnellere Übertragungszeiten zu erzielen. Es kann jedoch Kantenfälle geben. YMMV. - CodeGnome
Gute Anmerkung, aber wenn es ein Skript ist, erwarte ich keine Übertragung von mehr als ein paar KB. - ThoriumBR
Auch hier gibt es einen nutzlosen Echo-Effekt. base64 script | ssh remotehost 'base64 -d | sudo bash' wäre genug :) - hobbs
Heute getestet und perfekt gearbeitet. Danke Leute. - Soham Chakraborty


Siehe die -tt Möglichkeit? Lies das ssh(1) Handbuch.

ssh -tt root@host << EOF
sudo some # sudo shouldn't ask for a password, otherwise, this fails. 
lines
of
code 
but be careful with \$variables
and \$(other) \`stuff\`
exit # <- Important. 
EOF

Eine Sache, die ich oft tue, ist vim und benutze die :!cat % | ssh -tt somemachine Trick.


32
2017-09-02 13:01



Na sicher :!cat % | (command) kann als gemacht werden :w !(command) oder :!(command) < %. - Scott
Ja. Meine Linie ist a Katzenmissbrauch - moebius_eye


Ich denke, die einfachste Lösung liegt in einer Änderung von @ thanasisks Kommentar.

Erstelle ein Skript, scp es an die Maschine, dann führe es aus.

Habe das Skript rm selbst am Anfang. Die Shell hat die Datei geöffnet, also wurde sie geladen und kann dann ohne Probleme entfernt werden.

Dinge in dieser Reihenfolge erledigen (rm Erstens, andere Sachen zweitens) es wird sogar entfernt werden, wenn es an einem Punkt versagt.


9
2017-09-02 11:26





Du kannst den ... benutzen %q Formatbezeichner mit printf um die Variable zu kümmern, die für dich entgeht:

cmd="ls -al"
printf -v cmd_str '%q' "$cmd"
ssh user@host "bash -c $cmd_str"

printf -v schreibt die Ausgabe in eine Variable (in diesem Fall $cmd_str). Ich denke, dass dies der einfachste Weg ist, dies zu tun. Es gibt keine Notwendigkeit, irgendwelche Dateien zu übertragen oder die Befehlszeichenfolge zu codieren (so sehr ich den Trick mag).

Hier ist ein komplexeres Beispiel, das zeigt, dass es auch für eckige Klammern und Et-Zeichen funktioniert:

$ ssh user@host "ls -l test"
-rw-r--r-- 1 tom users 0 Sep  4 21:18 test
$ cmd="[[ -f test ]] && echo 'this really works'"
$ printf -v cmd_str '%q' "$cmd"
$ ssh user@host "bash -c $cmd_str"
this really works

Ich habe es nicht mit getestet sudo aber es sollte so einfach sein wie:

ssh user@host "sudo -u scriptuser bash -c $cmd_str"

Wenn Sie möchten, können Sie einen Schritt überspringen und vermeiden, die Zwischenvariable zu erstellen:

$ ssh user@host "bash -c $(printf '%q' "$cmd")"
this really works

Oder vermeiden Sie es einfach, eine Variable vollständig zu erstellen:

ssh user@host "bash -c $(printf '%q' "[[ -f test ]] && echo 'this works as well'")"

7
2017-09-04 20:10



Das ist eine großartige Lösung. Ich musste früher printf für eine ähnliche Situation verwenden, aber ich vergesse es immer. Danke für das Posting :-) - Jon L.


Hier ist der "richtige" (syntaktische) Weg, um so etwas in bash auszuführen:

ssh user@server "$( cat <<'EOT'
echo "Variables like '${HOSTNAME}' and commands like $( uname -a )"
echo "will be interpolated on the server, thanks to the single quotes"
echo "around 'EOT' above.
EOT
)"

ssh user@server "$( cat <<EOT
echo "If you want '${HOSTNAME}' and $( uname -a ) to be interpolated"
echo "on the client instead, omit the the single quotes around EOT."
EOT
)"

Für eine gründliche Erklärung, wie das funktioniert, sehen Sie bitte https://stackoverflow.com/a/21761956/111948


6
2018-05-28 17:48





Ist dir bewusst, dass du es benutzen kannst? sudo um Ihnen eine Shell zu geben, wo Sie Befehle als der gewählte Benutzer ausführen können?

-i, --login

Führen Sie die vom Kennwortdatenbankeintrag des Zielbenutzers angegebene Shell als Anmeldungsshell aus. Dies bedeutet, dass Login-spezifische Ressourcendateien wie z                    .profile oder .login wird von der Shell gelesen. Wenn ein Befehl angegeben wird, wird er über die Option -c der Shell zur Ausführung an die Shell übergeben. Wenn nein                    Befehl angegeben ist, wird eine interaktive Shell ausgeführt. sudo versucht, vor dem Ausführen der Shell zum Ausgangsverzeichnis dieses Benutzers zu wechseln. die Kom-                    mand wird mit einer Umgebung ausgeführt, die derjenigen ähnelt, die ein Benutzer bei der Anmeldung erhalten würde. Der Abschnitt Befehlsumgebung in den manuellen Dokumenten von sudoers (5)                    Gibt an, wie sich die Option -i auf die Umgebung auswirkt, in der ein Befehl ausgeführt wird, wenn die Richtlinie sudoers verwendet wird.


4
2017-09-03 09:22



Das scheint mir die offensichtliche Lösung zu sein. > sudo -i -u brian - code_monk
Dies funktioniert am besten, wenn es mit "ssh -t" im Falle eines Fernzugriffs kombiniert wird. Das ist in der Frage enthalten, aber wiederholt sich für die "Ich kann das nicht lesen / ganze / Seite" Leute. :) - dannysauer


Sie können das Skript auf Ihrem lokalen Rechner definieren und dann cat und es an die entfernte Maschine leiten:

user@host:~/temp> echo "echo 'Test'" > fileForSsh.txt
user@host:~/temp> cat fileForSsh.txt | ssh localhost

Pseudo-terminal will not be allocated because stdin is not a terminal.
stty: standard input: Invalid argument
Test

3
2017-09-02 09:39



UUOC können Sie <verwenden - Iain
Können Sie das Beispiel ändern, um es einzuschließen? sudo -u scriptuser? Wäre Heredoc benutzbar, wenn ich Variablen im Skript haben muss, die ich an die Maschine leiten würde? - VoY
Ich habe es versucht: echo "sudo `cat fileForSsh.txt`" | ssh ... aber ich bekomme weiter sudo: sorry, you must have a tty to run sudo. - jas_raj
Obwohl diese Frage kann helfen, wenn Sie das bekommen können /etc/sudoers Datei geändert - jas_raj
Das funktioniert für mich: ssh -tq user@host "sudo bash -s" < test.sh - AVee