The certificate model of authentication used by SSH is a variation of the public key authentication method. With certificates, each user's (or host's) public key is signed by another key, known as the certificate authority (CA). The same CA can be used to sign multiple user or host keys. The user or the host can then trust a single CA instead of having to trust each individual user/host key. Because this is a change in the authentication model, implementing certificates requires changes on both the client and the server side.
Also, do note that the certificates used by SSL (the ones generated by openssl
) are different from the ones used by SSH. This topic is explained by these QAs at the Security SE: What is the difference between SSL & SSH?, Converting keys between OpenSSL and OpenSSH.
Now, since the question is about how a client could connect to a server using an SSH certificate, let's look at that approach. The manual page for ssh-keygen
has some relevant information:
ssh-keygen
supports signing of keys to produce certificates that may
be used for user or host authentication. Certificates consist of a
public key, some identity information, zero or more principal (user or
host) names and a set of options that are signed by a Certification
Authority (CA) key. Clients or servers may then trust only the CA key
and verify its signature on a certificate rather than trusting many
user/host keys. Note that OpenSSH certificates are a different, and
much simpler, format to the X.509 certificates used in ssl
(8).
ssh-keygen
supports two types of certificates: user and host. User
certificates authenticate users to servers, whereas host certificates
authenticate server hosts to users. To generate a user certificate:
$ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
The resultant certificate will be placed in
/path/to/user_key-cert.pub
.
A host certificate requires the -h
option:
$ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
The host certificate will be output to /path/to/host_key-cert.pub
.
The first thing we'll need here is a CA key. A CA key is a regular private-public key pair, so let's generate one as usual:
ssh-keygen -t rsa -f ca
The -f ca
option simply specifies the output filename as 'ca'. This results in the two files being generated - ca (private key) and ca.pub (public key).
Next, we'll sign our user key with the CA's private key (following the example from the manual):
ssh-keygen -s path/to/ca -I myuser@myhost -n myuser ~/.ssh/id_rsa.pub
This will generate a new file named ~/.ssh/id_rsa-cert.pub
which contains the SSH certificate. The -s
option specifies the path to the CA private key, the -I
option specifies an identifier that is logged at the server-side, and the -n
option specifies the principal (username). The contents of the certificate can be verified by running ssh-keygen -L -f ~/.ssh/id_rsa-cert.pub
.
At this point, you're free to edit your configuration file (~/.ssh/config) and include the CertificateFile
directive to point to the newly generated certificate. As the manual indicates, the IdentityFile
directive must also be specified along with it to identify the corresponding private key.
The last thing to do is to tell the server to trust your CA certificate. You'll need to copy over the public key of the CA certificate to the target server. This is done by editing the /etc/ssh/sshd_config
file and specifying the TrustedUserCAKeys
directive:
TrustedUserCAKeys /path/to/ca.pub
Once that is done, restart the SSH daemon on the server. On my CentOS system, this is done by running systemctl restart sshd
. After that, you will be able to log in to the system using your certificate. Tracing your ssh
connection using the verbose flag (-v
) will show the certificate being offered to the server and the server accepting it.
One last thing to note here is that any user key signed with the same CA key will now be trusted by the target server. Access to the CA keys must be controlled in any practical scenario. There are also directives such as AuthorizedPrincipalsFile
that can be used to limit the access from the server side. See the manual for sshd_config for more details. On the client side, the certificates can also be created with tighter specifications. See the manual for ssh-keygen for those details.