Introduction
Administering large numbers of SSH keys and servers can be very difficult as your organization grows. Correctly identifying valid keys and removing invalid keys throughout an organization can be fraught with errors and have huge consequences on your server security.
In addition, when there are server changes, sometimes your users will receive warnings about being unable to establish the authenticity of your server. Most users will not double-check the key fingerprint of the server before connecting, allowing someone to potentially spoof the server and execute a man-in-the-middle attack.
A project called monkeysphere was created to address these issues. It does this by leveraging GPG keys and the web of trust model to both validate a server’s credentials, and provide easy user management.
In a previous guide, we discussed how to setup monkeysphere to validate servers to users. We will continue where we left off in this guide, where we will learn how to authenticate users to our servers automatically, based only on their GPG keys and our server administrator’s trust in these users. This will allow us to create authentication files that use plain English instead of mostly cryptographic information.
This guide will assume that you have the setup that we left off with in the previous guide (server.example.com, admin.example.com, client.example.com with the necessary trust relationships established). Let’s get started.
Create an Identity Certifier on the SSH Server
The first step towards allowing our SSH server to automatically authenticate our users to the server is to establish an identify certifier. An identity certifier is simply a person we are designating as trusted in establishing the identity of users.
In most cases, the simple and logical choice is to have the server administrator identify users who should be able to log in. We are going to go this route. You can also create more than one identity certifier if your situation requires a distribution of that responsibility.
Let’s begin by getting the fingerprint of our administrative user again. On our admin’s computer, we can use the same GPG command we used in the last guide to get the full fingerprint:
gpg --with-colons --fingerprint [email protected]
Again, we are looking for the line of output that looks like:
fpr:::::::::A61256B85307B7ED9AD8D93E9E06881E49E95F19:
The section highlighted in red is what we need here.
On the SSH server (server.example.com), we are going to add this key as an identity certifier. You can do this by typing:
monkeysphere-authentication add-identity-certifier A61256B85307B7ED9AD8D93E9E06881E49E95F19
Monkeysphere will then pull the matching GPG information from the keyservers and store it in its own keyring. It will mark this key as one that can verify the identity of other users.
Generate Authentication Subkeys for SSH Users
Now that we have established that our server administrator can identify which users are legitimate, we need to do a bit of work on the client side.
Each client must generate a GPG subkey that will be used for the actual authentication. While the public GPG key is used to identify the user, the subkey is used for the actual login procedure.
The monkeysphere
command contains a subcommand that will allow you to easily generate an authentication subkey. On your client, type:
monkeysphere gen-subkey
A subkey will be generated and added to your local GPG keyring under your main key.
We need to upload the key change to the keyserver again so that our SSH server can use this subkey to generate internal authentication files for the user in question. The key we need to publish is our main key, which contains the subkey change. To get the key information, type:
gpg --list-keys [email protected]
pub 2048R/87791BD0 2014-03-14 uid client <[email protected]> sub 2048R/3294D31D 2014-03-14 sub 2048R/0FECF512 2014-03-14
The highlighted portion is the key ID that we’ll use to send to the server. Use this ID to send the key back to the server:
gpg --keyserver pool.sks-keyservers.net --send-key 87791BD0
Now that our subkey is available on the keyservers (it may take a bit of time to propagate), we can configure our SSH server to generate authentication files using this key.
Creating the Authentication Files on the SSH Server
Now we need to create the actual authentication files. Monkeysphere authentication files come in two distinct categories.
The user-level files are the ones that we should interact with to establish authentication policies. These are simple, straight forward, plain English files that simply specify people by name and email (as committed to GPG) who should be allowed to log in. These files are located in a subdirectory in each user’s home directory, just like regular SSH authorized_keys
files.
These files are then used by Monkeysphere to generate authentication files that SSH can understand using the subkeys associated with each valid user that we created above. Monkeysphere generates authentication files for each user in the /var/lib/monkeysphere/authorized_keys
directory.
We will create the directories and files on the SSH server in this section.
Start by going to the home directory of whatever user you want to configure access for. Since we’ve needed to be signed in with administrative privileges to get this far, let’s set up access for our root user. In the home directory, create a hidden directory called .monkeysphere
:
cd /root
mkdir .monkeysphere
Monkeysphere requires certain permissions on the user-level folders and files in order to consider them valid. Specifically, it requires that there are no write permissions for anyone beyond the file or directory owner.
Let’s set the directory permissions to match this scheme and then let’s move into the directory:
chmod 755 .monkeysphere
cd .monkeysphere
Within this directory, we need to create a file called authorized_user_ids
. This is the user-level authentication file. Create it with your text editor:
nano authorized_user_ids
In this file, we simply list the users, by name and email, exactly as they are in GPG. So to see the formatting we need to use, we can type this again on our client machine:
gpg --list-keys [email protected]
pub 2048R/87791BD0 2014-03-14
uid client <[email protected]>
sub 2048R/3294D31D 2014-03-14
sub 2048R/0FECF512 2014-03-14
So this is all we have to type in this file:
client <[email protected]>
If we want to add additional people, we just add them one per line:
client <[email protected]>
admin <[email protected]>
This is much easier to read and manage than large authorized_keys
files. Those files tend to get out-of-date and it is difficult to tell if an older key is still valid or not. With this method, it is easy to be able to ask yourself “should Bob have access to this machine?” If not, simply remove his name.
Save and close the file when you are finished.
Now, we need to remember to take away write permissions from anyone not the owner:
chmod 644 authorized_user_ids
Repeat this procedure for any user you wish to configure remote access for.
Generating Internal Authentication Files
Now that we have our user-level authentication files in place, we can generate our internal authentication files easily.
All we have to do is issue this command:
monkeysphere-authentication update-users
You should run this command after making any changes to the user-level authentication files.
If you only want to update a specific user, you can add their name as an argument:
monkeysphere-authentication update-users root
Let’s see what files were generated by this procedure. We need to go to the directory where these are stored:
cd /var/lib/monkeysphere/authorized_keys
Inside, you should see a file for each user on the system that you configured access for. The one small caveat to this is that each user in the user-level authentication file needs to have an associated subkey available on the public GPG keyserver network.
ls
demouser root
If we look at the files, we will see a key that looks like:
ssh-rsa
AAAAB3NzaC1yc2EAAAADAQABAAABAQD0CdVIlUptYdZBz/0pn+7XIa2jdzy/VnayAZDXhFdHDTZU0hB8MDGHC9yjUrn9RCMj2NWD3Ls7JjqVAzmRsUn56UwyCJt8/GVmHpeIhYzmUAUjMaaMnjBG3Nhdpm9rsnJt0XVUvOu9oxrvTWYH6ZCVNwsY1O7aX/kQWnaXQW6/B6oiQJ76feZyoLEBR8D/nbxGTtNlkEMcTMTylHN0jHLACJy483SFUkSjHneNK9gNFoxTlUyF/ZBo5+Bo8Uld4iAyhaW7Di4HzfUJzvebZYX1Z1O0yS/db8anSJoZX90MLt7eIFsixuDMS3m31dsX26RI71tJGihvzF0fUsUPDg17
MonkeySphere2014-03-22T13:14:31 client <[email protected]>
As you can see, this is basically a normal authorized_keys
entry. We have abstracted this away though for easier user management and the ability for users to dynamically update their keys through GPG.
You may also see additional lines in this file that are not related to any entry you made in in the authorized_user_ids
file. This is because, by default, monkeysphere appends any entries it finds in existing authorized_keys
files to the end of the generated file. This is to help you in transitioning between the two systems and for users who are unable, for whatever reason, to switch.
Now that we’ve generated these new authorization files, we need to update the SSH daemon’s configuration to look at these files instead of the files within each user’s directory.
Open the config file with your editor (make sure you are selecting sshd_config
, not ssh_config
):
nano /etc/ssh/sshd_config
Within this file, find and modify the AuthorizedKeysFile
parameter, or create it if it does not exist. Set the value to this:
AuthorizedKeysFile /var/lib/monkeysphere/authorized_keys/%u
Save and close the file when you are finished.
Now, we just need to restart the SSH daemon for the change to take place:
service ssh restart
Configure Client to Send GPG Key for Authentication
Now, our server is completely configured to accept the GPG subkey that we created for authentication.
We need to configure our client to connect using this information instead of the usual password or RSA keys. Monkeysphere does this through the use of the ssh-agent
utility, which is used to store authentication details for SSH connections for extended periods of time.
We can try it out without starting the agent itself by using a one-off command like this:
ssh-agent sh -c 'monkeysphere subkey-to-ssh-agent && ssh server.example.com'
This will work, and after you have entered your password for the GPG key, you should be able to connect to the server without entering any password for the server’s account.
However, it’s probably worthwhile to start an agent session. You can do that in your current shell by typing:
eval $(ssh-agent)
To start this automatically every time we login, we can add it to the client’s ~/.bash_profile
file:
echo 'eval $(ssh-agent)' >> ~/.bash_profile
Either way, we then need to add our GPG subkey to the SSH agent so that it can use it for authentication. Do this by typing:
monkeysphere subkey-to-ssh-agent
You will have to type in your GPG key password, but this will only be required once per session.
We can see that it has been accepted by typing:
ssh-add -l
2048 2a:1a:1d:52:32:e5:f4:45:b2:a3:ff:d0:c0:6e:69:f6 client <[email protected]> (RSA)
We can now login without being prompted for anything to any account that we have access to using our GPG subkey:
ssh server.example.com
Conclusion
After getting Monkeysphere set up on your infrastructure, you’ll have a sustainable way of managing server and human interactions for your organization. This method can handle server administrators joining and leaving the organization because all user-level authentication is in plain English. Additionally, you will not have to worry about an attacker trying to spoof access to your servers.