Since Solaris 11.1 the ssh implementation of Solaris supports the usage of X.509 certificates. There is a tutorial of a colleague that explains the setup however when i linked to it a while ago, i got some mails telling me, that it was a little bit on the hard side to understand. So i thought it would be a nice idea to explain the stuff Hai-May Chao wrote in her article on OTN the LKSF way.
However there are a few differences: I won’t explain that much about command lines and - more important - i’m using openssl instead of pktool to create keys and certificates.
Why using certificates
The basic idea of using certificates for ssh is quite simple. In order to get rid of passwords, you have to distribute public keys to the .ssh/authorized_keys files on each server. This is easy, when you have one instance of the OS. However imagine you have one hundred of them … or thousands.
This issue can be nicely solved by certificate. The system doesn’t check if you are for example user junior. The idea of using X.509 certificates is much simpler. You are showing a certificate stating that you are user x or host y and the system believes you. However in order to prevent that you make up your own certificate stating you are user x, the certificate has to be signed by a certificate authority the communication partner trusts. Furthermore to ensure that you don’t have just the certificate, you have to sign some data with the private key, so when your communication partner can validate the signature with the certificate, it knows that you have the private key. So in essence the mechanisms checks if you have a certificate stating that you are user x, checks if a trusted certificate authority has confirmed this fact and checks that you have the private key matching to the CA signed certificate. If all is true, you are allowed to login as user x, if one is not true, access is denied and you have to use your normal password. I know this is vastly simplified, and the subject matter expert will kill me for this, but i think this is sufficient for a first explanation. At the end it’s not that different from doing SSL.
Preparations
When we want to use certificates, we have to create them. We need a Certificate Authority. When you want to do this for more than just playing around, you have to spend some thoughts about the physical security of the system. May be purchasing a cheap notebook or netbook would be a good idea. A system small enough to put it in a safe. Never attach it to the network. Disable WiFi by hardware so you don’t go into the network accidentally. Perhaps by using a wire cutter. Don’t leave it alone outside the safe. This notebook is the anchor of trust in your network and you have to trust it that it isn’t compromised without a doubt, because with this system you can basically create certificates to be any user in you network. The whole concept is based on concept that this anchor isn’t compromised. Perhaps it’s even a good idea to protect the system by an RBAC configuration that enforces a two-person-rule so a rogue employee can’t make it’s own certificates. Glenn Brunette wrote a nice example back in 2005 how to do this and he is even configuring it for a script we will use later on. Perhaps you should even use auditing of the system to the max.
Okay, for this tutorial i won’t go into that part. That’s to a part because i’m lazy, however it’s more about the fear that when i’m missing something in such a part it would be my fault ;)
Okay, let’s start with the tutorial.
The certificates
At first we have to create a Certificate Authority and a certificate for a host and a user.
Certificate Authority
At first we have to create our Certificate Authority (CA). This will be our anchor of trust. The configuration described in the rest of the document assumes, that when you are able to use the private key of the CA, you are authorised to give a user access to a system by signing the public key of a user or host.
Please keep the password you have just set in mind. You will need it every time when you sign a certificate request in order to create a certificate.
Server Certificates
Now we create the server certificate. This certificate will be used by the host to identify towards a client as being really the host the client wants to connect to. For the configuration i will show in this blog entry only one parameter is really important: The common name has to be equal to the hostname. It’s the red part in the following output.
Now we sign the certificate request. You will need the password for the private key of the CA here.
Now we have signed certificate for the host.
User Certificate
We have to do pretty much the same for our users. Important for this kind of certificate: The common name in the certificate has to be equal to the username of the user. Again it’s the red part in the following output.
We have to sign this certificate request as well. You will need the password for the private key of the CA here, again.
Okay, we have now the certificates we need. Of course other users need their own certificates as well as other hosts need their own certificate. But that should be obvious.
Assumption
I assume in the tutorial that a user junior exists on the client and the server. The user on the client could be named differently. However the username on the server has to be exactly the one as stated in the common name of the user certificate. In case there aren’t such users on your system, please create the necessary user accounts:
At first on server:
We repeat the same on the client.
Futhermore you have to ensureproper resolution of the host names. In this example i will just use /etc/hosts. So execute this on the server.
Now repeat the same on the client system
Distributing the keys and certificates
The keys and certificate we created are without use when we do not distribute them. I will to this with scp and use another already existing account on the system.
On the server we need the key file and the certificate for the common name server and the certificate for the CA.
On the client we need the key and the certificate for the common name junior
Configuring SSH
Now we have the certificates we need. Next step is the configuration of the ssh and sshd.
On the server
After the transfer of the keys and certificates by scp your home directory should look like this:
The next step is changing the PIN of the keystone of the root user.:
This password is needed whenever you want to access keys in the Solaris keystone.
However: As the sshd must be able to access the keystore automatically without user intervention, we put the pin in a file.
The access to keys and certificates is handled by the Solaris Key Management Framework. We need a policy file for ssh.
This command leads to a policy file:
Okay, essentially this file is telling you “Don’t do a validation of the certificate by using CRL (certificate revocation lists) or OCSP (Online certificate Status Protocol). Search for a matching issuer certificate (the certificate of the CA) in the key store for such certificates (which is a directory) and the mapping from cert to name is done with /lib/crypto/kmf_mapper_cn.so” kmf_mapper_cn.so is a simple mapper which maps a certificate to it’s value of the Common Name certificate.
Now we add a few lines of configuration to /etc/ssh/sshd_config. We can just append them by echo because they aren’t in the default sshd_config:
Okay, the meaning of this statements is quite straight forward: The store of the certificates of the trusted CA is in /etc/ssh/cert. It will trust any CA if they are placed here. The Key Management Policy Database is the file we just created and we will use the ssh policy in that file. The Hostkey should be taking out of the pkcs11 keystone. It’s the key with the label host and as i already wrote, as you need a password to access the keystore, the password is store in /etc/ssh/pinfile.
But how do we get the private key into the pkcs#11 keystone? That’s quite easy. You use the pktool to import the keys and the certificates.
Why do you need to enter two passwords? The first one is the password to access the key store. The second one is the password protecting the key. The second is stripped off while importing it.
Just one tip: The CA.pl puts the metadata of the certificate in front of the certificate. You can’t import it with this header. When you see something like that, you forgot to remove this header:
I just removed the stuff by using egrep:
Now you should be able to import the certificate:
That’s all for the moment on the server.
On the client
Your home directory should look like this when using the junior
We will do some steps as root first. Again we create a policy file for the Key Management Framework of Solaris and put the certificate of the certificate authority in a central directory.
Get back to the normal user privileges by leaving your root shell and change the password of the keystone for user junior:
Now we have to import the key and the certificate for the common name junior
Okay, that’s all on client.
Please note...
Please note that i din’t imported the host keys and certificates to the client machine or the user certificates and keys to the server machine. Just the certificate of the CA is on both server and it’s the piece of information that creates trust between both parties.
There could be hundreds or thousands of servers. As long as you have a certificate with a username in it and there is a user account with that name on the system (locally or by LDAP for example), you can log in to the system with your certificate on your client without a question for a password. This has an important implication. The user junior on server A and the user junior on server B has to be same person when both trust the same certificate authority. Otherwise the person junior on server B could access the account junior on server A and vice versa with just the certificate. But that is pretty obvious. You can solve this by separate CA for each server or just giving separate account names.
Testing
I’m not a fan of testing an ssh configuration just by kicking the ssh-service of SMF. So i will start the sshd with a different port number and a vastly increased debug level:
Important to know … sshd terminates after one successful or unsuccessful attempt to log in. You have to restart it afterwards by executing the command again.
Right after startup you should see something like that:
As soon you see Server listening on :: port 2222. you are ready to test.
Now try to log into my server with the X.509:
It’s a rather complex and long command line. However it tells ssh a lot of import information. You know most of the statements. We just added the satement IdentityFile By using this, you really enable the x.509 certificate based authentication (when you forget it, you will use password authentication in this session).
You should see in the client’s debug output the check for the host certificate.
Back on the server you should see something like that in the debugging output of the sshd:
At the end of it all you should see a nice shell on your system.
Neat works as designed.
Cleaning up
Of course it’s a little bit cumbersome to type in all this stuff for each login into the system.
If you prefer to type in your key store password every time you log in (as i do), just leave out the ;pinfile=/export/home/junior/.ssh/pinfile part and of course don’t put the PIN into the file:
Afterwards you can log into the other server with public key authentication.