SSH Again

I’ve written a few articles now regarding my SSH setup and my .bashrc and .bash_profile files. I think I finally arrived at a configuration that’s good, and I’d like to share my findings.

This is the complete content of my ~/.bash_profile:

# if a directory exists, add it to $PATH
__add_path_head() {
    if [ -d "$1" ]; then
        if [ -n "${PATH}" ]; then
            PATH="$1:${PATH}"
        else
            PATH="$1"
        fi
    fi
}

export PATH
__add_path_head "${HOME}/local/bin"
__add_path_head "${HOME}/local/sbin"
__add_path_head "${HOME}/opt/arcanist/bin"

export GOPATH="${HOME}/gocode"
if [ ! -d "${GOPATH}/bin" ]; then
    mkdir -p "${GOPATH}/bin"
fi
__add_path_head "${GOPATH}/bin"

# Try to find an already running ssh-agent process
foundagent=0
for agentsock in $(find /tmp/ssh-* -name 'agent.*' -type s 2>/dev/null); do
    export SSH_AUTH_SOCK="${agentsock}"
    ssh-add -l &>/dev/null
    # 0 means the agent had keys, 1 means the agent is properly configured but
    # has no keys, 2 would mean that the SSH_AUTH_SOCK is inavlid
    if [ $? -lt 2 ]; then
        foundagent=1
        break
    fi
done

# If no ssh-agent process was found, create a new one
if [ "${foundagent}" -eq 0 ]; then
    source <(ssh-agent)
fi

# source .bashrc if we're on a tty
test -t 0 && source ~/.bashrc

The relevant points are:

The code that I have for detecting an SSH agent is not comprehensive; it assumes that you’re using the actual ssh-agent program that puts agent sockets in a predictable place. If you want something that handles more edge cases (e.g. OS X or the GNOME keyring) Wayne Walker has a project on Git Hub called ssh-find-agent which can handle those cases (but is a lot more complicated).

If you paid close attention you may have noticed that no SSH keys are automatically loaded. You can sort of do this with pam_ssh or gnome-keyring but AFAIK neither supports the new SSH protocol 2 private keys (i.e. as generated by ssh-keygen -o), and gnome-keyring has other bugs that I’ve blogged about earlier (e.g. you can’t remove keys from it).

I also want my SSH encryption key to be different from my login password, and AFAIK pam_ssh requires that the two be the same.

Instead what I do is have some wrapper methods in my ~/.bashrc that load keys into my ssh-agent the first time the key is used. The relevant code from my ‘~/.bashrc` file is like:

ensure_ssh() {
    /usr/bin/ssh-add -l &>/dev/null || /usr/bin/ssh-add
}

ssh() {
    ensure_ssh
    /usr/bin/ssh "$@"
}

rsync() {
    ensure_ssh
    /usr/bin/rsync "$@"
}

unset SSH_ASKPASS

The first time I run ssh or rsync I’m prompted for a key and then it is loaded into my agent. I also unset SSH_ASKPASS as I dislike the graphical SSH password manager that GNOME sets during login.