
SSH Key Management: Moving Beyond Password Authentication
Explore SSH key management, certificates, and Vault integration to secure access without passwords.
Static SSH keys create a vulnerability known as key sprawl. When a key is compromised or an employee leaves, administrators must manually locate and remove that key from ~/.ssh/authorized_keys on every server. This manual friction often leads to stale keys lingering on decommissioned servers, creating a permanent attack surface that is operationally impossible to clean at scale.
The mechanism to solve this is the SSH Certificate Authority (CA). Instead of distributing individual public keys, you distribute a single CA public key to all servers. When a user needs access, they present a certificate signed by this CA. The server verifies the signature against the CA key and checks the certificate's metadata, such as expiration time and allowed principals (usernames). This shifts the trust model from "trust this specific key blob" to "trust this authority to issue valid identities."
The Static Key Failure Mechanism
The core failure of the traditional SSH model lies in its static nature. The mechanism relies on the authorized_keys file, which acts as a flat, unstructured database of public keys. While revocation is technically possible via manual deletion, there is no built-in mechanism for it. In modern infrastructure, where hosts are ephemeral and scale dynamically, maintaining the integrity of these files becomes operationally impossible.
When a key is compromised, the "key sprawl" problem manifests immediately. An administrator must search every host for the specific key fingerprint. If the infrastructure spans thousands of nodes, this manual intervention is prone to error and delay. Furthermore, if an employee departs, their keys often remain on servers they no longer need to access because the cleanup process is tedious. This creates a permanent attack surface where stale credentials linger indefinitely.
The contrast between the static authorized_keys mechanism and the dynamic nature of modern infrastructure is stark. Static keys assume a stable environment where users and hosts rarely change. Dynamic infrastructure assumes constant flux. The friction required to update static keys in a high-churn environment leads to security debt, as administrators often choose to leave compromised or unnecessary keys in place rather than perform the arduous task of removal.
The CA Mechanism
The solution to key sprawl is the SSH Certificate Authority (CA) mechanism. Instead of distributing individual public keys, you distribute a single CA public key to all servers. When a user needs access, they present a certificate signed by this CA. The server verifies the signature against the CA key and checks the certificate's metadata, such as expiration time and allowed principals (usernames).
At the wire protocol level, an SSH certificate is not just a public key with a signature attached; it is a distinct data structure that includes extensions. When you generate a certificate using ssh-keygen -s, the tool creates a blob containing the public key, the signer's identity, the validity period (notBefore, notAfter), and critical extensions like critical options and extensions.
For example, a certificate might include the extension permitopen="localhost:8080", which restricts port forwarding capabilities strictly to the local machine, regardless of what the user tries to configure in their client. The server's sshd_config must have the TrustedUserCAKeys directive pointing to the CA public key file used for verification. When the connection attempt arrives, sshd parses the certificate, verifies the cryptographic signature using the CA key, checks the current time against the notAfter timestamp, and validates that the requested username matches one of the principals listed in the certificate.
This mechanism allows for immediate revocation. To revoke a user's access, you simply rotate the CA key pair. Since all valid certificates are signed by the old CA, they instantly become invalid on all servers once the new CA is deployed. There is no need to touch individual servers. The OpenSSH implementation treats certificates as first-class citizens, handling them transparently during the key exchange phase of the SSH handshake.
Dynamic Provisioning with Vault
While SSH CAs solve the revocation problem, they still require a process for generating and distributing keys. This is where HashiCorp Vault integrates to automate the lifecycle. The Vault SSH Secrets Engine acts as the CA, but it decouples the key generation from the key storage.
In a typical workflow, a developer authenticates to the system (e.g., via OIDC from GitHub or Okta). The Vault agent, running on the developer's machine or in a CI pipeline, requests a short-lived SSH certificate. The request includes the public key and the desired principals. Vault validates the external identity against its internal policies. If approved, Vault signs the key using its internal CA key and returns the certificate to the client.
The client then configures their SSH agent with this certificate. The private key remains ephemeral or is stored in a secure enclave, while the certificate is presented to the target server. The certificate typically has a TTL of a few hours. Once the session ends or the TTL expires, the certificate is useless. This eliminates the risk of a long-term private key being stolen from a disk or a laptop.
# Example: Requesting a certificate from Vault
vault write ssh/sign/role-name \
key=devops-engineer \
public_key=@/path/to/id_ed25519.pub \
ttl=1h \
roles="dev-team"The response contains the certificate blob. The developer adds this to their ssh-agent using ssh-add -s. The ssh-agent then handles the presentation of this certificate during the SSH handshake, ensuring the server sees a valid, time-bound identity without the user ever managing a private key file.
Operational Enforcement and Bastion Architecture
Even with certificates, the network topology matters. A "bastion host" or jump box architecture is often used to centralize access. However, a simple bastion host that just forwards TCP connections does not enforce policy; it just relays packets. A more robust approach uses a proxy like Teleport or a hardened bastion that acts as the SSH CA endpoint itself.
In this model, the user connects to the proxy, which handles authentication, authorization, and logging. The proxy then establishes the connection to the target server on behalf of the user. This ensures that the target server only ever sees the proxy's identity, not the user's. The proxy can enforce granular policies, such as requiring MFA for access to production databases, or recording session video for compliance.
The mechanism here relies on the proxy holding the CA private key. It issues certificates to users on the fly based on their session context. If a user attempts to access a server they are not authorized for, the proxy denies the certificate request before the packet ever leaves the network perimeter. This creates a "zero trust" boundary where the network is not trusted, and every hop requires verification.
The Tradeoff
Adopting SSH certificates and centralized CA management introduces complexity. You must manage the CA key securely, often requiring it to be stored in a HSM or a highly restricted secret store. You also need to ensure that all servers in your fleet are updated to support the certificate features, though OpenSSH has supported this since version 6.5.
There is also a dependency on the availability of the CA. If the CA is offline, you cannot issue new certificates, and existing certificates will eventually expire. For high-availability setups, you must run a redundant CA cluster with a shared secret store. This is a significant operational overhead compared to the "generate and copy" method of static keys, but the security return on investment is substantial. The ability to revoke access globally in seconds, combined with the elimination of long-lived private keys, makes this the only viable path for modern DevSecOps environments.
Ultimately, the shift from static keys to certificate-based authentication is a shift from managing secrets to managing identity. It moves the complexity from the endpoints (servers) to the control plane (CA/Vault), allowing for automated, auditable, and secure access to infrastructure at scale.
Common Pitfalls
Implementing SSH certificates introduces specific risks that must be managed proactively.
- CA Key Compromise: If the CA private key is stolen, an attacker can issue valid certificates for any user. This necessitates strict HSM protection or hardware security modules for the CA key storage, as well as rigorous access controls around the key management system.
- Clock Skew Issues: SSH certificates rely heavily on accurate timestamps for validity periods (
notBefore,notAfter). If the time on the issuing server, the target host, or the client drifts significantly due to NTP issues, valid certificates may be rejected, causing widespread access failures. - Legacy Client Incompatibility: Older SSH clients or servers may not support the certificate extensions or the specific signature algorithms required by modern CAs. This can lead to silent failures or fallback to insecure methods if not explicitly configured to fail closed.
Practical Takeaways
- Centralize Authority: Move away from distributing public keys to
authorized_keysand adopt a centralized CA or Vault-based signing service. - Enforce Short Lifespans: Configure certificates with short TTLs (e.g., 1 hour) to limit the window of opportunity for attackers using stolen credentials.
- Automate Lifecycle: Integrate certificate signing into your CI/CD pipelines and identity providers (OIDC) to ensure keys are generated and rotated automatically without human intervention.
FAQ
Q: Can I still use my existing SSH keys? A: Yes, you can generate a key pair and use it to request a certificate from the CA. The private key remains on your machine, but it is used only to sign the certificate request, not to authenticate directly.
Q: How do I revoke access if a laptop is lost? A: If the laptop is lost, you simply revoke the user's access by rotating the CA key or removing the user's principal from the CA policy. All certificates issued to that user become invalid immediately across the entire fleet.
Q: Does Vault replace the need for a Bastion Host? A: Vault automates the issuance of credentials, but it does not replace the network topology. You typically use Vault to issue certificates, which are then consumed by a proxy like Teleport or a Bastion host that enforces the actual network policies and logs sessions.
Conclusion
The transition from static SSH keys to a certificate-based model managed by a centralized authority represents a fundamental architectural shift in infrastructure security. By replacing the brittle "key sprawl" of static authorized_keys files with short-lived, signed certificates, organizations can achieve near-instantaneous revocation and granular policy enforcement. Tools like HashiCorp Vault and Teleport automate the lifecycle of these identities, ensuring that access is always time-bound and context-aware. While the operational complexity increases, the reduction in attack surface and the ability to enforce zero-trust principles make this approach essential for modern, scalable DevSecOps environments.
Related posts
The Role of Identity in DevSecOps: Integrating Security into the Pipeline
An examination of identity management within DevSecOps to ensure secure CI/CD pipelines through code signing and secure security integration.
SBOMs and Identity: From Inventory to Trust
An examination of Software Bills of Materials (SBOM) and identity mechanisms like SLSA and cosign for strengthening supply chain security.
Kubernetes RBAC and Service Account Security
An examination of Kubernetes RBAC and service account security strategies to enhance cluster protection using Kyverno and pod security policies.