Shell – how to execute commands on remote server as different user

shell-scriptssh

I am trying to connect to server B from server A using ssh and executing commands using some other user.
However,
when I try searching for a pattern in log file it says "cannot open log file"
below is the sample code

ssh  -t user@hostname <<EOF
sudo su - someotheruser
a=`tail -10 /somepath/application.log | awk '/Agent Exited/ { print $3 }'`
if [ $a -eq 0 ] 
then
echo "Success"
else
echo "Failure"
fi 
EOF

once I run the script,
it says, unable to open "tail........."

I can't stay logged in on server B and run multiple commands.

Best Answer

Think carefully about when each command is executed, where it runs, and what input it receives.

  1. First the here document is expanded. This means that the tail/awk pipe is executed on the local host, and the variable substitution $a as well.
  2. Then the ssh command is executed. It receives the expanded here document; these are commands that are executed in the remote shell.
  3. The remote shell is executed with no arguments, so it reads commands to execute from standard input. These commands include sudo, but possibly (depending on the shell) some of the following lines as well.
  4. The remote shell executes sudo su - someotheruser. This runs a shell as someotheruser which first reads and executes that user's .profile, then reads commands from its standard input. The standard input contains whatever the first remote shell did not read, which is somewhat unpredictable (it depends on the shell and how much it happened to read from its input pipe).
  5. The shell running as someotheruser runs the commands that it read, if any.
  6. The shell running as someuser executes the if command (if it's read it).

To avoid here document expansion, use quotes around the heredoc marker. To avoid the unholy mixture of standard inputs, use sh -c … or be explicit as to what the second remote shell receives as its input.

ssh  -t user@hostname <<'SSH_EOF'
sudo su - someotheruser <<'SU_EOF'
a=`tail -10 /somepath/application.log | awk '/Agent Exited/ { print $3 }'`
if [ "$a" -eq 0 ] 
then
echo "Success"
else
echo "Failure"
fi
SU_EOF
SSH_EOF

Do you really need to source someotheruser's .profile? If not, use sudo -u someotheruser. If you do, use sudo -i -u someotheruser. Ajust your sudoers rule accordingly.

Reading the log file is the only thing that requires elevated privileges, so it would make sense to only run the tail command as someotheruser.

ssh -t user@hostname <<'SSH_EOF'
a=`sudo -u someotheruser tail -10 /somepath/application.log | awk '/Agent Exited/ { print $3 }'`
if [ "$a" -eq 0 ] 
then
echo "Success"
else
echo "Failure"
fi
SSH_EOF

You'll make your life a lot easier if you don't mix privilege escalation methods. Instead of using sudo to switch from someuser to someotheruser, use SSH to localhost. Chaining two ssh commands is easy. Set up a key — you can even set up a key that only allows running a specific command like tail -10 /somepath/application.log. Define an alias in your .ssh/config to SSH through the someuser account:

Host hostname-someotheruser
HostName hostname
UserName someotheruser
ProxyCommand ssh someuser@hostname

Then run

a=$(ssh hostname-someotheruser tail -10 /somepath/application.log |
    awk '/Agent Exited/ { print $3 }')
if [ "$a" -eq 0 ] 
then
  echo "Success"
else
  echo "Failure"
fi
Related Question