Question Comment puis-je exécuter des commandes arbitrairement complexes en utilisant sudo sur ssh?


J'ai un système auquel je ne peux me connecter que sous mon nom d'utilisateur (myuser), mais je dois exécuter des commandes en tant qu'autre utilisateur (scriptuser). Jusqu'ici, je suis venu avec ce qui suit pour exécuter les commandes dont j'ai besoin:

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

Si toutefois, lorsque j'essaie d'exécuter une commande plus complexe, telle que [[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory" J'ai rapidement des ennuis avec les citations. Je ne sais pas comment je pourrais passer cet exemple de commande complexe à bash -c, quand \" délimite déjà les limites de la commande que je passe (et donc je ne sais pas comment citer / tmp / Some directory, qui inclut des espaces.

Existe-t-il une solution générale me permettant de passer n’importe quelle commande, quelle que soit la complexité ou la folie de la citation, ou s’agit-il d’une limitation que j’ai atteinte? Existe-t-il d'autres solutions possibles et peut-être plus lisibles?


76
2017-09-02 09:21


origine


Copiez un script dans $ remote puis exécutez-le. - Iain
Cela fonctionnerait, mais je trouverais une solution qui ne laisse aucun fichier de script (en cas de problème, etc.) serait un peu plus propre. - VoY
avoir le script lui-même à la fin de chaque exécution - thanasisk
Pensez à utiliser du tissu fabfile.org. Peut vous rendre la vie beaucoup plus facile si vous devez vous déplacer beaucoup à distance. - Nils Toedtmann
Si vous avez installé Ansible, cette commande affiche la documentation de votre cas d'utilisation: script ansible-doc - bbaassssiiee


Réponses:


Une astuce que j’utilise parfois est d’utiliser base64 pour encoder les commandes et de la diriger vers bash sur l’autre site:

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

Ceci encodera le script, avec des virgules, des barres obliques inverses, des guillemets et des variables dans une chaîne sécurisée, et l'enverra à l'autre serveur. (-w0 est nécessaire pour désactiver le retour à la ligne, ce qui se produit par défaut à la colonne 76). D'un autre côté, $(base64 -d) va décoder le script et le transmettre à bash pour qu'il soit exécuté.

Je n’ai jamais eu de problème, peu importe la complexité du script. Résout le problème de l'évasion, car il n'est pas nécessaire d'échapper à rien. Il ne crée pas de fichier sur l'hôte distant et vous pouvez facilement exécuter des scripts extrêmement complexes.


138
2017-09-02 13:10



Ou même: ssh user@remotehost "echo `base64 -w0 script.sh` | base64 -d | sudo bash" - Niklas B.
Il est à noter que dans la plupart des cas, vous pouvez substituer lzop ou gzip à base64 pour des temps de transfert plus rapides. Cependant, il peut y avoir des cas extrêmes. YMMV. - CodeGnome
Bonne note, mais si c'est un script, je ne m'attends pas à ce que le transfert soit supérieur à quelques ko. - ThoriumBR
Il y a une utilisation inutile d'écho ici aussi. base64 script | ssh remotehost 'base64 -d | sudo bash' serait suffisant :) - hobbs
Testé aujourd'hui et parfaitement travaillé. Merci les gars. - Soham Chakraborty


Voir le -tt option? Lis le ssh(1) Manuel.

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

Une chose que je fais souvent est d'utiliser vim et d'utiliser le :!cat % | ssh -tt somemachine tour.


32
2017-09-02 13:01



Bien sûr :!cat % | (command) peut être fait comme :w !(command) ou :!(command) < %. - Scott
Oui. Ma ligne est un abus de chat - moebius_eye


Je pense que la solution la plus simple réside dans une modification du commentaire de @ thanasisk.

Créer un script, scp à la machine, puis exécutez-le.

Avoir le script rm lui-même au début. Le shell a ouvert le fichier, il a donc été chargé et peut ensuite être supprimé sans problèmes.

En faisant les choses dans cet ordre (rm d’abord, d’autres choses ensuite) il sera même supprimé lorsqu’il échoue à un moment donné.


9
2017-09-02 11:26





Vous pouvez utiliser le %q spécificateur de format avec printf prendre en charge la variable s'échappant pour vous:

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

printf -v écrit la sortie dans une variable (dans ce cas, $cmd_str). Je pense que c'est la manière la plus simple de le faire. Il n'est pas nécessaire de transférer des fichiers ou d'encoder la chaîne de commande (autant que j'aime le truc).

Voici un exemple plus complexe montrant que cela fonctionne également pour des éléments tels que les crochets et les esperluettes:

$ 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

Je ne l'ai pas testé avec sudo mais cela devrait être aussi simple que:

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

Si vous le souhaitez, vous pouvez ignorer une étape et éviter de créer la variable intermédiaire:

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

Ou même simplement éviter de créer une variable entièrement:

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

7
2017-09-04 20:10



c'est une solution géniale. J'ai déjà dû utiliser printf auparavant pour une situation similaire, mais je l'oublie toujours. Merci d'avoir posté ceci :-) - Jon L.


Voici la manière "correcte" (syntaxique) d'exécuter quelque chose comme ceci dans bash:

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
)"

Pour une explication détaillée de la façon dont cela fonctionne, veuillez consulter https://stackoverflow.com/a/21761956/111948


6
2018-05-28 17:48





Etes-vous conscient que vous pouvez utiliser sudo vous donner un shell où vous pouvez exécuter des commandes en tant qu'utilisateur choisi?

-i, --login

Exécutez le shell spécifié par l'entrée de la base de données de mots de passe de l'utilisateur cible en tant que shell de connexion. Cela signifie que les fichiers de ressources spécifiques à la connexion, tels que                    .profile ou .login sera lu par le shell. Si une commande est spécifiée, elle est transmise au shell pour exécution via l'option -c du shell. Sinon                    Si la commande est spécifiée, un shell interactif est exécuté. sudo tente de modifier le répertoire de base de cet utilisateur avant d'exécuter le shell. La com-                    mand est exécuté avec un environnement similaire à celui qu'un utilisateur recevrait lors de la connexion. La section relative à l'environnement de commande dans le document sudoers (5) du manuel                    explique comment l’option -i affecte l’environnement dans lequel une commande est exécutée lorsque la stratégie sudoers est utilisée.


4
2017-09-03 09:22



cela semble être la solution évidente pour moi. > sudo -i -u brian - code_monk
Cela fonctionne mieux lorsqu'il est combiné avec "ssh -t" dans le cas de l'accès à distance. Ce qui est inclus dans la question, mais mérite d'être répété pour les gens "je ne peux pas lire ceci / tout / page". :) - dannysauer


Vous pouvez définir le script sur votre machine locale puis cat et dirigez-le vers la machine distante:

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 vous pouvez utiliser < - Iain
Pouvez-vous modifier l'exemple pour inclure sudo -u scriptuser? Hérédoc serait-il utilisable étant donné que je devais avoir des variables dans le script, je serais en train de me diriger vers la machine? - VoY
J'essayais: echo "sudo `cat fileForSsh.txt`" | ssh ... mais je continue à obtenir sudo: sorry, you must have a tty to run sudo. - jas_raj
Bien que cette question peut aider si vous pouvez obtenir le /etc/sudoers fichier modifié - jas_raj
Cela fonctionne pour moi: ssh -tq user@host "sudo bash -s" < test.sh - AVee


Simple et facile.

utilisateur ssh @ servidor "bash -s" <script.sh


1
2017-09-03 20:15