Posts Tagged ‘OS X’

Using multiple private keys with SSH

Friday, July 23rd, 2010

A couple of days ago I posted on how to set up a subversion server with ssh access. In that post, in the section about creating your private ssh key I said that if you already had an id_rsa or id_dsa file in your ~/.ssh directory not to go any further because the generation of a new private key file could over write it. This post explains how to cope with multiple private keys.

ssh uses ~/.ssh/identity as the default filename for the private key when using version 1 of the ssh protocol and it uses ~/.ssh/id_rsa and ~/.ssh/id_dsa as the default filenames for the RSA and DSA private keys when using version 2 of the ssh protocol. However there are several ways of changing this behaviour.

Command line

ssh allows you to provide a different identity/id file using the -i option on the ssh command line as follows:

$ ssh -i /path/to/id_rsa user@some.domain.org

Where id_rsa can be substituted with id_dsa or identity.

This is the simplest method. And when used in conjunction with a subversion client you can create a [tunnel] in the subversion configuration file like so:

[general]
ssh = ssh -i /path/to/identity_file

If you want to support different identity/id files create a new [tunnel] ‘alias’ for each identity file. You can also use the -p option if you want to specify a different port at the same time.

Config file – first method

Another method is to use the ssh config file. The global file is found in /etc/ssh/config however you can also provide config files on a per user basic in ~/.ssh. In the config file you can restrict declarations using the Host declaration. Per the man page:

Host
   Restricts the following declarations (up to the next Host 
   keyword) to be only for those hosts that match one of the 
   patterns given after the keyword.  If more than one pattern 
   is provided, they should be separated by whitespace.  A 
   single `*' as a pattern can be used to provide global defaults 
   for all hosts.  The host is the hostname argument given on 
   the command line (i.e. the name is not converted to a 
   canonicalized host name before matching).

The declaration IdentityFile allows you to specify the private key file that ssh should use. By using Host and IdentityFile you can let ssh pick the identity/id file itself based upon the host name. The following example will pick ~/.ssh/id_dsa for any host other than my.specific.host.org and my.other.host.com. In those cases the specified private key files are used.

# General settings
IdentityFile ~/.ssh/id_rsa
IdentifyFile ~/.ssh/id_dsa
IdentityFile ~/.ssh/identity

Host my.specific.host.org
IdentityFile ~/.ssh/my_specific_key_file

Host my.other.host.com
IdentityFile ~/.ssh/my_other_key_file

Note how the config file allows you to specify more than one file at once. When you do ssh will try each of the files in turn or as appropriate.

Config file – second method

The problem with the above method is that you have to keep adding new entries to the config file for new hosts. IdentityFile is actually very powerful and allows you to have wild cards in the path specification. The full man page definition says:

IdentityFile
   Specifies a file from which the user's RSA or DSA 
   authentication identity is read.  The default is ~/.ssh/identity 
   for protocol version 1, and ~/.ssh/id_rsa and ~/.ssh/id_dsa 
   for protocol version 2. Additionally, any identities 
   represented by the authentication agent will be used for 
   authentication.

   The file name may use the tilde syntax to refer to a user's 
   home directory or one of the following escape characters: 
   `%d' (local user's home directory), `%u' (local user name), 
    `%l' (local host name), `%h' (remote host name) or `%r' 
   (remote user name).

   It is possible to have multiple identity files specified in 
   configuration files; all these identities will be tried in 
   sequence.

So I have set up my config file as below. It basically tries ~/.ssh/idents/hostname/username/id_* first, then ~/.ssh/idents/hostname/id_*, then the defaults before giving up.

# SSH config file

IdentityFile ~/.ssh/idents/%h/%u/id_rsa
IdentityFile ~/.ssh/idents/%h/%u/id_dsa
IdentityFile ~/.ssh/idents/%h/id_rsa
IdentityFile ~/.ssh/idents/%h/id_dsa
IdentityFile ~/.ssh/id_rsa
IdentityFile ~/.ssh/id_dsa

This allows me to support a new server/key file combination just by putting the key file in the appropriate place in the ~/.ssh without having to edit config files.