can ansible ask for passwords automatically and only if necessary - ansible

So ansible-playbook has --ask-pass and --ask-sudo-pass. Is there a way to get ansible to try ssh without a password first and then only prompt for a password if passwordless login fails? Similarly, can ansible try sudo without a password first and then only prompt if that doesn't work?
FYI I have a little shell function to try to figure this out by trial and error, but I'm hoping something like this is baked into ansible.
get_ansible_auth_args() {
local base_check="ansible all --one-line --inventory-file=deploy/hosts/localhost.yml --args=/bin/true --sudo"
${base_check}
if [[ $? -eq 0 ]]; then
return;
fi
local args="--ask-pass"
${base_check} ${args}
if [[ $? -eq 0 ]]; then
export ANSIBLE_AUTH_ARGS="${args}"
return;
fi
local args="--ask-pass --ask-sudo-pass"
${base_check} ${args}
if [[ $? -eq 0 ]]; then
export ANSIBLE_AUTH_ARGS="${args}"
return;
fi
}

If you set ask_pass and ssh_args as I show below then ansible should ask you for password at the beginning once and use that password whenever public key auth doesn't work.
[defaults]
ask_pass = True
[ssh_connection]
ssh_args = -o PubkeyAuthentication=yes -o PasswordAuthentication=yes -o ControlMaster=auto -o ControlPersist=60s
This is still not the full solution: Catch being (AFAIK) ansible uses sshpass, so the password it collected from your at the start would be the only password it would use and it won't work if you have different passwords for different machines. :-)
Only other hack I can think of is to replace /usr/bin/ssh (or whichever is your openssh's ssh used by ansible) with a script of your own that wraps the logic of reading password from some flat file if needed, I suspect ansible would hide the tty so your script won't be able to 'read' the password from stdin.

Related

What's the best way to send multiple commands via ssh whilst running a script?

I'm making a script that occasionally sends commands to another machine over ssh. At the moment, im just calling this one function that opens up a new shell for each command it sends like so:
#!/bin/bash
port='22'
user='user'
host='hostname'
send_ssh() {
ssh -oBatchMode=yes -oConnectTimeout=5 -p "$1" -tq "$2"#"$3" "$4" || exit 1
}
send_ssh "$port" "$user" "$host" true
# it worked so do some stuff locally blah blah
send_ssh "$port" "$user" "$host" anothercommand
# rest of script
I've looked at keeping a tunnel open in the background and / or using a control socket so i can speed things up without having to open a new connection for each command but cant work out if and wether it's worth doing that in this case.
Setting up a control socket is so easy that I would argue it is absolutely worth doing, even with only two calls to send_ssh.
send_ssh() {
ssh -o ControlMaster=auto -o ControlPersist=10 -oBatchMode=yes -oConnectTimeout=5 -p "$1" -tq "$2"#"$3" "$4" || exit 1
}
ControlMaster=auto means that an existing connection will be used if available, otherwise one will be opened for you.
The setting ControlPersist=10 means that the connection to the remote host will remain open for 10 seconds after the client exists, you can adjust this as desired. You can set it to 0 or yes to keep it open permanently, in which case you'll want to make sure something like
ssh -o exit -p "$1" "$2#$3"
executes before your script exits to close the master connection.

bash script which can ssh to a remote machine and execute commands, throws error when password is incorrect

I'm trying a bash script where i'm taking an argument of a file which has the IP address. I'm using sshpass, but with this i'm not able to know if ssh login was successful or not. Is there a way to check this ?
Please suggest if not sshpass, do i need to use any other cmd, to do remote login and execute cmds ?
Here is the snippet of the code :
#!/bin/bash
filename="$1"
while read -r line; do
sshpass -p 'test' ssh -o StrictHostKeyChecking=no test#$line 'df -h'
done < "$filename"
Have tried the suggested way to check $? value (if its incorrect password, $? value will be 5, however with valid or invalid password, shell script is not echoing 'wrong password', its always echoing "Can ssh to box- Password is correct" as per the following code :
#!/bin/bash
filename="$1"
while read -r line; do
sshpass -p 'test' ssh -o StrictHostKeyChecking=no test#$line 'df -h'
if [ $? -eq 5]
then
echo "Wrong password"
else
echo "Can ssh to box- Password is correct"
fi
done < "$filename"
My Requirement is to ssh to the remote box and execute commands. And in case, ssh fails i.e password is invalid, it need to print that password is invalid.
Use return value from sshpass.
According to man sshpass:
RETURN VALUES
As with any other program, sshpass returns 0 on success. In case of failure, the following return codes are used:
5 Invalid/incorrect password
After running sshpass, in bash return value from command is stored in $? variable.
Proof:
devilan#localhost:~ $ sshpass -p 'test' ssh smurf#localhost
devilan#localhost:~ $ echo $?
5
Sugested usage:
sshpass -p 'test' ssh smurf#localhost
if [ $? -eq 5 ]
then
echo "Wrong password"
else
echo "Something else"
fi
Space was missing after 5, and thus if condition wasn't getting evaluated successfully.
Here is the modified code which works :
filename="$1"
while read -r line; do
sshpass -p 'test' ssh -o StrictHostKeyChecking=no test#$line 'df -h'
if [ $? -eq 5 ]
then
echo "Wrong password"
else
echo "Can ssh to box- Password is correct"
fi
done < "$filename"

How to check the SSH login status of routers in bash script with password prompts

I am running a task where i need to check the SSH login status on 400 remote routers. I have made scripts using expect in bash which SSH the remote routers and run some commands over it. However, there are some routers that are not responding to SSH. I am using if statement to avoid those routers which are failing on SSH. Sample code to check the status on remote router works only if we have password less entry or the private key saved. Could you please help how can I check the SSH status on the remote routers?
If I get the password prompt while doing SSH to the router, I can say that the server is able to SSH the router. There is no need to supply password to it.
#!/bin/bash
ssh -q -o BatchMode=yes -o ConnectTimeout=7 username#IP exit
echo $?
if [ $? -ne 0 ]
then
# Do stuff here if example.com SSH is down
echo "Can not connect to the device"
fi
Well,
If you are using expect package then there is timeout option there as well.
Else your shell code above is correct way of doing it except just a few corrections:
#!/bin/bash
ssh -q -o BatchMode=yes -o ConnectTimeout=7 username#IP date
ret=$?
echo $ret
if [ $ret -ne 0 ]
then
# Do stuff here if example.com SSH is down
echo "Can not connect to the device"
fi
You can see, we are assigning $? immediately to a var. If you don't, then $? will contain the return value of echo $? command which will be always 0. Hence giving you true for all ssh.
Also I suggest to run some other command rather than exit with ssh.
Hope this helps
===Edited====>>>
well since you don't have passwordless ssh enabled. You can try to telnet to port 22, if 22 port is open then it will show connected and if its not open then it won't you can grep on it.
Here is the modified code: (Provided that ssh is running on 22 port otherwise change the port in code.)
#!/bin/bash
echo "" | telnet $IP 22 | grep "Connected"
ret=$?
echo $ret
if [ $ret -ne 0 ]
then
# Do stuff here if example.com SSH is down
echo "Can not connect to the device"
fi

Try to connect via script to multiple servers

I am trying to connect to multiple servers from file (servers.txt --> something around 300 IP add) and some server is RHEL5, some RHEL7 (so I must use a diff command).
I can connect to multiple server, its OK, but I can't continue with some condition: like if you don't know one command use another command.
#!/bin/bash
for host in $(cat servers.txt); do
ssh -q -o StrictHostKeyChecking=no root#$host
#when I try to continue with "if" -> of course I am logout from servers
I agree with #rkosegi that this can be achieved an Ansible ad-hoc command, but you'd have to convert the list of servers to an inventory - a very simple task.
At the bash prompt, I think I understand what you want. You want to try multiple commands via each ssh command. So let's assume you want to check the version of the redhat-release package and take different actions from that:
while read HOST; do
ssh -q -o StrictHostKeyChecking=no root#$HOST '
VERSION="`rpm -q --queryformat "%{VERSION}" redhat-release`"
if [[ $VERSION == 5* ]]; then # RHEL5
echo this is a rhel5
elif [[ $VERSION == 7* ]]; then # RHEL7
echo this is a rhel7
else
echo this is neither a rhel5 or rhel7
fi
'
done <servers.txt
Of course, the script can be written on one line, but I thought I'd format it nicer here for increased readability.
Note: The post being tagged with bash, the above command also uses [[ tests which are specific to bash and won't work on some other shells.

How to call ssh so it will only use identity file

My SSH server uses both password and identity file authentication. I don't want to change this behaviour.
I want to check if $THE_IDENTITY file is known by the server('s user) or not.
That's why I use this code:
echo "Check if server knows the SSH identity:"
if [ "$(ssh user#host -i ${SSH_ID_FILE} echo 'hello')" == 'hello' ]; then
echo "Server already knows me"
else
echo "Registering SSH ID Key to the server..."
ssh-copy-id -i $SSH_ID_FILE "user#host"
fi
But, the problem is, inside the "if" statement, if server does not know ID file, it asks for password, that's why my code works wrong.
How can I change my ssh line to make it exit if it fails with id file?
the following may do the trick:
ssh user#host -o NumberOfPasswordPrompts=0 -i .....
There's a keyword option to tell ssh not to use password authentication:
ssh user#host -o PasswordAuthentication=no ...
On Unix systems, details of all the keyword options can be found by:
man ssh_config

Resources