Using multiple private keys with SSH
Friday, July 23rd, 2010A 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.