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?

  • possible duplicate: serverfault.com/questions/241588/… – Alex Mar 31 '17 at 16:12
  • 1
    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. – James Sneeringer Mar 31 '17 at 17:30
  • @JamesSneeringer I can accept your comment as solution, if you repost it as an answer. – klor Mar 31 '17 at 18:20
  • use kerberos, set ticket lifetime. – Jacob Evans Mar 31 '17 at 21:37
  • Checked kerberos, but seems to be too difficult and seems to be developed for enterprise use. – klor Apr 1 '17 at 7:38
3

(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 klor@remote.server:/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.

  • 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 '17 at 19:06
  • 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. – James Sneeringer Mar 31 '17 at 19:32
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.

  • 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 '17 at 19:06
  • A manual call to auto_init_ssh_agent will allow rsync to work like that. – Andrew Domaszek Mar 31 '17 at 19:50
  • I just want to start bash script, enter password, and leave it working until timeout asks password again. – klor Apr 1 '17 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. – Andrew Domaszek Apr 1 '17 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 '17 at 13:38
0

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" root@192.168.0.1

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" root@192.168.0.1

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

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
  • Your solution needs hard coded password into bash script, which is not acceptable. – klor Mar 31 '17 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 – Diego Velez Mar 31 '17 at 18:24
  • Yes, and variable will be stored in memory unencrypted. – klor Mar 31 '17 at 18:57
  • well you never said you wanted encrypted password, but anyways you can use unset before exiting the script – Diego Velez Mar 31 '17 at 19:10
  • Well, once I use SSH, security is a requirement. – klor Apr 1 '17 at 7:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.