Setup the SSH server to use keys for authentication


"Secure Shell or SSH is both a computer program and an associated network protocol designed for logging into and executing commands on a networked computer." -WikiPedia-
An SSH server can be set up in various ways, but in this document I’ll describe how it can be configured to:
  • only support connections through the 2nd version of the SSH protocol (SSH-2)
  • use DSA keys for user authentication, without permitting authentication with passwords
  • allow only a specific group of users to connect

The SSH-2 protocol, apart from many other useful features, provides stronger security than SSH-1. It’s a bit more cpu hungry than the latter, but this should not be a problem. Using the above configuration, someone must be extremely lucky to manage to break into our system.
But, let me say a few words about how the authentication is done. The user creates a keypair, which consists of a private key, that can be protected with a passphrase, and a public key. The public key is transfered to the server and the private key is kept in our workstation. We assume that the user has accounts in both the server machine and his workstation. Everytime he tries to connect to the server, the keys are validated and the user is granted access.

Prerequisites

user account in the SSH server machine.
You need to install the following packages to the SSH server machine:
  • openssh
  • openssh-server
The client machines should have the following:
  • openssh
  • openssh-clients

First things first…

I assume that our server machine (server.example.com) is a headless one and that the SSH server is up and running with the default configuration. This permits users, including root, to login with their username/password combination. I also assume that we have already set up a user account on the server with the username "leopard". From a client machine (pc1.example.com) we connect like this:
# ssh leopard@server.example.com
Keypair generation
The default key directory is "~/.ssh". Create this directory in both the user leopard’s home on the server and in your current home directory on the client machine and chmod it so that only the users have access to it.
# mkdir ~/.ssh
# chmod 0700 ~/.ssh
Now, we will create our keypair on our client machine. The following command creates a standard 1024-bit DSA keypair:
# ssh-keygen -t dsa -f ~/.ssh/id_dsa
You will be asked for a passphrase for the private key. You can type any phrase here or leave it blank. Keep in mind that if you do not set a passphrase for you private key and someone else gets access to it, then it will take him only a few seconds to connect to your user account on the server. Anyway, this is up to you. After the key generation is finished, the files id_dsa(private key) and id_dsa.pub (public key) are created in the ~/.ssh/ directory.
Now, we will copy the public key to the /home/leopard/.ssh/ directory on the server saving it with the name authorized_keys and delete id_dsa.pub from our client machine, just because it’s not needed to be there.
# scp ~/.ssh/id_dsa.pub leopard@server.example.com:~/.ssh/authorized_keys
# rm -f ~/.ssh/id_dsa.pub
Make sure that you chmod both keys so that only the respective users have access to them. Issue the following command on both the server and the client machine:
# chmod 0600 ~/.ssh/*
A limited group of SSH users
As an extra security measure, we will create a new group on the server machine and configure the SSH server to only allow this group’s members to authenticate. So, we create a group named "sshusers" and add user "leopard" to it. This has to be done as root:
# groupadd sshusers
# usermod -a -G sshusers leopard

The SSH Server configuration

The SSH server’s configuration file is /etc/ssh/sshd_config. Most of the default options do not need to be modified. What we’ll do is to set it up so that only the members of the "sshusers" group can authenticate using keys instead of passwords. So, as root, fire up your favourite text editor and edit the server configuration file.
NOTE: It’s a good habit to create backups before editing system files.
The options that need to be modified are shown below:
Port 22
Protocol 2
AddressFamily inet
ListenAddress 192.168.0.1
With these we configure the server to listen on port 22, accept connections only over the SSH-2 protocol, use the IPv4 address family and bind on the 192.168.0.1 IP address. Only the "protocol" option is really critical. You can set the others as you like or leave the defaults.
HostKey /etc/ssh/ssh_host_dsa_key
Uncomment or add this line. This is exactly the same as the default option, but needs to be uncommented in the server configuration file, so that the server shows its DSA key’s fingerprint when the client tries to authenticate the server during the connection process. If this is not set, then the server shows its RSA key’s fingerprint (the reason is unknown to me).
LoginGraceTime 2m
PermitRootLogin no
MaxAuthTries 1
The LoginGraceTime option sets a time limit for the user authentication process. If this time passes and the user has not yet authenticated succesfully, then the server closes the connection. Leave this value to the default "2m" until everything is set up properly, so that you have enough time to read any server messages. After that, you can lower it to a reasonable value. I have set it to "20s".
Setting the "PermitRootLogin" option to "no" the server does not allow root to login directly. You can still use "su" after you have succesfully logged in as a normal user.
The "MaxAuthTries" option sets the maximum login attempts per connection. Since we use keys and key validation never fails, we set it to "1".
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
These are the default options. I just add them here so that you make sure they are set up properly in your config.
RSAAuthentication no
PasswordAuthentication no
UsePAM no
KerberosAuthentication no
GSSAPIAuthentication no
We do not want the server to let users authenticate using passwords or use SSH-1 based authentication methods. You should comment out any Kerberos or GSSAPI options too.
AllowGroups sshusers
Only users that belong to the "sshusers" group can authenticate. Any other user will be rejected without even being given the oportunity to authenticate.
MaxStartups 2
This option specifies the maximum number of concurrent unauthenticated connections to the SSH Server. It has nothing to do with the number of authenticated connections. The default value is "10". We lower this value in order to limit the connections from third parties which do not have an account on our server machine.
Banner /etc/ssh/banner
Finaly, you can set a text file that will be displayed as a banner when someone connects to the server. Just remember that it is displayed before the authentication takes place, so do not be very descriptive. The banner is not really needed.
This is all we have to do. The rest of the configuration options should be left to their default values, unless you need something different. This is up to you.
Restarting the server
Now, that we have finished editing the config file, we need to restart the server, so that our changes take effect. Before that, I would recommend deleting any existing server keys. Don’t worry, they will be recreated as soon as the service is restarted. A quick way to delete all the keys is to:
# rm -f ssh_host*key*
Then restart the server:
# service sshd restart
Note that the key creation time may vary from machine to machine, so it may take a few minutes if the CPU is slow.
The server logging is done through syslog and authentication information is sent to/var/log/secure. This file should not be world-readable.
A last thing is to take a note of the server’s DSA public key fingerprint, so that we can compare it with the fingerprint the server sends to our client when we connect. This is important for connections to the server from locations other than our LAN in order to be sure that we actually connect to our server. On the server console type:
# ssh-keygen -l -f /etc/ssh/ssh_host_dsa_key.pub
Take a note of the fingerprint.

Connect to the server

To connect to our SSH server from our client machine (pc1.example.com), we type:
# ssh leopard@server.example.com
I suggest that the first time you connect you should add the -v option to the above command for verbose output.
Before the user authentication takes place, the ssh client will try to authenticate the SSH server. Since, there is no stored information about your server it will present you the server’s public DSA key fingerprint so you can compare it with the fingerprint you had previously taken a note of during the server configuration. If the fingerprints are identical, you can answer positively to the question. At this time the file ~/.ssh/known_hosts is created on your client machine and it contains the trusted SSH server’s information. You will never be asked again if you trust this server. If the fingerprint comparison took you longer than the server’sLoginGraceTime, the user authentication does not take place. Just try to reconnect. This time you will eventually log in succesfully using key authentication.
Hashing the known_hosts file
Because the servers’ hostnames and addresses are stored in plain text in the known_hosts file, hashing it is a good habit. This can be done using the ssh-keygen utility. Type:
# ssh-keygen -H -f ~/.ssh/known_hosts
This process makes it unreadable, but the ssh programs can still read the contents. Make sure you permanently delete the known_hosts.old backup file.
Change your private key’s passphrase
If you ever need to change the private key’s passphrase you can use ssh-keygen:
# ssh-keygen -p -f ~/.ssh/id_dsa

The ssh-agent

Although key authentication has many advantages over the authentication with passwords, it has one significant drawback: we have to type the passphrase every time we make a connection to the SSH server. One solution would be not to use a passphrase for our private key. But, this is unacceptable. If someone else gets access to our key and finds out to which servers we connect, things get really bad. A second solution is to use the ssh-agent (part of the openssh package) which caches our passphrase in the memory and then it’s automatically used when we make the connection to the SSH server. This way, we only need to type the passphrase once. This is by far more secure than not using a passphrase.
The ssh-agent is a small daemon that runs in the background. When it is run, it exports some environment variables (SSH_AUTH_SOCK, SSH_AGENT_PID) which can be used by programs likessh-add in order to manage the agent’s cached info or by other programs like the ssh client in order to use this cached info for user authentication. These environment variables must be available to these programs, so the ssh-agent needs to be started in our login shell. There are many different ways to start the agent. Here I’ll describe a rather simple, but very efficient one.
The ssh-agent’s configuration
What we need is to start the agent when we login to our client machine’s shell and stop it when we log out. So, we add the following line to ~/.bash_profile:
eval `ssh-agent`
Why do we use eval? When the ssh-agent is started, it just prints some commands to the stdout. These commands set and export the environment variables we talked about earlier. We use eval, so that these commands are actually executed, or better, evaluated by the shell, so the environment variables are made available to all applications that can use them.
We add the following line to ~/.bash_logout
eval `ssh-agent -k`
This "unsets" the environment variables and kills the agent every time we logout.
Management of cached passphrases
A small utility called ssh-add is used to manage the cached passphrases.
To add a key to the ssh-agent’s cache, we issue the command:
# ssh-add ~/.ssh/id_dsa
We are prompted for the passphrase. After typing it succesfully, it gets cached. From now on, the cached passphrase will be automatically used for every connection we make to the SSH server. Convenient!
If we store our key to the standard location ~/.ssh/ and name it with the standard filenameid_dsa, then ssh-add can be run without arguments. Our key will be used.
To list the cached keys we type:
# ssh-add -l
To remove a cached key:
# ssh-add -d ~/.ssh/id_dsa
To empty the ssh-agent’s cache:
# ssh-add -D

Further Reading

There are numerous articles around the web about SSH. Just use google. Keep in mind though that all the necessary info is in the man pages. You should not just read them, but rather study them:
  1. The official openssh manuals
  2. The openssh FAQ
(Refer g-loaded.eu)