
September 12, 2026
13 min read
By Kokil Thapa | Last reviewed: September 2026
Manual SSH key management breaks down once you pass a dozen servers and a handful of developers. Every new hire means copying public keys into authorized_keys on every box. Every departure means hunting stale keys nobody remembers. SSH Certificate Authorities for Scale solve this by replacing long-lived keys with short-lived, CA-signed certificates and a single trust anchor per host fleet. If you already run Ubuntu SSH server setup on production boxes, the jump to certificate-based auth is smaller than most teams expect.
What Are SSH Certificate Authorities and Why Do They Matter at Scale?
An SSH Certificate Authority is not a web TLS CA. It is a dedicated signing key pair used only to issue OpenSSH-format certificates. Those certificates bind a public key to a principal name, optional permissions, and an expiry time. Hosts and clients verify signatures against a pinned CA public key configured in sshd_config or ssh_config.
At small scale, static keys feel fine. I've seen the pain on real client projects once fleets grow. A law-firm portal might start on one VPS. Six months later there are staging, production, backup, and CI runners. Each developer laptop holds three key types. Someone rotates a deploy key and forgets the old one on a cron host. That is operational debt, not a security feature.
Certificate-based SSH centralizes trust. You configure each server once with TrustedUserCAKeys. After that, access changes happen at the CA layer. Issue a cert when someone joins. Stop issuing when they leave. Existing certs expire on their own. The model mirrors what you already know from PKI and certificate management basics, but the wire format and tooling are OpenSSH-native.
OpenSSH has supported certificates since version 5.4. Modern Ubuntu 22.04 and 24.04 images ship OpenSSH 8.x or 9.x, so the feature is already on your servers. You do not need third-party agents unless you want a full identity layer like Step CA for internal PKI.
How Do You Set Up an OpenSSH Certificate Authority for Production?
Start with a dedicated CA key pair that never lives on production servers. Store the private key offline or in a hardware-backed vault. The public key gets copied to every host and client that should trust your CA.
Generate the CA key pair
Use Ed25519 for new CAs. It is fast, small, and aligns with current SSH key type guidance.
# On a secure admin workstation — not a production box
ssh-keygen -t ed25519 -f ssh_user_ca -C "prod-user-ca-2026"
ssh-keygen -t ed25519 -f ssh_host_ca -C "prod-host-ca-2026"
# Restrict private keys immediately
chmod 0400 ssh_user_ca ssh_host_ca
Keep separate CAs for user certs and host certs. If one is compromised, blast radius stays bounded. This is the same separation principle you apply when splitting TLS issuance from code-signing keys.
Configure servers to trust the user CA
Copy the user CA public key to each server. Then point sshd at it.
# /etc/ssh/sshd_config.d/50-ca.conf
TrustedUserCAKeys /etc/ssh/ca/user_ca.pub
AuthorizedKeysFile none
# Optional: require principals mapping
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
Setting AuthorizedKeysFile none disables static key files entirely. That is the right end state for scale, but migrate gradually. Run CA auth alongside existing keys until your pipeline is stable. Pair this with the checks in harden SSH on Linux servers — certificates are not a substitute for sensible PermitRootLogin and network controls.
Sign a user certificate
A user cert wraps an existing public key. The CA signature proves identity for a limited time.
# Developer generates a normal key locally
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_prod
# CA admin signs it — valid 8 hours, principal = unix username
ssh-keygen -s ssh_user_ca \
-I "kokil-laptop-2026-09" \
-n kokil \
-V +8h \
~/.ssh/id_ed25519_prod.pub
# Output: id_ed25519_prod-cert.pub (used automatically by ssh)
The -V flag sets validity window. Short TTLs limit exposure if a laptop is stolen. Eight to twenty-four hours works for human access. CI jobs may use five to fifteen minutes. The -I field is a certificate ID useful in logs and revocation lists.
Sign host certificates
Host certs let clients trust server identity without StrictHostKeyChecking accept-new gymnastics. Sign each host key at provisioning time.
# On the target server
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
# On CA workstation
ssh-keygen -s ssh_host_ca \
-I "web-prod-01.example.com" \
-h \
-n web-prod-01.example.com,10.0.1.15 \
-V +52w \
/path/to/ssh_host_ed25519_key.pub
Deploy the resulting -cert.pub beside the host key. Clients configure @cert-authority entries in known_hosts or use KnownHostsCommand to fetch trusted host certs dynamically.
How Does SSH CA Authentication Compare to Manual Key Management?
Teams delay CA adoption because static keys still work. The trade-off becomes obvious once you count operational steps per access change.
| Criteria | Manual authorized_keys | SSH CA at scale |
|---|---|---|
| Onboarding | Append key to every server | Issue one cert; servers already trust CA |
| Offboarding | Remove key from N hosts; easy to miss one | Stop signing; existing certs expire |
| Key lifetime | Years unless rotated | Hours or days by policy |
| Audit trail | Scattered files, little metadata | Cert ID, principals, validity in CA logs |
| Host verification | Manual known_hosts updates | Host certs + CA trust line |
| Initial setup cost | Low | Moderate — CA ops + sshd rollout |
Manual keys win for a single VPS and one developer. CA wins everywhere else. On Deployer-managed fleets I maintain — shared EC2 hosts running Laravel legal-tech portals — the per-server key copy step was the first thing we automated away.
How Do You Automate Certificate Issuance for a Growing Team?
Manual ssh-keygen -s commands do not scale past five people. Production systems wrap the CA in an API tied to your identity provider. The flow is predictable.
- Engineer authenticates to SSO — Okta, Google Workspace, or Azure AD.
- Access portal verifies group membership and requests a cert from the CA service.
- CA signs the submitted public key with appropriate principals and TTL.
- Engineer downloads the cert and connects with normal
ssh user@host. - Cert expires; user repeats login tomorrow.
Small teams can script this with a bastion and sudo-gated signing. Larger teams adopt Step CA or cloud identity extensions. HashiCorp Vault's SSH secrets engine is another option if you already run Vault for application secrets.
Map SSO groups to SSH principals explicitly. A developer might get principal deploy on staging only. Production access might require a break-glass group with one-hour certs. Document these mappings the same way you document SSH key-only auth setup policies today.
CI and deploy pipelines
GitLab CI, GitHub Actions, and Deployer need machine access too. Issue pipeline certs with very short TTL and narrow principals. Store the signing request behind your CI secret store. Never embed CA private keys in repository variables.
On projects using GitLab CI plus Deployer 7, I issue a five-minute cert at the start of the deploy job. The job connects, runs dep deploy production, and the cert expires before the runner is recycled. That beats long-lived deploy keys sitting in authorized_keys for years.
Principals file for role separation
Use AuthorizedPrincipalsFile to decouple Unix usernames from access roles.
# /etc/ssh/auth_principals/deploy
deploy
ci-readonly
# Sign with: ssh-keygen -s ssh_user_ca -n deploy,id_ed25519_prod.pub
One Unix account can accept multiple principals. Different teams receive different principal sets without creating shared login accounts. Avoid shared accounts entirely where possible.
What Certificate Extensions and Policies Should You Enforce?
OpenSSH certificates carry critical options that static keys cannot express cleanly. Use them.
- force-command — restrict a cert to a single command, useful for backup scripts or
gitdeploy users. - source-address — bind cert use to office or VPN CIDR ranges.
- permit-X11-forwarding — disable unless explicitly needed.
- permit-agent-forwarding — default off; see SSH agent forwarding risks.
Example: sign a read-only monitoring key locked to one command and one source network.
ssh-keygen -s ssh_user_ca \
-I "monitoring-readonly" \
-n monitoring \
-V +24h \
-O force-command=/usr/local/bin/readonly-check.sh \
-O source-address=10.10.0.0/16 \
-O clear-permit-agent-forwarding \
monitoring_id_ed25519.pub
These flags encode policy in the credential itself. Even if someone exfiltrates the private key, the cert cannot open an interactive shell from a home ISP. That is defense in depth beyond what fail2ban and port hardening alone provide.
Align TTL policy with your broader rotation practice described in automate certificate rotation. SSH user certs are cheap to reissue. Err toward shorter lifetimes.
How Do You Handle Revocation and Host Trust at Scale?
Short TTLs reduce revocation urgency but do not eliminate it. A terminated employee with a valid eight-hour cert still has eight hours of access. You need a kill switch.
Key Revocation Lists
OpenSSH supports KRL — a compact binary revocation list generated from compromised cert IDs or raw public keys.
# Revoke by certificate serial / key
ssh-keygen -k -f /etc/ssh/revoked.krl -s ssh_user_ca -I "kokil-laptop-2026-09"
# sshd_config
RevokedKeys /etc/ssh/revoked.krl
Distribute KRL updates via configuration management — Ansible, cloud-init, or your existing Linux system administration playbook. Propagation delay is your revocation window. Pair KRL with very short TTL for defense in depth.
Host certificate rotation
Host certs typically last longer — thirty to fifty-two weeks. Track expiry the same way you track TLS cert expiry. A host cert expiring silently triggers the dreaded host key changed warning for every engineer. Add monitoring alerts thirty days before expiry. The lifecycle patterns in certificate lifecycle management apply directly.
For client-side trust at scale, replace static known_hosts with a CA line:
# ~/.ssh/known_hosts or ssh_config snippet
@cert-authority *.prod.example.com ssh-ed25519 AAAA...user_ca_pub...
Only hosts presenting a valid cert signed by your host CA pass verification. This closes MITM gaps that plague teams using SSH tunneling across jump hosts.
What Are Common Mistakes When Rolling Out SSH CAs?
Most failures are operational, not cryptographic.
CA private key on a server. If the CA key lives on a box that SSH users can reach, you have rebuilt centralized keys with extra steps. Keep signing offline or in a dedicated secrets service.
Skipping host certificates. Teams adopt user certs but ignore host certs. Engineers still click through host key warnings. Sign host keys during provisioning and automate renewal.
Principal sprawl without documentation. Ad-hoc principal names become as messy as ad-hoc Unix groups. Maintain a table mapping SSO groups to principals and permitted servers.
No logging. Enable verbose auth logging during rollout. Ship sshd logs to your central store. Certificate IDs in logs tell you which laptop accessed which box.
Mixing CA and static keys forever. Transitional dual mode is fine for a month. Permanent dual mode doubles audit surface. Set a cutoff date to disable AuthorizedKeysFile.
Generate strong CA passphrases with a proper entropy source. A local password generator beats keyboard mashing for offline CA keys you type once into a hardware token.
How Does SSH CA Fit Into Broader Supply Chain and Access Patterns?
SSH certs complement — not replace — other trust mechanisms. Developers can still sign Git commits with SSH keys using a separate key from their access cert. The signing key never needs shell access to production.
For Nepal-based teams on budget infrastructure, CA auth reduces support tickets. Small agencies charge Rs 2,000–5,000 (~USD 15–37) per manual key rotation ticket. Automating access pays for itself quickly. The same ops discipline supports trek booking platforms and legal-tech portals where uptime matters during peak season.
If you lack staff to run Step CA, start minimal. One Ed25519 CA key, an Ansible task to push TrustedUserCAKeys, and a signed shell script on a bastion beats unmanaged keys on forty servers. Expand when pain returns.
Official reference: the OpenSSH certificate format is documented in the ssh-keygen manual and the broader sshd_config specification. Read both before you disable static keys in production.
Key Takeaways
- Deploy separate user and host CAs; never store CA private keys on production servers.
- Configure
TrustedUserCAKeysfleet-wide and migrate offauthorized_keysonce signing is automated. - Keep user cert TTL under twenty-four hours; CI certs under fifteen minutes.
- Enforce policy via certificate extensions — force-command, source-address, no agent forwarding.
- Combine short TTL with KRL distribution for fast revocation when someone leaves.
- Sign host certificates and use
@cert-authorityin client config to eliminate MITM host warnings.
People Also Ask
Do I need special software to run an SSH CA?
No. OpenSSH ships everything required. You generate a CA key with ssh-keygen, sign certificates with ssh-keygen -s, and configure servers with TrustedUserCAKeys. Tools like Step CA add API and SSO layers but are optional for smaller fleets.
Can SSH certificates replace VPN access?
Often partially. Short-lived certs with source-address restrictions provide strong server authentication without a full VPN client. Many teams use a bastion plus SSH certs instead of site-to-site VPN for admin access. Application-level network segmentation still matters.
What key type should the CA use?
Ed25519 is the default choice in 2026. It produces small certs and fast verification. RSA CA keys remain valid for legacy compatibility but add size without benefit for greenfield rollouts.
How is an SSH CA different from TLS certificate authorities?
Both use PKI concepts — a root of trust, signed credentials, expiry. SSH certs authenticate shell access and are consumed by OpenSSH directly. TLS certs authenticate HTTPS and follow X.509. Different formats, same operational mindset.
Build Access That Scales With Your Fleet
SSH Certificate Authorities for Scale turn access management from a file-editing chore into a policy-driven pipeline. Start with one CA, one Ansible role, and eight-hour user certs. Add host certs, automated signing, and KRL distribution as your server count grows. The upfront setup pays back the first time someone leaves and you do not grep authorized_keys at midnight.
Need help hardening SSH across Ubuntu fleets, Laravel deploy pipelines, or mixed staging and production environments? See support and maintenance services or contact us to plan a rollout that fits your team size and budget.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

