OpenSSH/Cookbook/Authentication Keys

From Wikibooks, open books for an open world
Jump to: navigation, search

Authentication keys can improve efficiency, if done properly. As a bonus advantage, the passphrase and private key never leave the client. They are generally recommended for outward facing systems so password authentication can be turned off.

Verify a Host Key by Fingerprint[edit]

The first time connecting to a remote host, the key itself should be verified. Usually this is done by comparing the fingerprint or the ASCII art visual host key, metadata about the key, rather than trying to compare the whole key itself.

$ ssh -l fred server.example.org
The authenticity of host 'server.example.org (192.0.32.10)' can't be established. 
RSA key fingerprint is 4a:11:ef:d3:f2:48:f8:ea:1a:a2:0d:17:57:ea:a6:16. 
Are you sure you want to continue connecting (yes/no)? 

Downloading keys[edit]

Usually a host’s key is displayed the first time the SSH client tries to connect. The remote host’s public RSA or DSA keys can also be fetched on demand using ssh-keyscan(1):

$ ssh-keyscan -t rsa host.example.org
# host.example.org SSH-2.0-OpenSSH_5.3
host.example.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAsA3bhtFFgzB9sdcjS0gcPRILUYGlDciXDzBb3PVp2rAYW1yW4AwsWLBYXW7d38dj+Q4rdGdzwpdsu0cAuFA9UD+9o1ajxAa8hAQsjOU+1l/hEJDQelYEeW905CZF7xl4sbcapyKN5y1bXZtdz84E2v8LAruNzCUULt564NUeGSQQRNiHfNta6VXrMAU4fYGMiHynbxTjOmpZV/GiSwcyZqCQqCmTMq2nn0/32QgpfmTkNgAHYk0jh/YNtXmRsGnbEvqdZAwog+NQsQriye0d2MMlgpuevpYKgL1IAhXMeb+Xx2HcUXjuKINwYAwfqOBQZBWMyMw5TAV1tFktsJBY4w==

Once the key is acquired, its fingerprint can be shown using ssh-keygen(1). This is a two step process, the key is read to a file and then the file analyzed to get a fingerprint.

$ ssh-keyscan -t rsa host.example.org > key
$ ssh-keygen -lf key
2048 37:af:05:99:e7:fb:86:6c:98:ee:14:a6:30:06:bc:f0 192.168.12.1 (RSA)

Note that output from ssh-keyscan(1) is sent to stderr instead of stdout. Note that the pipe below works on some systems and not others.

$ ssh-keyscan -t rsa host.example.org 2>&1 | ssh-keygen -lf -
2048 37:af:05:99:e7:fb:86:6c:98:ee:14:a6:30:06:bc:f0 192.168.12.1 (RSA)

It is possible to find all hosts from a file which have new or different keys from those in known_hosts, if the host names are in clear text and not stored as hashes.

$ ssh-keyscan -t rsa,dsa -f ssh_hosts | \
  sort -u - ~/.ssh/known_hosts | \
  diff ~/.ssh/known_hosts -

ASCII Art Visual Host Key[edit]

An ASCII art representation of the key can be supplied along with the fingerprint:

$ ssh-keygen -lvf key 
2048 37:af:05:99:e7:fb:86:6c:98:ee:14:a6:30:06:bc:f0 www.example.net (RSA) 
+--[ RSA 2048]----+ 
|          o      | 
|         o .     | 
|        o o      | 
|       o +       | 
|   .  . S        | 
|    E ..         | 
|  .o.* ..        | 
|  .*=.+o         | 
|  ..==+.         | 
+-----------------+ 

Key-based authentication[edit]

OpenSSH can use public key cryptography for authentication. In public key cryptography, encryption and decryption are asymmetric. The keys are used in pairs, a public key to encrypt and a hidden key to decrypt. ssh-keygen(1) can make RSA, DSA, or ECDSA keys for authenticating. DSA keys must be exactly 1024 bits in size. RSA keys are allowed to vary from 768 bits on up. ECDSA can be one of 256, 384 or 521 bits. Shorter keys are faster, but less secure. Longer keys are much slower to work with but provide better protection.

The key files can be named anything, so it is possible to have many keys each for different services or tasks. The comment field at the end of the public key can be useful in helping to keep the keys sorted, if you have many of them or use them infrequently.

With key-based authentication, a copy of the public key is stored on the server and the private key is kept on the client. When the client first contacts the server, the server responds by using the client's public key to encrypt a random number and return that encrypted random number as a challenge to the client. The client uses the matching private key to decrypt the challenge and extract the random number. The client then makes an MD5 hash of the session ID and the random number from the challenge and returns that hash to the server. The server then makes its own hash of the session ID and the random number and compares that to the hash returned by the client. If there is a match, the login is allowed. If there is not a match, then the next public key on the server is tried until either a match is found or all the keys have been tried. [1]

If an agent is used on the client side to manage authentication, the process is similar. It only differs in that ssh(1) passes the challenge off to the agent which then calculates the response and passes it back to ssh(1) which then passes the agent's response back to the server.

Basics of Public Key Authentication[edit]

For public key authentication, a key pair is needed. ssh-keygen(1) is used to make the key pair. From that pair the public key must be properly stored on the remote host and the private key stored safely on the client. The public key is added to the designated authorized_keys file for the remote user account. Once the keys have been prepared they can be used again and again without needing to do anything else.

Preparation of the keys: 0) If either the authorized_keys file or .ssh directory do not exist on either the client machine or the remote machine, create them and set the permissions correctly:

$ mkdir ~/.ssh/
$ touch ~/.ssh/authorized_keys
$ chmod 0700 ~/.ssh/
$ chmod 0600 ~/.ssh/authorized_keys

1) Create a key pair. The example here creates a 4096-bit RSA key pair in the directory ~/.ssh. As a result, the public key will be seen named mykey_rsa.pub and and the private key will be called mykey_rsa. Be sure to enter a sound passphrase.

$ ssh-keygen -b 4096 -t rsa -f ~/.ssh/mykey_rsa

2) Transfer both the public and private keys to the client machine, if not already there from the step above. It is usually best to store both the public and private keys in the directory ~/.ssh/ together.

3) Transfer only the public key to remote machine.

$ scp ~/.ssh/mykey_rsa fred@remotehost.example.org:.

4) Log in to the remote machine and add the new public key to the authorized_keys file, whether in ~/.ssh/authorized_keys, the default, or somewhere else as designated by the server's configuration.

$ cat mykey_rsa >> ~/.ssh/authorized_keys
$ nano -w ~/.ssh/authorized_keys

Any editor that does not wrap long lines can be used. In the example above, nano(1) is started with the -w option to prevent wrapping of long lines. The same can also be accomplished permanently by editing nanorc(5) However it is done, the key must be in the file whole and unbroken, on a single line.

Usage of the keys: Authenticate to the remote machine from the client using the private key. The option -i tells ssh(1) which private key to try.

$ ssh -i ~/.ssh/mykey_rsa -l fred remotehost.example.org

A common error, if a key doesn't work, is that the file permissions are wrong. The authorized key file must not be group writable.

$ chmod u=rwx,g=rx,o= ~/.ssh
$ chmod u=rw,g=,o=  ~/.ssh/authorized_keys 

Another mistake that can happen is if the key is broken by line breaks or has other white space in the middle. That can be fixed by joining up the lines and removing the spaces or by recopying the key more carefully.

Associating Keys Permanently with a Server[edit]

The host directive in ssh_config(5) can apply specific settings to a target host. That includes using specific keys with certain hosts. So by changing ~/.ssh/config it is possible to assign keys to be tried automatically whenever making a connection to that host. Here, all that's needed is to type ssh web1 to connect with the key for that server.

Host web1
        Hostname 198.51.100.32
        IdentitiesOnly=yes
        IdentityFile=/home/fred/.ssh/web_key_rsa

Below ~/.ssh/config uses different keys for server versus server.example.org, regardless whether they resolve to the same machine. This is possible because the host name argument given to ssh(1) is not converted to a canonicalized host name before matching.

Host server
        IdentityFile /home/fred/.ssh/key_a_rsa

Host server.example.org
        IdentityFile /home/fred/.ssh/key_b_rsa  

The parser is first-match, so the shorter name is tried first. Of course less ambiguous shortcuts can also be made.

Encrypted Home Directories[edit]

With encrypted home directories, the keys must be stored in an unencrypted directory and sshd(8) configured appropriately to find the keys in that special location. Sometimes it is also necessary to add a script or call a program from /etc/ssh/sshrc to decrypt the directory after authentication.

One symptom of having an encrypted home directory is that key-based authentication only works when you are already logged into the same account, but fails when trying to make the first connection and log in for the first time.

Here is one method for solving the access problem. Each user is given a subdirectory under /etc/ssh/keys/ which they can then use for storing their authorized_keys file. This is set in the server's configuration file /etc/ssh/sshd_config

AuthorizedKeysFile      /etc/ssh/keys/%u/authorized_keys

Multiple key file locations can be specified if they are separated by whitespace. The user needs read access to the directory and keys, but write access is not needed. That opens up more possibilities as to how the keys can be managed.

Passwordless login[edit]

One way of allowing passwordless logins is to follow the steps above, but do not enter a passphrase. Note that this is very risky, so the key files should be very well protected and kept track of. That includes that they only be used as single-purpose keys as described below. Timely key rotation becomes especially important. In general, it is not a good idea to make a key without a passphrase. A better solution is to work with an authentication agent in conjunction with a single-purpose key.

Requiring Both Keys and a Password[edit]

While users should have strong passphrases for their keys, there is no way to enforce or verify that. Indeed, the passphrase for any given key never leaves the client machine so it is nothing that the server can have any influence over. Starting with OpenSSH 6.2, it is possible for the server to require multiple authentication methods for login using the AuthenticationMethods directive.

AuthenticationMethods publickey,password

This example requires that users first authenticate using a key and only queries for a password if that succeeds. It is not possible to get to the system password prompt without first authenticating with a valid key. Changing the order of the arguments changes the order of the authentication methods.

AuthenticationMethods can also be set under a Match directive to apply only to certain groups or situations.

Key-based authentication using an Agent[edit]

The authentication agent, ssh-agent(1), should be started at the beginning of the session and used to launch the login session or X-session so that the environment variables are passed to each subsequent shell pointing to the agent process and its unix-domain socket. Many distros do this automatically upon login or startup. Starting the agent sets a pair of environment variables:

  • SSH_AGENT_PID : the process id of the agent
  • SSH_AUTH_SOCK : the filename and full path to the unix-domain socket

The various SSH and SFTP clients find these variables automatically and use them to contact the agent if they are set and if one or more keys are loaded. If the shell or desktop session was launched using ssh-agent(1), then these variables are already set and available. If not, then it is necessary to set them manually inside each shell or for each application in order to use the agent.

Once the agent is available, a private key only needs to be loaded once and then can be used many times. Private keys are loaded into the agent with ssh-add(1).

$ ssh-add /home/fred/.ssh/mykey_rsa

It is possible to list the identities currently in the agent. The option -l will list all the fingerprints of the identities in the agent.

$ ssh-add -l
2048 09:58:23:08:03:65:e0:2b:03:54:31:89:7b:ee:05:28 /home/fred/.ssh/some_key_rsa (RSA)

It is also possible to remove individual identities from the agent using -d which will remove them one at a time by name, but only if the name is given. Without the name of a private key, it will fail silently. Using -D will remove all of them at once without needing to specify any by name.

Agent forwarding[edit]

In agent forwarding, intermediate machines forward challenges and responses back and forth between the client and the final destination. This eliminates the need for passwords or keys on any of these intermediate machines. In other words, an advantage of agent forwarding is that the private key itself is not needed on any remote machine, thus hindering unwanted access to it. [2] Another advantage is that the actual agent to which the user has authenticated does not go anywhere and is thus less susceptible to analysis.

The default configuration files for the server enable authentication agent forwarding, so to use it, nothing needs to be done there. On the client side it is disabled by default and so it must be enabled explicitly. Put the following line in ssh_config(5) to enable agent forwarding for a particular server:

Host gateway.example.org
        ForwardAgent yes

One risk with agents is that they can be re-used to tailgate in if the permissions allow it. Keys cannot be copied this way, but authentication is possible when there are incorrect permissions. Note that disabling agent forwarding does not improve security unless users are also denied shell access, as they can always install their own forwarders.

Single-purpose keys[edit]

Tailored single-purpose keys can eliminate use of remote root logins for administrative activities. A finely tailored sudoers is needed along with a user account. When done right, it gives just enough access to get the job done, following the security principle of Least Privilege. Single-purpose keys are accompanied by use of either the ForceCommand directive in sshd_config(5) or the Command= directive inside the authorized_keys file. Further, neither the authorized_keys file nor the home directory should be writable. ssh -v can show exactly what is being passed to the server so that sudoers can be set up correctly when setting up encrypted remote backups using rsync, tar, mysqldump, etc. For example, here is what ssh -v show from one particular usage of rsync:

$ rsync --server -vlHogDtprz --delete --delete-after \
        --ignore-errors . /org/backup

Key-based authentication, with limitations on activity[edit]

The authorized_keys file can force a particular program to run whenever the key is used. This is useful for automating various tasks. The following launches firefox automatically and exits the connection when it is finished.

command="/usr/bin/firefox" ssh-rsa AAAAB3NzaC1yc2EAAA...OFy5Lwc8Lo+Jk=

The following further restricts the connection to coming from a single domain.

command="/usr/bin/firefox",from="*.example.net" ssh-rsa AAAAB3...FLoJk=

The manual page sshd(8) has the full list of options for the authorized_keys file.

The following key will only echo some text and then exit, unless used non-interactively with the -N option. No matter what the user tries, it will echo the text. The -N option will disable running the remote program, allowing the connection to stay open.

command="/bin/echo do-not-send-commands" ssh-rsa AAAAB3...99ptc=

This is very useful for keys that are only used for tunnels.

Read-only access to keys[edit]

In some cases it is necessary to prevent the users from changing their own authentication keys. This can be done by putting the key file in an external directory where the user has read-only access to the key file and no write permissions to either the file or the directory. The AuthorizedKeysFile directive sets where sshd(8) looks for the keys and can point to the secured location for the keys instead of the default location.

The default location for keys on most systems is usually ~/.ssh/authorized_keys. A good alternate location could be to create the directory /etc/ssh/authorized_keys and store the selected users' key files there. The change can be made to apply to only a group of users by putting it under a Match directive.

Match Group sftpusers
        AuthorizedKeysFile /etc/ssh/authorized_keys/%u

This works even within a chrooted environment.

Match Group sftpusers
        ChrootDirectory /home
        ForceCommand internal-sftp -d %u
        AuthorizedKeysFile /etc/ssh/authorized_keys/%u

Of course it could be set to affect all users by putting the directive in the main part of the server configuration file.

Mark public keys as revoked[edit]

Keys that have been revoked can be stored in /etc/ssh/revoked_keys, a file specified in sshd_config(5) using the directive RevokedKeys, so that sshd(8) will prevent attempts to log in with them. No warning or error on the client side will be given if a revoked key is tried. Authentication will simply progress to the next key or method.

The revoked keys file should contain a list of public keys, one per line, that have been revoked and can no longer be used to connect to the server. The key cannot contain any extras, such as login options or it will be ignored. If one of the revoked keys is tried during a login attempt, the server will simply ignore it and move on to the next authentication method. An entry will be made in the logs of the attempt, including the key's fingerprint. See the section on logging for a little more on that.

RevokedKeys /etc/ssh/revoked_keys

The RevokedKeys configuration directive is not set in sshd_config(5) by default. It must be set explicitly if it is to be used.

Key Revocation Lists[edit]

A compact, binary form of representing revoked keys and certificates is available as a Key Revocation List (KRL). KRLs are generated with ssh-keygen(1) and can be created fresh or an existing one updated.

$ ssh-keygen -kf  /etc/ssh/revoked_keys -z 1 ~/.ssh/old_key_rsa.pub
$ ssh-keygen -ukf /etc/ssh/revoked_keys -z 2 ~/.ssh/old_key_dsa.pub

It is possible to test if a specific key or certificate is in the revocation list.

$ ssh-keygen -Qf  /etc/ssh/revoked_keys ~/.ssh/old_key_rsa.pub

Only public keys and certificates will be loaded into the KRL. Corrupt or broken keys will not be loaded and will produce an error message if tried. Like with the regular RevokedKeys list, the public key destined for the KRL cannot contain any extras like login options or it will produce an error when an attempt is made to load it into the KRL or search the KRL for it.

More on Verifying SSH Keys[edit]

Reliable verification of a host key must be done when first connecting. To know the key fingerprint in advance, it can be necessary to contact the system administrator who can provide it out of band. Use ssh-keygen on the local console to be absolutely sure.

Here the server's RSA key is read:

$ ssh-keygen -lf /etc/ssh/ssh_host_rsa_key
xxxx x:x:x:x:x:x:x:x:x:x:x:x:x:x:x:x /etc/ssh/ssh_host_rsa_key.pub (RSA)

And here the corresponding DSA key is read.

$ ssh-keygen -lf /etc/ssh/ssh_host_dsa_key
1024 x:x:x:x:x:x:x:x:x:x:x:x:x:x:x:x /etc/ssh/ssh_host_dsa_key.pub (DSA)

It is also possible to use ssh-keyscan(1) However, the fingerprint still needs to be verified out of band.

Warning: Remote Host Identification Has Changed![edit]

If the server's key does not match what has been recorded in either the system's or the local user's authorized_keys files, then the SSH client will issue a warning. Two main reasons for the warning exist. One is when the server's key has been changed, maybe the server was reinstalled without backing up the old keys. Another situation is when the connection is made to the wrong machine, one such case would be the during an attempted man in the middle attack or when contacting a server that changes addresses because of dynamic address allocation.

In cases where the key has changed there is only one thing to do: contact the system administrator and verify the key. The system administrator may be you yourself in some cases. If so, was OpenSSH-server recently reinstalled, or was the machine restored from an old backup? The new key fingerprint can be sent out by some method where it is possible to verify the integrity and origin of the message, for example via PGP-signed e-mail.

Then go over to the client machine where you got the error and remove the old key from ~/.ssh/known_hosts

$ ssh-keygen -R host.example.org

Then try logging in, but enter the password if and only if the key fingerprint matches what you got on the server console. If the key fingerprint matches, then go through with the login process and the key will be automatically added. If the key finger print does not match, stop immediately and it would be a good idea to get on the phone (a real phone, no computer phones) to the remote machine's system administrator or the network administrator.

Multiple keys for a host, multiple hosts for a key in known_hosts[edit]

Using pattern matching in known_hosts, it is possible to assign multiple host names or ip addresses to the same key. That goes for both those global keys in /etc/ssh/ssh_known_hosts and those local user-specific key lists in ~/.ssh/known_hosts. They should provide you with an up-to-date set to add to your known hosts file. Otherwise, you must verify the keys by hand.

server1,server2,server3 ssh-rsa AAAAB097y0yiblo97gvl...jhvlhjgluibp7y807t08mmniKjug...==

You can use globbing to a limited extent in either /etc/ssh/ssh_known_hosts or ~/.ssh/known_hosts.

172.19.40.* ssh-rsa AAAAB097y0yiblo97gvl...jhvlhjgluibp7y807t08mmniKjug...==

However, to get the effect you want, multiple keys for the same address, make multiple entries in either /etc/ssh/ssh_known_hosts or ~/.ssh/known_hosts, one for each key.

server1 ssh-rsa AAAAB097y0yiblo97gvljh...vlhjgluibp7y807t08mmniKjug...==
server1 ssh-rsa AAAAB0liuouibl kuhlhlu...qerf1dcw16twc61c6cw1ryer4t...==
server1 ssh-rsa AAAAB568ijh68uhg63wedx...aq14rdfcvbhu865rfgbvcfrt65...==

To get a pool of servers to share a pool of keys, each server-key combination must be added manually to the known_hosts file.

 
server1 ssh-rsa AAAAB097y0yiblo97gvljh...07t8mmniKjug...==
server1 ssh-rsa AAAAB0liuouibl kuhlhlu...qerfw1ryer4t...==
server1 ssh-rsa AAAAB568ijh68uhg63wedx...aq14rvcfrt65...==

server2 ssh-rsa AAAAB097y0yiblo97gvljh...07t8mmniKjug...==
server2 ssh-rsa AAAAB0liuouibl kuhlhlu...qerfw1ryer4t...==
server2 ssh-rsa AAAAB568ijh68uhg63wedx...aq14rvcfrt65...==

I'm not quite sure how to get that to work with hashed host names.

This will get the rsa key for server1, put the rsa key in file (e.g. /tmp/z.key) and give a fingerprint for the key in that file:

$ ssh-keyscan -t rsa server1 
$ ssh-keyscan -t rsa server1 > /tmp/z.key 
$ ssh-keygen -l -f /tmp/z.key

Another way of Dealing with Dynamic (roaming) IP Addresses[edit]

It is possible to manually point to the right key using HostKeyAlias either as part of ssh_config(5) or as a runtime parameter. Here the key for machine Foobar is used to connect to host 192.168.11.15

$ ssh -o CheckIP=no -o StrictHostKeyChecking=no \
      -o HostKeyAlias=foobar   192.168.11.15

This is useful when DHCP is not configured to try to keep the same addresses for the same machines over time.

References[edit]