Back to Guides
SSHIntermediate

SSH Certificate Authority Setup

Create your own CA with native OpenSSH (no extra software)

12 min read
SSH Certificate Authority Setup: Create your own CA with native OpenSSH
TL;DR for SREs & Platform Engineers
  • What it is: An SSH CA is just a key pair—no special software required
  • Best practice: Separate CAs for users and hosts (security isolation)
  • Key command: ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca

Why use an SSH CA?

Eliminate SSH key sprawl across your infrastructure, make offboarding instant (revoke the CA trust instead of hunting down authorized_keys), and enable bastionless access patterns. Replace hundreds of static keys with one trust anchor.

1. What is an SSH Certificate Authority?

Here's the surprising part: an SSH CA is just a key pair.

No special software. No complex infrastructure. No certificate chain hierarchy. Just a key pair that you designate for signing. This is different from X.509 PKI where you typically need a full CA application or managed service—SSH certificates work with native OpenSSH out of the box.

┌─────────────────────────────────────────┐
│       SSH Certificate Authority         │
│                                         │
│  ┌─────────────┐    ┌─────────────┐     │
│  │ Private Key │    │ Public Key  │     │
│  │   (signs)   │    │  (verifies) │     │
│  └─────────────┘    └─────────────┘     │
│        │                   │            │
│        ▼                   ▼            │
│   Keep SECRET         Distribute to    │
│   (offline/HSM)      servers/clients   │
└─────────────────────────────────────────┘
The private key

Signs certificates. Guard it carefully—this is the crown jewel.

The public key

Verifies signatures. Distribute it everywhere trust is needed.

That's it. If you can generate an SSH key pair, you can create a CA.

2. One CA or Two? The Architecture Decision

Best practice: Separate CAs for users and hosts.

┌─────────────────┐         ┌─────────────────┐
│    User CA      │         │    Host CA      │
│                 │         │                 │
│ Signs: user     │         │ Signs: server   │
│ certificates    │         │ certificates    │
│                 │         │                 │
│ Trusted by:     │         │ Trusted by:     │
│ SERVERS         │         │ CLIENTS         │
└─────────────────┘         └─────────────────┘

Why separate CAs? (Threat model perspective)

Threat ScenarioSingle CA ImpactSeparate CAs Impact
User CA compromisedAttacker can impersonate servers AND usersAttacker can only create fake user certs
Host CA compromisedAttacker can impersonate servers AND usersAttacker can only create fake host certs
Audit trail"Which type of cert was signed?"Clear separation in logs
RotationMust rotate everything togetherRotate independently

When single CA is acceptable:

  • • Small environments (< 20 servers)
  • • Lab/development setups
  • • You understand and accept the risk

For production:

Two CAs. Always.

3. Creating the CA Key Pairs

On your CA host, create a dedicated directory and generate two key pairs:

Use a dedicated CA machine. Avoid running the CA on bastions, jump boxes, or developer laptops. The CA host should have minimal attack surface and restricted access.

mkdir -p /etc/ssh/ca
chmod 700 /etc/ssh/ca

User CA (signs user certificates):

ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca -C "user-ca@example.com"

Host CA (signs host certificates):

ssh-keygen -t ed25519 -f /etc/ssh/ca/host_ca -C "host-ca@example.com"

Flags explained:

FlagPurposeRecommendation
-t ed25519Key typeEd25519 is modern, fast, secure
-f <path>Output fileKeep CAs in dedicated directory
-C <comment>Comment fieldLabel clearly for identification

Output files:

/etc/ssh/ca/
├── user_ca          # Private key - PROTECT THIS
├── user_ca.pub      # Public key - distribute to servers
├── host_ca          # Private key - PROTECT THIS
└── host_ca.pub      # Public key - distribute to clients

Set a strong passphrase when prompted. This protects the CA if the file is stolen.

4. Protecting CA Private Keys

The CA private key is the crown jewel. If compromised, attackers can forge any certificate.

Protection levels (choose based on your risk tolerance):

Level 1: Passphrase + file permissions (minimum)
chmod 600 /etc/ssh/ca/user_ca
chmod 600 /etc/ssh/ca/host_ca
chown root:root /etc/ssh/ca/*

Good for: Development, small teams, low-risk environments

Level 2: Dedicated signing machine
  • • CA keys live on a single hardened server
  • • Network-isolated or tightly firewalled
  • • All signing requests go through this machine
  • • Audit logging on all signing operations

Good for: Production environments, compliance requirements

Level 3: Offline CA
  • • CA private key stored on air-gapped machine or USB
  • • Brought online only for signing
  • • Maximum security, minimum convenience

Good for: High-security environments, root CAs

Level 4: Hardware Security Module (HSM)
  • • CA key generated and stored in HSM
  • • Key never exists in extractable form
  • • Hardware-enforced access controls

Good for: Enterprise, financial services, regulated industries

Reality check: Most organizations land at Level 2. Level 1 is fine for getting started; move up as you scale.

Decision guideline: If you're unsure, start at Level 2 and plan a path to Level 3 for your root CAs. Level 1 is acceptable only for development environments.

5. CA Key Algorithm Choices

Ed25519 is recommended, but here are your options:

AlgorithmKey CommandProsCons
Ed25519-t ed25519Fast, secure, small keysNot on very old systems
ECDSA-t ecdsa -b 521Widely supportedLarger signatures
RSA-t rsa -b 4096Universal compatibilityLarge keys, slower

Check OpenSSH version:

ssh -V
# Ed25519 supported in OpenSSH 6.5+ (2014)

Recommendation: Ed25519 unless you have ancient systems (RHEL 6, etc.) that don't support it. If you need maximum compatibility, create both Ed25519 and RSA CAs.

FIPS/compliance note: If your organization requires FIPS 140-2 compliance and is RSA-only, mirror every Ed25519 CA with an RSA CA. Issue certs from both, letting clients negotiate what they support.

6. Distributing CA Public Keys

The public keys need to go to the right places:

User CA public key → Servers

Servers need to trust user certificates:

# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/user_ca.pub
Host CA public key → Clients

Clients need to trust host certificates:

# ~/.ssh/known_hosts
@cert-authority *.example.com ssh-ed25519 AAAA...

Distribution methods:

MethodBest ForNotes
Manual SCPSmall environmentsSimple but doesn't scale
Configuration managementMedium/largeAnsible, Puppet, Chef
Cloud-init / user-dataCloud VMsBake into instance launch
Image bakingContainers, AMIsInclude in base image

7. Signing Workflow

Now your CA is ready to sign certificates.

Sign a user certificate:

ssh-keygen -s /etc/ssh/ca/user_ca \       # Sign with User CA
  -I "username@example.com-$(date +%Y%m%d)" \  # Key ID for audit logs
  -n username,admin \                     # Allowed principals (usernames)
  -V +24h \                               # Valid for 24 hours
  /path/to/user_key.pub                   # User's public key to sign

Sign a host certificate:

ssh-keygen -s /etc/ssh/ca/host_ca \       # Sign with Host CA
  -I "server01.example.com-$(date +%Y%m%d)" \  # Key ID for audit
  -h \                                    # Mark as HOST certificate
  -n server01.example.com,server01,10.0.1.50 \ # Hostnames/IPs this cert is valid for
  -V +52w \                               # Valid for 52 weeks (1 year)
  /etc/ssh/ssh_host_ed25519_key.pub       # Server's host public key

The key difference: The -h flag marks it as a host certificate.

→ See SSH User Certificates for detailed user signing options.
→ See SSH Host Certificates for detailed host signing options.

8. Validity Period Strategy

How long should certificates be valid?

User certificates: Short

DurationUse Case
1-8 hoursInteractive users, workday access
24 hoursReasonable default
1 weekInfrequent access, vacation coverage
Never > 30 daysIf you need longer, reconsider your architecture

Short validity = compromised cert is useless quickly = no revocation infrastructure needed.

Incident response reality: If your mean time to detect a breach is measured in days, certificates longer than a week increase your blast radius. Match cert validity to your detection capability.

For auditors: Short-lived user certs combined with central logging can often satisfy revocation requirements in practice—certificates expire before traditional revocation would take effect.

Host certificates: Longer

DurationUse Case
1-4 weeksHigh-security, frequent rotation
3-6 monthsReasonable default
1 yearStable infrastructure, calendar-based renewal

Why longer is acceptable for hosts: Host keys are already long-lived, hosts don't "log in"—they just exist, and renewal requires server access (operational overhead).

9. Operational Procedures

For user certificates with short validity, you need an efficient signing process:

Option A: Manual signing (small scale)
# User sends public key
# Admin signs and returns certificate
ssh-keygen -s /etc/ssh/ca/user_ca -I "user-$(date +%Y%m%d)" -n user -V +24h user.pub
Option B: Self-service with approval (medium scale)
  • • User requests certificate through ticketing system
  • • Automated signing after approval
  • • Certificate returned via secure channel
Option C: Automated signing service (large scale)
  • • HashiCorp Vault SSH secrets engine
  • • smallstep step-ca
  • • Venafi SSH Protect
  • • Custom signing service with API

Recommended starting point: Option B for most teams. It balances security (approval workflow) with usability (self-service requests). Move to Option C when you hit 50+ users or need sub-hourly certificate validity.

Certificate renewal check:

# Check expiration
ssh-keygen -L -f /etc/ssh/ssh_host_ed25519_key-cert.pub | grep "Valid:"

# Example output:
# Valid: from 2025-01-14T00:00:00 to 2025-07-14T00:00:00

10. CA Key Rotation

Eventually, you'll need to rotate CA keys. Plan for this:

When to rotate:

  • • Suspected compromise
  • • Staff with CA access leaving
  • • Compliance requirements (annual rotation)
  • • Algorithm upgrades (RSA → Ed25519)

Rotation procedure:

1

Generate new CA key pair

ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca_2025 -C "user-ca-2025@example.com"
2

Distribute new CA public key alongside old

Servers trust both old and new user CAs temporarily

3

Start signing with new CA

All new certificates use new CA. Old certificates remain valid until expiration.

4

Remove old CA trust after transition period

Once all old certificates have expired, remove old CA from TrustedUserCAKeys

5

Securely destroy old CA private key

shred -u /etc/ssh/ca/user_ca_old

Transition period: Typically 2x your longest certificate validity. If host certs are 6 months, plan 12-month transition.

Note: User and Host CAs often have different rotation cadences. Document each separately in your runbooks—user CAs may rotate more frequently due to shorter cert lifetimes.

11. Audit and Logging

Track what gets signed:

Basic logging:

# Log every signing operation
ssh-keygen -s /etc/ssh/ca/user_ca ... 2>&1 | tee -a /var/log/ssh-ca-signing.log

Better: Structured signing script

#!/bin/bash
# sign-user-cert.sh
# Minimal example – adapt paths and logging for your environment

USER_KEY="$1"
PRINCIPALS="$2"
VALIDITY="${3:-+24h}"

TIMESTAMP=$(date -Iseconds)
KEY_ID="$(basename $USER_KEY .pub)-${TIMESTAMP}"

# Sign the certificate
ssh-keygen -s /etc/ssh/ca/user_ca \
  -I "$KEY_ID" \
  -n "$PRINCIPALS" \
  -V "$VALIDITY" \
  "$USER_KEY"

# Log the operation
echo "$TIMESTAMP | SIGN | $KEY_ID | principals=$PRINCIPALS | validity=$VALIDITY" >> /var/log/ssh-ca.log

What to log:

  • • Timestamp
  • • Key ID
  • • Principals granted
  • • Validity period
  • • Who requested the certificate
  • • Who approved (if applicable)

12. Quick Start Checklist

Ready to set up your SSH CA? Here's the condensed version:

Create CA directory
mkdir -p /etc/ssh/ca
chmod 700 /etc/ssh/ca
Generate User CA
ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca -C "user-ca@example.com"
chmod 600 /etc/ssh/ca/user_ca
Generate Host CA
ssh-keygen -t ed25519 -f /etc/ssh/ca/host_ca -C "host-ca@example.com"
chmod 600 /etc/ssh/ca/host_ca
Distribute User CA public key to servers
# On servers, /etc/ssh/sshd_config:
TrustedUserCAKeys /etc/ssh/user_ca.pub
Distribute Host CA public key to clients
# On clients, ~/.ssh/known_hosts:
@cert-authority *.example.com ssh-ed25519 AAAA...
Test and document
  • • Test signing a user certificate (see SSH User Certificates for signing flags)
  • • Test signing a host certificate (see SSH Host Certificates for options)
  • • Document: Who can request? Who can sign? What validity periods?

FAQ

Can I use my regular SSH key as a CA?

Technically yes, but don't. Use dedicated keys for CA purposes only. This keeps your CA keys separate from keys used for authentication.

Do I need to set up my own CA, or should I use a service?

Depends on scale:

  • • < 50 servers: DIY CA is fine
  • • 50-500 servers: Consider Vault or step-ca
  • • 500+ or compliance requirements: Enterprise solution (Venafi)

What if I lose my CA private key?

All certificates signed by that CA become unverifiable. You'll need to generate a new CA, redistribute the new public key everywhere, and re-sign all certificates. Backup your CA keys—store an encrypted backup in at least two locations with access limited to CA operators. Test your restore procedure annually.

Can I have multiple User CAs?

Yes. List multiple in TrustedUserCAKeys:

TrustedUserCAKeys /etc/ssh/user_ca_1.pub /etc/ssh/user_ca_2.pub

Use case: Different CAs for different teams or environments.

How is this different from X.509 PKI?

AspectSSH CertificatesX.509 PKI
FormatOpenSSH proprietaryASN.1/DER standard
Chain depthSingle levelMulti-level hierarchies
RevocationNo built-in mechanismCRL, OCSP
ComplexitySimpleComplex

SSH certificates are simpler by design. That's a feature, not a bug.

Related Guides

SSH Certificate Series
Related Concepts

→ Explore all SSH topics in our Guide Collection