SSH ask password once, reuse password until timeout finishes

How can I solve this problem? I have a bash script (under Ubuntu Server), doing several SSH connections, executes some remote transfers, like rsync multiple times.

My problem is, that I would like to avoid entering password multiple times. But I don't want to use SSH public key exchange, because if anybody has the key, will be able to connect the remote computer.

I would like the following:

  • SSH should ask password when I start the bash script
  • reuse password, so don't ask password again until timeout
  • when timeout is over, ask password again.

Something similar, how sudo is working, just with ssh.

Any idea how to solve this?

EDIT1:

I found a new SSH feature named ssh multiplexing. Maybe using this I can reach the goal I want.

https://unix.stackexchange.com/questions/50508/reusing-ssh-session-for-repeated-rsync-commands

Would this work?


Solution 1:

(Reposting my comment as an answer per request from klor).

It's not what you want to hear, but this is what key-based authentication is for. So long as you put a passphrase on your private key, it's no less secure than password authentication.

You can use ssh-agent to avoid needing to enter the passphrase every time, and the -t option to ssh-agent will give you the timeout behavior you're after.

# start a shell under ssh-agent with a 5-minute timeout for keys loaded with ssh-add
ssh-agent -t 300 /bin/bash

# add your key(s) to the agent; ssh-add will prompt for passphrase, if one is set
ssh-add

# do some stuff
ssh remote.server cat /some/file
rsync file1 file2 [email protected]:/some/directory

# after 300 seconds, timeout reached, run ssh-add again to re-add your keys
ssh-add

Your script will need some logic to determine when the timeout occurs. One way would be to run ssh and rsync with -o BatchMode=yes, which will prevent interactive authentication methods, so if the key is no longer usable, ssh will exit instead of prompting for a password. You can use the exit code to determine if you need to run ssh-add again; $? should be set to 255 in this case.

You'll still need to work out how to feed the passphrase to ssh-add, because it doesn't provide a way to accept it programmatically. Unless your script will prompt you to enter it by hand, you'll probably need to use expect for that part, and that will mean hard-coding the passphrase somewhere.

Solution 2:

It seems I found the perfect solution for my needs:

Reusing ssh session for repeated rsync commands

#!/bin/bash

# Create ssh-mux (SSH multiplex) dir only if not exists
[[ ! -d dir ]] || mkdir ~/.ssh/ssh-mux

apache_site_path_source="/var/www/source_site"
apache_site_path_target="/var/www/target_site"

# Solution: Start SSH multiplexing session (works fine)
# https://unix.stackexchange.com/questions/50508/reusing-ssh-session-for-repeated-rsync-commands
sudo ssh -nNf -o ControlMaster=yes -o ControlPath="~/.ssh/ssh-mux/%L-%r@%h:%p" [email protected]

sudo rsync -av --progress -e 'ssh -l root -p 22 -o "ControlPath=~/.ssh/ssh-mux/%L-%r@%h:%p"' 192.168.0.1:${apache_site_path_source}/. ${apache_site_path_target}/;
printf "\n\n\n\n\n\n"
sudo rsync -av --progress -e 'ssh -l root -p 22 -o "ControlPath=~/.ssh/ssh-mux/%L-%r@%h:%p"' 192.168.0.1:${apache_site_path_source}/. ${apache_site_path_target}/;
printf "\n\n\n\n\n\n"
sudo rsync -av --progress -e 'ssh -l root -p 22 -o "ControlPath=~/.ssh/ssh-mux/%L-%r@%h:%p"' 192.168.0.1:${apache_site_path_source}/. ${apache_site_path_target}/;
printf "\n\n\n\n\n\n"

# Finish SSH multiplexing session
sudo ssh -O exit -o ControlPath="~/.ssh/ssh-mux/%L-%r@%h:%p" [email protected]

This solution asks password only once, then doing rsync 3 times without asking password again. Each rsync reuses the SSH connection using SSH multiplexing.

Could be possible to change the SSH config, and store the SSH multiplexing settings, but using this solution there is no need to change the server config, the script works as is.

Solution 3:

If you're using a keyfile, you can use the AddKeyToAgent option (OpenSSH>=7.2).

ssh(1): Add an AddKeysToAgent client option which can be set to 'yes', 'no', 'ask', or 'confirm', and defaults to 'no'. When enabled, a private key that is used during authentication will be added to ssh-agent if it is running (with confirmation enabled if set to 'confirm').

So your script might look like this.

# make sure the ssh agent is running (may not be necessary on some systems)
eval "$(ssh-agent -s)"

# ssh commands.  only the first command needs AddKeysToAgent option
ssh -o AddKeysToAgent=yes user@host "echo hello"
ssh user@host "echo world"
...