3

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?

4
  • possible duplicate: serverfault.com/questions/241588/…
    – Alex
    Mar 31, 2017 at 16:12
  • 3
    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. Mar 31, 2017 at 17:30
  • use kerberos, set ticket lifetime. Mar 31, 2017 at 21:37
  • Checked kerberos, but seems to be too difficult and seems to be developed for enterprise use.
    – klor
    Apr 1, 2017 at 7:38

5 Answers 5

6

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.

2
  • I have one doubt about ssh-add. Is it possible to start bash, enter password, then rsync..., rsync..., rsync... without entering password (within the timeout period)?
    – klor
    Mar 31, 2017 at 19:06
  • 1
    Yes, that's how it works. When ssh-agent starts, it sets a couple environment variables that ssh knows to look for (and rsync will leverage ssh by default). ssh-add tells ssh-agent to load your private key into memory, so when ssh checks with ssh-agent, it will find a usable key. Once the timeout is reached, ssh-agent removes the key from memory. Mar 31, 2017 at 19:32
3

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.

1

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"
...
0

Implementation of James Sneeringer's comment as a profile script.

# This script must be sourced to be useful. For example, if you name this script 
# ~/.bash_autossh, at the end of .bashrc, source $HOME/.bash_autossh
# Tested in bash & zsh
# MIT license, if you need a license.

# An absolute path to a private key:
AUTOLOADSSHID=$HOME/.ssh/id_ecdsa
# Timeout is in seconds, optional:
SSHID_TIMEOUT=60

auto_init_ssh_agent() {
  if [ "${SSH_AGENT_PID}x" = "x" ] || \
     [ "${SSH_AUTH_SOCK}x" = "x" ] || \
     ps -p "${SSH_AGENT_PID}" >& /dev/null || \
     [ ! -e "${SSH_AUTH_SOCK}" ]; then
    # There are problems with the agent, initialize a new agent.
    # Agents started this way should be manually stopped with ssh-agent -k
    source <(ssh-agent -s)
  fi
  if ! ssh-add -l | grep "${AUTOLOADSSHID}" >/dev/null; then
    # The autoload key is not present, try to load it.
    SSH_ADDTL_ARGS=()
    if [ "${SSHID_TIMEOUT}x" != "x" ]; then
      SSH_ADDTL_ARGS+=( -t "${SSHID_TIMEOUT}" )
    fi
    # This may ask for a password, as appropriate
    ssh-add "${SSH_ADDTL_ARGS[@]}" "${AUTOLOADSSHID}"
    unset SSH_ADDTL_ARGS
  fi
}

_autossh() {
  args=( "$@" )
  auto_init_ssh_agent
  ssh "${args[@]}"
}

alias autossh=_autossh

Then you can run the command autossh myserver and it will auto-initialize an agent if one isn't available. The alias is to prevent accidentally calling an interactive function from a script.

Problematically, on systems that don't automatically start an agent with the WM session, this may litter your machine with ssh-agent processes, you may need to ssh-agent -k to end it, or killall ssh-agent. Some additional scripting may be required if you want to share a single ssh-agent across an entire login session or across multiple process sessions.

6
  • I have one doubt. Is it possible to start bash, enter password, then rsync..., rsync..., rsync... without entering password (within the timeout period)?
    – klor
    Mar 31, 2017 at 19:06
  • A manual call to auto_init_ssh_agent will allow rsync to work like that. Mar 31, 2017 at 19:50
  • I just want to start bash script, enter password, and leave it working until timeout asks password again.
    – klor
    Apr 1, 2017 at 7:22
  • You'd have to replace the ssh program for that. The ssh binary does not provide that functionality and it is called by rsync, unless you specify a different rsh transport. Which, I suppose you could do by writing a script and having it found before /usr/bin/ssh. Apr 1, 2017 at 10:33
  • I found a new SSH feature named ssh multiplexing. Maybe using this I can reach the goal I want.
    – klor
    Apr 1, 2017 at 13:38
-1

I'd normally tell you to try expect, but in this case I think it's beter to use sshpass, it is very easy to install and to use, here I post some use cases

sshpass -p<pass> ssh <args> sshpass -pfoobar ssh -o StrictHostKeyChecking=no user@host command_to_run

have fun :)

EDIT 1

on a script

#!/bin/bash
read -p "give me the password" pass
sshpass -p"$pass" ssh -o StrictHostKeyChecking=no user@host command_to_run
7
  • 1
    Your solution needs hard coded password into bash script, which is not acceptable.
    – klor
    Mar 31, 2017 at 18:22
  • you can declare a variable and make it ask it to you, you can use read -p "What is the password: " pass Mar 31, 2017 at 18:24
  • 1
    Yes, and variable will be stored in memory unencrypted.
    – klor
    Mar 31, 2017 at 18:57
  • well you never said you wanted encrypted password, but anyways you can use unset before exiting the script Mar 31, 2017 at 19:10
  • Well, once I use SSH, security is a requirement.
    – klor
    Apr 1, 2017 at 7:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .