114

I'm using Ubuntu 11.10 and ssh for connecting to many servers daily, so I put their parameters in the .ssh/config file like this:

Host Home
User netmoon
Port 22
HostName test.com

Is there a way to put passwords for each connection in this file, so that, when the server asks for the password, the terminal enters its password and sends it to the server?

I need this because sometimes I'm away from the PC and when I get back, type a password, and press Enter the terminal says CONNECTION CLOSED.

P.S. I don't want to use a public/private key pair.

Netmoon
  • 1,498

15 Answers15

58

Trading off security for convenience never ends well...

Could you use ssh-copy-id from the openssh-client package?

From man ssh-copy-id:

ssh-copy-id is a script that uses ssh to log into a remote machine and append the indicated identity file to that machine's ~/.ssh/authorized_keys file.

Elazar
  • 105
waltinator
  • 37,856
27

If you don't really want to use a public/private key pair, you can write an expect script to enter the password for you automatically depending on the destination address.

Edit: What I mean is that you can have a script that, on one hand, uses expect to enter the password for you and, on the other hand, reads the password for a given user and host from a configuration file. For example, the following python script will work for the sunny day scenario:

#!/usr/bin/python                                                                                                                        
import argparse
from ConfigParser import ConfigParser
import pexpect

def main(args):
    url = args.url
    user, host = url.split('@', 1)

    cfg_file = 'ssh.cfg'
    cfg = ConfigParser()
    cfg.read(cfg_file)
    passwd = cfg.get(user, host)

    child = pexpect.spawn('ssh {0}'.format(url))
    child.expect('password:')
    child.sendline(passwd)
    child.interact()

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Run ssh through pexpect')
    parser.add_argument('url')
    args = parser.parse_args()
    main(args)

and the configuration file format would be as follows:

[user_1]
host1 = passwd_1
host2 = passwd_2

[user_2]
host1 = passwd_1
host2 = passwd_2

Note: As explained, the python script would need to be much more complex to handle all the possible errors and question messages from ssh and all the possible URLs (in the example it's assumed that it will be something like user@host, but the user part isn't used most of the times), but the basic idea would still be the same. Regarding the configuration file, you may use a different configuration file or use .ssh/config and write your own code to parse that file and get the password for a given user and host.

jcollado
  • 9,868
25

How about ProxyCommand:

Host Home-raw
    HostName test.com
Host Home
   User netmoon
   Port 22
   ProxyCommand sshpass -pmypass ssh netmoon@%h-raw nc localhost %p

You can use ssh -W instead of nc as well:

ProxyCommand sshpass -pmypass ssh netmoon@%h-raw -W localhost:%p
21

There also is sshpass program for that. How to use: sshpass -p MyPa55word ssh me@myservor.com

igor
  • 319
16

No. This is not possible I'm afraid.

The only real alternative is to use private keys but you've said you don't want to (why not?).

Caesium
  • 16,207
  • 4
  • 42
  • 48
9

You can create a simple ssh script replacement in /usr/local/bin:

#!/bin/bash

host=$1
password=`awk "/#Password/ && inhost { print \\\$2 } /Host/ { inhost=0 } /Host $host/ { inhost=1 }" ~/.ssh/config`

if [[ -z "$password" ]]; then
  /usr/bin/ssh $*
else
  sshpass -p $password /usr/bin/ssh $*
fi

And then in your ~/.ssh/config file you can use

Host foohost
    User baruser
    #Password foobarpassword
5

Answering the question you asked, no it's not possible to configure a default password in an ssh config file.

But if indeed, as you say, it's "because sometimes I stand away from the PC and when I go back, type a password and press Enter the terminal says CONNECTION CLOSED", then why not prevent closing the session instead? SSH can keep connections alive for you.

Host Home
  User netmoon
  Port 22
  HostName test.com
  ServerAliveInterval 300
  ServerAliveCountMax 2
Eliah Kagan
  • 119,640
3

Inspired by @Arek Burdach's answer and others' wrapper, I've wrote a wrapper that should be more robust which facilitated ssh own command parsing.

UPDATE 2021-04-26: Fixed wrapper when a host only matches the prefix (e.g. Host is none)

Here's how it work:

  • We first dry-run the ssh with -v and a non-existent ProxyCommand, so it wouldn't make any network connection and exit at once.
  • Then we extract the line like debug1: /home/misty/.ssh/config line 42: Applying options for XXXXXX. But the ssh output the errlog with \r, so we replaced them before passing into grep.

According to my test, ssh will only recognize the first -o ProxyCommand=XXX in commandline, even if there's second ProxyCommand option in the cmdline, or there's ProxyCommand in ~/.ssh/config, so our method will be very very stable ;)

For ssh

#!/usr/bin/env bash
ORISSH=/usr/bin/ssh
ssh_dryrun=$($ORISSH -v -o "ProxyCommand=FAKE_PROXY_STUB %h %p" "$@" 2>&1 | sed -e 's/\r/\n/g')
host=$( grep -oP 'Applying options for \K(.*?)$' <<< $ssh_dryrun | head -n 1 )

if [[ $host == "*" ]]; then password='' else password=awk &quot;/#Password/ &amp;&amp; inhost { print \\\$2 } /^Host/ { inhost=0 } /Host $host$/ { inhost=1 }&quot; ~/.ssh/config fi

if [[ -z "$password" ]]; then $ORISSH "$@" else sshpass -p $password $ORISSH "$@" fi

For scp:

#!/usr/bin/env bash
ORISCP=/usr/bin/scp
scp_dryrun=$($ORISCP -v -o "ProxyCommand=proxyhost %h %p" "$@" 2>&1 | sed -e 's/\r/\n/g')
host=$( grep -oP 'Applying options for \K(.*?)$' <<< $scp_dryrun | head -n 1 )

if [[ $host == "*" ]]; then password="" else password=awk &quot;/#Password/ &amp;&amp; inhost { print \\\$2 } /^Host/ { inhost=0 } /Host $host$/ { inhost=1 }&quot; ~/.ssh/config fi

if [[ -z "$password" ]]; then $ORISCP "$@" else sshpass -p $password $ORISCP "$@" fi

Misty
  • 131
3

I use an application from VanDyke Software called SecureCRT.

http://www.vandyke.com/products/securecrt/

It is not free, but very reasonably priced. I have used it for years (running on Windows, or using Wine) for remote access, terminal emulation, and (dispersed) network management. They finally released a native Linux version of this at the beginning of 2011.

It has support for complex login settings (or scripts), stored passwords (or certificates), tabbed multiple sessions, etc.

At startup you can choose which remote target (and protocol) from a structured list (tree view) of stored remote (or local) machines, or just create a connection (which is then stored).

I have found it particularly useful for remote sites with advanced authentication, non-standard ports, or firewall-access negotiation.

If you are doing remote access a lot (part of your main role), then this application will justify its expense in the first month of use.

david6
  • 14,528
  • 5
  • 38
  • 46
2

This is a bash function that runs a single command, awk to parse the config file and populate a PASSWORD variable, then runs the sshpass command. The advantage of using it as a function is there wont be any extra processes left running when ssh is run. You can specify the password directly inside the ssh config. Or you can grab a password from an environmental variable with the variable being defined in the ssh config so you dont have to expose your "more secret" passwords inside the ssh config file itself.

# In your .bash_profile
function ssh(){
    host=$1;
    unset PASSWORD
    unset PASSVAR
    eval $(awk "/^#[Pp][aA][sS][sS][vV][aA][rR] / && inhost { printf \"PASSVAR=%s\",\$2; exit 1; } /^ *#[Pp][aA][sS][sS][wW][oO][rR][dD] / && inhost { printf \"PASSWORD=%s\",\$2; } /^[[:blank:]]*$/ { blankline=1; next } /^#?[Hh][oO][sS][tT] / && inhost && blankline { inhost=0; exit 1; } /^[Hh][oO][sS][tT] $host\$/ { blankline=0; inhost=1 }" ~/.ssh/config.d/*)
    if [[ -z "$PASSWORD" ]] && [[ -z "$PASSVAR" ]]; then
        /usr/bin/ssh -q $* 2>/dev/null
    else
       if [[ -n "$PASSVAR" ]]; then
          # Get password from an ENV variable specified in ssh config
          PASSWORD=$(TMP=${!PASSVAR-*};echo ${TMP##*-})
       fi
       /usr/local/bin/sshpass -p"$PASSWORD" /usr/bin/ssh -q $* 2>/dev/null
    fi
}
# and setup your passwords (perhaps in .bashrc instead...)
MYPASS_ENVVAR=SomePassword
MYPASSWD_FROM_FILE=$(</home/me/.passwd_in_file)

Then a ~/.ssh/config section looks like this:

Host MyHostname
 Port 22
 Hostname 2.1.2.2
 User merrydan
 #Passvar MYPASS_ENVVAR
 #Password Some!Password

If a #Passvar exists in the config section this overrides the #Password.
$MYPASS_ENVVAR is the environment variable holding your password.

And a similar function to handle most scp scenarios

function scp(){
    host=$(echo $* | perl -pe 's/^.*?([A-Za-z-1-9-]+):.*?$/\1/;');
    unset PASSWORD
    unset PASSVAR
eval $(awk &quot;/^#[Pp]assvar / &amp;&amp; inhost { printf \&quot;PASSVAR=%s\&quot;,\$2; exit 1; } /^ *#[Pp]assword / &amp;&amp; inhost { printf \&quot;PASSWORD=%s\&quot;,\$2; } /^#?[Hh][oO][sS][tT] / &amp;&amp; inhost { inhost=0; exit 1; } /^[Hh][oO][sS][tT] $host\$/ { inhost=1 }&quot; ~/.ssh/config.d/*)
if [[ -z &quot;$PASSWORD&quot; ]] &amp;&amp; [[ -z &quot;$PASSVAR&quot; ]]; then
    #echo /usr/bin/scp -3 $*
    /usr/bin/scp -3 $* || true
    #echo &quot;SSH Exit Code $?&quot;
else
   if [[ -n &quot;$PASSVAR&quot; ]]; then
      #PASSWORD=`echo ${!PASSVAR}`
      PASSWORD=$(TMP=${!PASSVAR-*};echo ${TMP##*-})
   fi
   #echo /usr/local/bin/sshpass -p&quot;$PASSWORD&quot; /usr/bin/scp -3 $*
   /usr/bin/sshpass -p&quot;$PASSWORD&quot; /usr/bin/scp -3 $* || true
   #echo &quot;SSHPass Exit Code $?&quot;
fi

}

0

If you don't have direct access to key-pair, you could encrypt password on your local machine.

The way to do it is encrypt your password using key in addition to @Eric Woodruff 's ProxyCommand.

A way to combine is using pipe:

openssl rsautl -decrypt -inkey /path/to/decrypt_key -in /path/to/encrypted_password  | sshpass ssh real-destination -tt

where

Host real-destination
    Hostname test.com
    User netmoon
0

There is a slight variant of a way described in the blog on how to use sshpass which can be found here. Given that you have a gpg encrypted password (how ot do this is described in the blog) file you could do something like this:

 sshpass -p $(echo $(gpg -d -q .sshpasswd.gpg)) ssh your_desination.xyz

and simply save that command as an alias in your .bashrc .

If you want to tunnel through that connection you could do something like

 Host actual_dest
      Hostname actual.dest.xyz
      User username
      ProxyCommand sshpass -p $(echo $(gpg -d -q ~/.sshpasswd.gpg)) \ 
                   ssh your_destination.xyz nc %h %p
ricffb
  • 1
0

Because I cannot find documentation on how to implement key-based authentication for a Windows ssh server I am forced to use password authentication to access files and directories hosted by Windows.

Below are working Python3 versions of the ssh and scp wrapper programs in the answer by @IngoKarkat. This assumes that you store the password in ~/.ssh/config just as he suggests:

# Allow specifying passwords for Host entries, to be parsed by ssh-wrapper and scp-wrapper.
IgnoreUnknown Password

Host foohost User baruser Password foobarpassword

Before running these programs first install the sshconf Python library:

$ pip3 install sshconf

These programs first attempt to find a password, and if none is available they fall back to key-based authentication.

Enhanced ssh

#!/usr/bin/env python3

from future import print_function import shutil, subprocess, sys from sshconf import read_ssh_config from os.path import expanduser

c: str = read_ssh_config(expanduser("~/.ssh/config"))

if len(sys.argv) == 1: print(f"Usage: {sys.argv[0]} host [command]") sys.exit(1)

if shutil.which("sshpass") == None: print("Please install sshpass and retry.") sys.exit(2)

host: str = sys.argv[1] try: password: str = c.host(host)["password"] command = [ "sshpass", f"-p{password}", "ssh", host ] + sys.argv[2:] except KeyError: command = [ "ssh", host ] + sys.argv[2:]

subprocess.run(command)

Enhanced scp

#!/usr/bin/env python3

Python3 version of https://askubuntu.com/a/878335/58760

See https://github.com/sorend/sshconf

pip3 install sshconf

from future import print_function import shutil, subprocess, sys from sshconf import read_ssh_config from os.path import expanduser

c: str = read_ssh_config(expanduser("~/.ssh/config"))

if len(sys.argv) < 3: print(f"""Usage: {sys.argv[0]} /dir1 host2:/dir2 {sys.argv[0]} host1:/dir1 /dir2""") sys.exit(1)

if shutil.which("sshpass") == None: print("Please install sshpass and retry.") sys.exit(2)

try: host = sys.argv[1].rsplit(":", 1)[0] password: str = c.host(host)["password"] command = [ "sshpass", f"-p{password}" ] except KeyError: try: host = sys.argv[2].rsplit(":", 1)[0] password: str = c.host(host)["password"] command = [ "sshpass", f"-p{password}" ] except KeyError: command = [ ]

command = command + [ "scp" ] + sys.argv[1:]

subprocess.run(command)

Saving and Running

I stored the programs in the ~/.local/bin/ directory, which is the recommended Ubuntu directory for user scripts.

To use the programs, first make them executable. Assuming you stored them in ~/.local/bin/sshPass and ~/.local/bin/scpPass, type the following to make them executable:

$ chmod a+x ~/.local/bin/sshPass
$ chmod a+x ~/.local/bin/scpPass

You can run them like this:

$ ~/.local/bin/sshPass hostName ls
$ ~/.local/bin/scpPass hostName:fromFile toFile
$ ~/.local/bin/scpPass fromFile hostName:toFile

You could also add this to ~/.bash_aliases, for *nix distros that support that, or your startup bash script:

alias ssh=~/.local/bin/sshPass
alias scp=~/.local/bin/scpPass
0

Here's my elaborate variation on @ArekBurdach's answer. It offers the following extensions:

  • the host can be anywhere in the ssh command-line; i.e. it also supports the ssh <args> <host> <commands> syntax
  • does not hard-code the path to ssh
  • more robust parsing of ssh_config
  • Bonus: wrapper for scp, too

ssh-wrapper

#!/bin/bash

password=$(awk ' BEGIN { # Collect the SSH arguments as keys of a dictionary, so that we can easily # check for inclusion. for (i = 2; i < ARGC; i++) { sshArgs[ARGV[i]] = 1 }

# Only process the first argument; all others are the command-line arguments
# given to ssh.
ARGC = 2

} $1 == "Password" && inhost { print $2 } /^\s*Host\s/ { if ($2 in sshArgs) inhost=1 else inhost=0 } ' ~/.ssh/config "$@")

if [ "$password" ]; then sshpass -p "$password" ssh "$@" else exec ssh "$@" fi

scp-wrapper

#!/bin/bash

password=$(awk ' BEGIN { # Collect the SCP arguments as keys of a dictionary, so that we can easily # check for inclusion. for (i = 2; i < ARGC; i++) { colonIdx = index(ARGV[i], ":") if (colonIdx > 0) { scpArgs[substr(ARGV[i], 1, colonIdx - 1)] = 1 } }

# Only process the first argument; all others are the command-line arguments
# given to scp.
ARGC = 2

} $1 == "Password" && inhost { print $2 } /^\s*Host\s/ { if ($2 in scpArgs) inhost=1 else inhost=0 } ' ~/.ssh/config "$@")

if [ "$password" ]; then sshpass -p "$password" scp "$@" else exec scp "$@" fi

Installation

Define aliases in your ~/.bashrc:

alias ssh=ssh-wrapper
alias scp=scp-wrapper

Configuration

With the IgnoreUnknown directive, ssh does not complain about a newly introduced Password directive, so (in contrast to @ArekBurdach's answer), we can make this appear as a "real" configuration. If you don't like this, it's trivial to change the script back to the commented-out one.

# Allow specifying passwords for Host entries, to be parsed by ssh-wrapper.
IgnoreUnknown Password

Host foohost User baruser Password foobarpassword

0

The answer of @BrunoPereira to this question shows an alternative method to connect without explicitly entering a password and avoiding ssh keys.

You could create a script, an alias or a function in your ~/.bashrc to quickly execute that command.

Obviously, there are security considerations you should take into account with this approach.

enzotib
  • 96,093