QCecuring - Enterprise Security Solutions

SSH Certificate-based Authentication

Ayush Kumar Rai

Key Takeaways

  • SSH certificates are signed by a CA and have validity periods — they expire automatically, unlike static SSH keys
  • Servers trust the CA, not individual user keys. No more managing authorized_keys on every server.
  • Principals (roles) in the certificate control which users the certificate can authenticate as — centralized access control
  • Short-lived certificates (8-24 hours) tied to SSO sessions eliminate the need for key rotation entirely

SSH certificate-based authentication replaces static authorized_keys with certificates signed by a trusted SSH Certificate Authority. Instead of deploying each user’s public key to every server, you configure servers to trust a single CA public key. Users present a certificate (their public key signed by the CA) that proves their identity, specifies which server accounts they can access (principals), and has an expiry time. When the certificate expires, access ends automatically — no key removal needed.


Why it matters

  • Automatic expiry — certificates have a valid_before timestamp. After expiry, they’re rejected. No manual key removal, no orphaned access, no forgotten keys granting access years later.
  • Eliminates authorized_keys — servers trust the CA, not individual keys. Adding a new user doesn’t require touching any server. Removing a user means not issuing new certificates — existing ones expire naturally.
  • Centralized access control — the CA decides who gets certificates with which principals (roles). Access policy lives in one place, not scattered across thousands of authorized_keys files.
  • Audit trail — the CA logs every certificate issued: who, when, which principals, which servers, what validity period. Complete access audit without parsing server logs.
  • Scales to thousands of servers — adding 100 new servers requires configuring them to trust the CA (one line in sshd_config). No per-user key deployment to each server.

How it works

  1. CA setup — generate an SSH CA key pair. The CA private key signs user certificates. The CA public key is trusted by all servers.
  2. Server configuration — add TrustedUserCAKeys /etc/ssh/ca.pub to sshd_config. The server now accepts any certificate signed by this CA.
  3. User requests certificate — user authenticates to the CA (via SSO, LDAP, or other identity provider) and presents their SSH public key.
  4. CA issues certificate — CA signs the user’s public key with: identity (username), principals (server accounts they can access), validity period (e.g., 8 hours), and optional extensions/restrictions.
  5. User connects — SSH client presents both the certificate and the private key. Server verifies: CA signature valid, certificate not expired, principal matches target account.
  6. Certificate expires — after the validity period, the certificate is rejected. User must re-authenticate to the CA for a new certificate.

In real systems

Setting up SSH CA (manual):

# Generate CA key pair
ssh-keygen -t ed25519 -f /etc/ssh/ca_key -C "SSH CA"

# Sign a user's public key (issue certificate)
ssh-keygen -s /etc/ssh/ca_key \
  -I "alice@example.com" \       # Identity (for logging)
  -n "ubuntu,deploy" \           # Principals (allowed usernames on servers)
  -V "+8h" \                     # Valid for 8 hours
  -z 1001 \                      # Serial number
  ~/.ssh/id_ed25519.pub
# Produces: ~/.ssh/id_ed25519-cert.pub

# View certificate details
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
# Shows: Type, Public key, Signing CA, Key ID, Serial, Valid, Principals, Extensions

Server configuration:

# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca.pub          # Trust this CA
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u  # Map principals to users

# /etc/ssh/auth_principals/ubuntu
# Contains allowed principals for the 'ubuntu' account:
deploy
admin
ubuntu

Smallstep (automated SSH CA):

# Install step-ca as SSH CA integrated with identity provider
step ca init --ssh

# User gets certificate via SSO
step ssh certificate alice@example.com ~/.ssh/id_ed25519 \
  --provisioner="Google" \
  --principal="ubuntu" \
  --principal="deploy"
# Opens browser for SSO authentication
# Returns 8-hour certificate tied to SSO session

# Automatic renewal while SSO session is valid
step ssh renew ~/.ssh/id_ed25519-cert.pub ~/.ssh/id_ed25519

Teleport (full SSH access platform):

# User logs in via SSO
tsh login --proxy=teleport.example.com
# Receives short-lived SSH certificate (12 hours default)

# Connect to any server in the cluster
tsh ssh user@server-name
# Certificate presented automatically, verified against Teleport CA
# Access logged centrally with session recording

Host certificates (server identity):

# Sign the server's host key (eliminates TOFU/known_hosts problem)
ssh-keygen -s /etc/ssh/ca_key \
  -I "server01.example.com" \
  -h \                           # Host certificate (not user)
  -n "server01.example.com,10.0.1.5" \  # Hostnames/IPs
  -V "+52w" \                    # Valid for 1 year
  /etc/ssh/ssh_host_ed25519_key.pub

# Client trusts the CA for host verification
# ~/.ssh/known_hosts:
@cert-authority *.example.com ssh-ed25519 AAAA...ca-public-key...
# No more "The authenticity of host can't be established" prompts

Where it breaks

CA key compromise — if the SSH CA private key is stolen, the attacker can issue certificates for any user with any principals and any validity period. This is equivalent to having root access to every server that trusts the CA. The CA key must be stored in an HSM or at minimum on a highly secured, access-controlled system. Short certificate validity limits the damage window but doesn’t prevent it.

Clock skew — SSH certificate validation checks valid_after and valid_before against the server’s system clock. If the server’s clock is skewed (NTP not configured, VM clock drift), valid certificates may be rejected as “not yet valid” or “expired.” With 8-hour certificates, even 30 minutes of clock skew can cause authentication failures near the validity boundaries. Ensure NTP is configured and monitored on all SSH servers.

Principal mismatch — a user’s certificate has principals ["deploy", "ubuntu"] but they try to SSH as root. The server rejects the connection because root isn’t in the certificate’s principal list. This is working as designed (access control), but users accustomed to authorized_keys (which grants access to whatever user the key is placed under) find it confusing. Clear documentation of which principals map to which server accounts is essential.


Operational insight

SSH certificates fundamentally change the access model from “distributed trust” (each server decides who to trust via authorized_keys) to “centralized trust” (the CA decides, servers enforce). This is the same shift that happened in web PKI decades ago — and it brings the same benefits: scalability, auditability, and automatic expiry. The migration path from static keys to certificates doesn’t require a big bang. Start by issuing certificates alongside existing authorized_keys (both work simultaneously). Once all users have certificates, remove authorized_keys entries. The overlap period lets you validate the certificate infrastructure without risking lockouts.


Ready to Secure Your Enterprise?

Experience how our cryptographic solutions simplify, centralize, and automate identity management for your entire organization.

Stay ahead on cryptography & PKI

Get monthly insights on certificate management, post-quantum readiness, and enterprise security. No spam.

We respect your privacy. Unsubscribe anytime.