How can I run arbitrarily complex command using sudo over ssh?
I have a system that I can only log in to under my username (myuser), but I need to run commands as other user (scriptuser). So far, I have come up with the following to run the commands I need:
ssh -tq myuser@hostname "sudo -u scriptuser bash -c \"ls -al\""
If however, when I try to run a more complex command, such as [[ -d "/tmp/Some directory" ]] && rm -rf "/tmp/Some directory"
I quickly get into trouble with quoting. I'm not sure how I could pass this example complex command to bash -c
, when \"
already delimites the boundaries of the command I'm passing (and so I don't know how to quote /tmp/Some directory, which includes a spaces.
Is there a general solution allowing me to pass any command no matter how complex/crazy the quoting is, or is this some sort of limitation I have reached? Are there other possible and perhaps more readable solutions?
Solution 1:
A trick I use sometimes is to use base64 to encode the commands, and pipe it to bash on the other site:
MYCOMMAND=$(base64 -w0 script.sh)
ssh user@remotehost "echo $MYCOMMAND | base64 -d | sudo bash"
This will encode the script, with any commas, backslashes, quotes and variables inside a safe string, and send it to the other server. (-w0
is required to disable line wrapping, which happens at column 76 by default). On the other side, $(base64 -d)
will decode the script and feed it to bash to be executed.
I never got any problem with it, no matter how complex the script was. Solves the problem with escaping, because you don't need to escape anything. It does not creates a file on the remote host, and you can run vastly complicated scripts with ease.
Solution 2:
See the -tt
option? Read the ssh(1)
manual.
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
One thing I often do is use vim and use the :!cat % | ssh -tt somemachine
trick.