Ruby shell visibility - ruby

I am trying to shell out in Ruby to use SSH. I know there is an SSH module but I don't want to use it. I find it clunky and confusing.
I am able to shell out and use SSH very nicely. I have one complaint, however, that I was hoping someone could offer some suggestions.
In Bash I can do this:
echo "PASSWORD" | ssh SERVER "sudo -S cat /etc/sudoers"
and it will show up as this when I do a ps -ef:
USER 8212 8837 0 09:31 pts/7 00:00:00 ssh SERVER sudo -S cat /etc/sudoers
The password is NOT shown when doing a ps -ef.
When I do the same in ruby, it is echoing the password:
%x[echo "#{password}" | ssh -q -o BatchMode=yes SERVER "sudo -S cat /etc/sudoers 2>/dev/null"].split("\n")
Shows up on the server with ps -ef:
sh -c echo "PASSWORD" | ssh -q -o BatchMode=yes SERVER "sudo -S cat /etc/sudoers 2>/dev/null"

Try using Ruby's Open3.popen3 or Open3.capture3. But, I don't think it'll work because ssh doesn't accept the password from STDIN and will rewire the input to come from the keyboard, at least that's the behavior I've encountered on CentOS and Mac OS.
Here's some code to test it against:
require 'open3'
host = 'myhost'
user = 'myname'
password = 'mypassword'
stdin, stdout, stderr, wait_thr = Open3.popen3(ENV, %Q[ssh #{host} "cat /home/#{user}/.bash_profile"])
pid = wait_thr[:pid]
stdin.puts password
stdin.close
puts stdout.read
stdout.close
puts stderr.read
stderr.close
exit_status = wait_thr.value
Running it shows the ssh prompt, even though the password is "puts" on the stdin channel, followed by the output once I enter the password:
myname#myhost's password:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
set editing-mode vi
# complete -W "$(echo $(grep '^ssh ' .bash_history | sort -u | sed 's/^ssh //'))" ssh
complete -W "$(echo $(grep '^ssh ' .bash_history | sort -u | sed 's/^ssh //' | sed 's/^.+#//'))" ssh
PATH=$HOME/bin:$PATH
export PATH
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
While Net::SSH might be "clunky", it is designed to allow you to cleanly work around this behavior in ssh. We use Net::SSH extensively internally, and it's working really well for our needs.

Related

Run a script on remote server with ssh password or key

I'm trying to run a script on a remote server with either password credentials or .pem key access and I'm getting errors no matter which solution I've found etc.
bash script content:
#!/bin/bash
sudo fdisk -l
ssh -T -i "~/.ssh/keys/key.pem" ubuntu#host "sudo bash <(wget -qO- http://host.com/do.sh)"
Error: bash: /dev/fd/63: No such file or director
ssh user#host.com 'echo "password" | sudo bash <(wget -qO- http://www.host.io/do.sh)'
Error: sudo: a password is required
ssh -t user#host.com "echo password | sudo fdisk -l"
Works but still gives me the password propmt
echo -t pass | ssh user#host "sudo bash <(wget -qO- http://host.com/do.sh)"
echo -tt pass | ssh user#host "sudo bash <(wget -qO- http://host.com/do.sh)"
Error: bash: /dev/fd/63: No such file or directory
// And I also get the password prompt
echo -tT pass | ssh user#host "sudo bash <(wget -qO- http://host.com/do.sh)"
Error: sudo: a terminal is required to read the password; either use the -S option to read from standard input or configure an askpass helper
sudo: a password is required
// And I also get the password prompt
// This works but I still get the password propmt
ssh user#host 'echo "password" | sudo -S sudo fdisk -l'
These are different variations of the supposed solutions from other places.
What I'm trying to do:
Is to run a script from a URL on the remote server while echoing the password to the cmd so I don't get propmt to input the password manually.
To be able to do the same thing above with using the .pem key variant also
For an explanation for commands except the first one, You can't do stdin-redirect a password to ssh if ssh requires interactively. ssh only allows manual typing if you use a password.
Your first error said that bash can't read a file descriptor. So ssh via ~/.ssh/keys/key.pem works. To run the shell command on the fly,
ssh -T -i "~/.ssh/keys/key.pem" ubuntu#host "curl -fsSL http://host.com/do.sh | sudo bash"
Does your script really need to run with sudo??
If not, then try this:
ssh user#host "curl -s -o do.sh 'http://host.com/do.sh'; source do.sh"

Execute commands as different user via sudo over SSH in a justfile

I have this justfile:
remote:
#!/usr/bin/env bash
read -p 'Password:' -s password
ssh -tt somewhere 'bash -l -s' << 'ENDSSH'
whoami
echo "$password" | sudo su someone 'bash -l -s' << 'ENDSUDO'
whoami
ENDSUDO
ENDSSH
It should:
Ask me for a password
SSH into somewhere
sudo to change the user
execute some scripts
What it does:
It asks for a password a second time.
It stucks on input (no error message).
How to solve this problem?
Update
As suggested by #xhienne, this does almost work, but it says, I use the wrong password:
remote:
#!/usr/bin/env bash
read -p 'Password:' -s password
ssh -tt somewhere 'bash -l -s' << 'ENDSSH'
sudo -S -i -u someone << ENDSUDO
$password
whoami
ENDSUDO
exit
ENDSSH
But this does work:
remote:
#!/usr/bin/env bash
read -p 'Password:' -s password
ssh -tt somewhere 'bash -l -s' << 'ENDSSH'
sudo -S -i -u someone << ENDSUDO
clear-text-password
whoami
ENDSUDO
exit
ENDSSH
Update 2
The answer of #xhienne does work.
With
echo "$password" | sudo su someone 'bash -l -s' << 'ENDSUDO'
whoami
ENDSUDO
You are redirecting stdin twice:
once with |
a second time with <<
Try this:
sudo -S -i -u someone << ENDSUDO
$password
whoami
ENDSUDO
sudo -S will read the password from stdin. sudo -i is a substitute for the ugly sudo su bash -l (but it needs that sudo be properly configured for -u someone)
Note that I removed the quotes around ENDSUDO. Beware of inadvertent substitutions. If you must keep ENDSUDO quoted, then you can try this instead:
{
echo "$password"
cat << 'ENDSUDO'
whoami
ENDSUDO
} | sudo -S -i -u someone
I believe the following will work, if you only want to run whoami instead of several commands:
#!/usr/bin/env bash
read -s -p 'Password: ' password
ssh somewhere whoami
echo "$password" | ssh somewhere sudo -S -u someone whoami
The -S tells sudo to read the password from stdin.
If you want to run several commands with a here-document, see #xhienne's answer.

Bash: get output of sudo command on remote using SSH

I'm getting incredibly frustrated here. I simply want to run a sudo command on a remote SSH connection and perform operations on the results I get locally in my script. I've looked around for close to an hour now and not seen anything related to that issue.
When I do:
#!/usr/bin/env bash
OUT=$(ssh username#host "command" 2>&1 )
echo $OUT
Then, I get the expected output in OUT.
Now, when I try to do a sudo command:
#!/usr/bin/env bash
OUT=$(ssh username#host "sudo command" 2>&1 )
echo $OUT
I get "sudo: no tty present and no askpass program specified". Fair enough, I'll use ssh -t.
#!/usr/bin/env bash
OUT=$(ssh -t username#host "sudo command" 2>&1 )
echo $OUT
Then, nothing happens. It hangs, never asking for the sudo password in my terminal. Note that this happens whether I send a sudo command or not, the ssh -t hangs, period.
Alright, let's forget the variable for now and just issue the ssh -t command.
#!/usr/bin/env bash
ssh -t username#host "sudo command" 2>&1
Then, well, it works no problem.
So the issue is that ssh -t inside a variable just doesn't do anything, but I can't figure out why or how to make it work for the life of me. Anyone with a suggestion?
If your script is rather concise, you could consider this:
#!/usr/bin/env bash
ssh -t username#host "sudo command" 2>&1 \
| ( \
read output
# do something with $output, e.g.
echo "$output"
)
For more information, consider this: https://stackoverflow.com/a/15170225/10470287

tee not working with ssh running an external script

I'm trying to log everything happening during an ssh session while showing output on shell.
sshpass -p "password" ssh -tt -o ConnectTimeout=10 -oStrictHostKeyChecking=no username#"$terminal" 'bash -s' < libs/debug-mon.lib "$function" | grep -E '^INFO:|^WARNING:' || echo "WARNING: Terminal not reacheable or wrong IP" | tee -a libs/debug-monitor-logs
I'm not getting anything on the log libs/debug-monitor-logs file
Could you please help me to see where the issue is?
Thanks
looks like this only thing you will ever write into the log file is "WARNING: Terminal not reacheable or wrong IP"
try something like this
(command-that-might-fail || echo error message) | tee -a log-file
instead of
commant-that-might-fail || echo error message | tee -a log-file
(put the whole expression in brackets that you want to pipe into tee)

Update root crontab remotely for many systems by script

I am trying to update the crontab file of 1000+ systems using a for loop from jump host.
The below doesn't work.
echo -e 'pass365\!\n' | sudo -S echo 'hello' >> /var/spool/cron/root
-bash: /var/spool/cron/root: Permission denied
I do have (ALL) ALL in the sudoers file.
This is another solution;
echo 'pass365\!' | sudo -S bash -c 'echo "hello">> /var/spool/cron/root'
The below worked for me.
echo 'pass365\!' | sudo -S echo 'hello' | sudo -S tee -a /var/spool/cron/root > /dev/null
Problem 1: You are trying to send the password via echo to sudo.
Problem 2: You can't use shell redirection in a sudo command like that.
Between the two of these, consider setting up ssh public key authorization and doing
ssh root#host "echo 'hello' \>\> /var/spool/cron/root"
You may eventually get sudo working but it will be so much more pain than this.

Resources