Can I automatically login to ssh using passwords from OS X keychain?
I need to login to an ssh server which doesn't support key based authentication. And I don't want to type the passwords every time.
I am using OS X Lion (10.7.2). I have added the passwords to the OS X keychain[1]. Now I can retrieve the password automatically from the keychain using /usr/bin/security
, however I can't find a way to send this password to the ssh prompt.
I also tried sshpass
. However when I try to run it ssh exits with the following error:
ssh_askpass: exec(/usr/libexec/ssh-askpass): No such file or directory
Permission denied, please try again.
ssh_askpass: exec(/usr/libexec/ssh-askpass): No such file or directory
Permission denied, please try again.
ssh_askpass: exec(/usr/libexec/ssh-askpass): No such file or directory
Permission denied (publickey,password).
Is there anyway I can login to this server without having to enter the password every time?
Notes
- The scheme I use in keychain looks like this
- Kind: Internet password
- Account: username
- Where: ssh://server-name
Non-interactive SSH sessions
If you don't need to have an interactive session on the remote server, you can execute ssh
in an environment without tty
, e.g. as part of a Run Shell Script action in Automator.
You need to create a program that when called prints the password to standard out, e.g. the following bash script you need to make executable using chmod +x pwd.sh
:
#!/usr/bin/env bash
echo "password"
Then, set the SSH_ASKPASS
environment variable to the path to this program, and then run ssh
in the Automator action, like this:
export SSH_ASKPASS=/Users/danielbeck/pwd.sh
ssh user@hostname ls
When there is no tty
, but SSH_ASKPASS
and DISPLAY
(for X11, set by default) are set, SSH executes the program specified by SSH_ASKPASS
and uses its output as password. This is intended to be used in graphical environments, so that a window can pop up asking for your password. In this case, we just skipped the window, returning the password from our program. You can use security
to read from your keychain instead, like this:
#!/usr/bin/env bash
security find-generic-password -l password-item-label -g 2>&1 1>/dev/null | cut -d'"' -f2
ls
(on the ssh
command line) is the command executed when ssh
has logged in, and its output is printed in Automator. You can, of course, redirect it to a file to log output of the program you start.
Interactive SSH sessions using sshpass
I downloaded, compiled and installed sshpass
and it worked perfectly. Here's what I did:
- Get the Apple developer tools
- Download and open
sshpass-1.05.tar.gz
- Open a shell to the directory
sshpass-1.05
- Run
./configure
- Run
make
- Run
make install
(you might needsudo
for it)
Now the program is installed to /usr/local/bin/sshpass
. Execute using a line like the following:
sshpass -pYourPassword ssh username@hostname
You can read the password from security
just before doing that, and use it like this:
SSHPASSWORD=$( security find-generic-password -l password-item-label -g 2>&1 1>/dev/null | cut -d'"' -f2 )
sshpass -p"$SSHPASSWORD" ssh username@hostname
Wrap this in a shell function and you can just type e.g. ssh-yourhostname
to connect, having it retrieve and enter the password automatically.
I found a solution (thanks to Daniel Beck for providing the key info needed for this). Note that I have only tested this with OS X Lion 10.7.2. If this doesn't work for you, try Daniel's solution.
First we need to set the SSH_ASKPASS
environment variable -- its value should be the path to a program which prints the password to standard output. To get the password from the keychain, this is what it needs to look like (I call it get-ssh-password.sh
):
#!/bin/bash
/usr/bin/security find-internet-password -a "$SSH_PASSWORD_USER" -s "$SSH_PASSWORD_HOSTNAME" -r "ssh " -g 2>&1 1>/dev/null | cut -d\" -f2
A couple of points to note:
This assumes that you have stored the password in the keychain in the way I have described in the question
The program given in
SSH_ASKPASS
will be called without any arguments; so we use environment variables to pass the user and hostname to it.
Now we can set SSH_PASSWORD_USER
and SSH_PASSWORD_HOSTNAME
and run sshpass
to login to our server.
I created another script, ssh-kcpass
, to do this:
#!/bin/bash
export SSH_ASKPASS=~/bin/get-ssh-password.sh
export SSH_PASSWORD_USER=$(echo "$1" | cut -d@ -f1)
export SSH_PASSWORD_HOSTNAME=$(echo "$1" | cut -d@ -f2)
sshpass ssh "$1"
To login to the ssh server without typing any password, you just need to run ssh-kcpass user@hostname
.