If I were a gambling man, I would put my entire Christmas bonus on the fact that, should I gather 100 PKI experts in a room and said the words, “digital certificate,” 70 percent of them would automatically assume I was talking about X.509 digital certificates. This makes sense – X.509 (also called SSL/TLS certificates) are talked about ad nauseum in the PKI world. Of course, X.509 certificates aren’t the only kind of digital certificate out there – there is also the less-talked about SSH certificate! X.509 certificates facilitate identity verification in browser-to-server interactions, whereas SSH certificates are used for authenticating identities in communications between a shell (terminal) and Linux servers.
It’s common to encounter misconceptions that SSH certificates are identical to or interchangeable with X.509 certificates, but this is simply incorrect. This blog will concisely explore the nature of SSH certificates, why you ought to be using them, and the fundamental differences that set them apart from X.509 certificates.
We’ve written extensively about SSH certificates in the past, but we figure that the topic is so important that it warrants writing about it even more – that said, here is a quick overview of what SSH certificates are and how they work.
When you decode an SSH certificate, it’s essentially a structure holding a public key, a name, and sometimes extra details like an expiration date and specific permissions. SSH certificates are quite similar to X.509 certificates, but they just have fewer attributes.
Using an SSH certificate is the most secure method for SSH access; however, its usage isn’t as widespread as you might think, possibly because of the simple and sad fact that many developers are unaware of them. Additionally, SSH certificates demand more initial effort compared to the standard SSH key method, which tends to deter people from using them. But the advantages that SSH certificates offer (particularly for managing numerous users, hosts, and keys) make the initial setup more than worthwhile.
Even though OpenSSH introduced SSH certificate-based authentication in 2010, the majority of people still rely on passwords or public keys for SSH authentication.
The use of passwords for SSH authentication is often criticized due to the human tendency to choose weak, easily guessable passwords, making them susceptible to hacking. Moreover, during the initiation of an SSH connection, passwords are sent directly to the server, leaving them open to brute-force attacks.
Public key authentication for SSH offers a more secure option than passwords, but it’s not without its potential for misuse either. In this system, both clients and servers must possess their respective public and private key pairs. When a client attempts to establish an SSH connection with a server, two critical steps occur:
Firstly, the client checks if the server’s public key is present in its known_hosts
file to verify the server’s trustworthiness. If the server’s public key is unrecognized, an error occurs, indicating that the server’s authenticity cannot be established, and it asks whether to proceed with the connection anyway:
The authenticity of host 'xxx' can't be established.
RSA key fingerprint is SHA256:kfcwi9X8T4nMRw1OM0xDXETGcqjU26/zbM+KqNB6CKw.
Are you sure you want to continue connecting (yes/no)?
In such a scenario, the ideal action is for the user to verify the key fingerprint with the server administrator. This step is crucial because there is a possibility that an attacker could have linked a widely-trusted IP address to a malicious machine. Despite this, in practice, many users opt for the simpler route and simply enter, “yes.” By doing so, a connection to the server is formed without proper authentication, and the server’s public key gets permanently saved in the client’s known_hosts
file. This highlights a fundamental weakness of SSH key authentication – it promotes the “trust on first use” (TOFU) anti-pattern. And much like the food, TOFU is incredibly overrated.
Secondly, the server attempts to authenticate the user by verifying if the user’s public key is in its authorized_keys
file. Team members commonly submit their public key to an administrator to be added to the authorized_keys
file on each necessary server – but what if there are more than tens of servers where these keys need to be deployed? This introduces the second problem with SSH key authentication – managing keys can become awfully burdensome, inefficient, and unmanageable for larger organizations. Furthermore, the fact that keys don’t have an expiry date exposes systems to security risks. For instance, when an employee leaves a company, their public key should be removed from all servers; however, in reality, this often doesn’t happen. These vulnerable key connections can remain undetected for extended periods of time, leaving the system open to illicit access. For example, Cisco had an issue where an ex-employee deleted hundreds of VMs after being let go.
Various commercial and open-source solutions aim to address the issue of key management. Their core concept is to manage keys via their service, supposedly ensuring that, when a key is deleted, it is removed from all associated servers; however, this approach has its share of risks, as the service itself could become a singular point of failure. If an attacker gains control of this service, they could potentially access all your servers! As such, in a worst-case scenario, losing access to this service means losing access to all your servers as well.
SSH certificate-based authentication functions similarly to X.509 certificates, yet it has a much more straightforward setup. This method ensures mutual authentication between clients and hosts, thereby eliminating the TOFU issue.
Initially, you establish an SSH CA server (or an “online CA”), which contains two SSH CA key pairs – one host CA key pair for signing and verifying host machine certificates, and a user CA key pair for client certificates. In SSH terminology, the term CA (certificate authority) is often used to refer to both the signing key pairs and the SSH CA server itself. The more you know!
Having two separate CA key pairs is considered the best practice to minimize the risk of attacks. In case a private key gets compromised, you only need to reissue certificates for either your hosts or users, not both simultaneously.
Once the host CA and user CA key pairs are created, configure all host machines to trust certificates signed by the user CA’s public key. Similarly, all clients should trust certificates signed by the host CA’s public key.
To issue certificates to host machines, generate public-private key pairs for each server and sign them using the host CA keys. For client (user) certificates, generate key pairs for each client and sign them with the user CA keys. Ideally, issuing user certificates should be an automated process; for instance, you might set up a system like EZSSH where users receive automatically-signed certificates upon authenticating with your organization’s identity provider.
When a client attempts to connect to a host, it presents its certificate and the host reciprocates. Host servers grant access only to clients with trusted certificates, and clients can be confident that they are connecting to a verified host.
Beyond removing the tedious process of key management and the TOFU problem, SSH certificate authentication also provides capabilities for detailed access control:
1) Certificates have expiration dates. Issuing short-lived certificates reduces the danger of unused compromised keys remaining active. For instance, if a developer leaves your organization without their access being revoked, their certificate will automatically expire after a set time, thereby revoking their access.
2) Certificates are designated for specific users (principals). This feature enables the implementation of role-based access control, ensuring that users have access permissions appropriate to their roles.
3) Certificates can include specific SSH restrictions, like disallowing PTY (pseudo-terminal) allocation or port forwarding, adding an extra layer of security and control over user actions.
If this is of interest to you and you want to go in-depth on how to set up SSH certificates by yourself, check out our blog on how to create SSH certificates on your own!
Now that we have a clear understanding of SSH certificates and their application, let’s explore how they are distinct from X.509 certificates; specifically, let’s take a look at how they differ in their design, features, and implementation.
X.509 certificates are versatile and widely applicable – they’re employed in a variety of contexts, such as SSL/TLS, S/MIME, EAP-TLS, and even within the SSH protocol. Their use extends to web applications, databases, VPNs, Wi-Fi, digital signatures for document signing, and much more.
In contrast, SSH certificates are predominantly utilized for SSH access and authentication, highlighting the much narrower design of these certificates when compared to X.509 certificates.
In OpenSSH, SSH certificates are more straightforward and have only a handful of features. In contrast to the traditional X.509 certificates, which come with a multitude of options and intricate encoding rules, SSH certificates simply consist of public and private key pairs along with added identity and constraint information. Below is a comparison of what a decoded SSH user certificate and an X509 client certificate look like:
In the X.509 framework, CAs have their own certificates and can include intermediate certificate authorities, a process known as certificate chaining. SSH, on the other hand, doesn’t allow for such complexities. Its straightforward approach simplifies the configuration of SSH certificates and reduces potential security vulnerabilities.
Furthermore, SSH employs two types of certificate formats: the host certificate and the user certificate. Conversely, in X509, a certificate’s function is specified as either “server authentication” or “client authentication,” and a single X509 certificate can be configured to enable both.