DEV Community

Cover image for Ending SSH Key Chaos: Setting Up Your Own SSH Certificate Authority
Mustafa ERBAY
Mustafa ERBAY

Posted on • Originally published at mustafaerbay.com.tr

Ending SSH Key Chaos: Setting Up Your Own SSH Certificate Authority

Ending SSH Key Chaos: Setting Up Your Own SSH Certificate Authority

SSH keys often create conflicts and revision problems when managing server access; you can eliminate this chaos by setting up your own SSH Certificate Authority (CA).

Why Does SSH Chaos Occur?

Manually distributing SSH keys leads to inconsistencies and the problem of not removing old keys.

  • Duplicate keys: When the same key is copied to multiple servers, access remains even if an employee's account is deleted.
  • Revocation delay: It can take hours to collect all keys when an employee leaves, creating a security vulnerability.

These problems can be reduced by creating a central signing authority.

ℹ️ Why CA?

CA signs multiple host certificates with a single root private key; clients only need to trust the CA's public key, thus eliminating individual key management.

What is an SSH CA and How Does it Work?

An SSH CA is a certificate model supported by OpenSSH, similar to X.509 certificates but in its own format. Host or user certificates are generated using ssh-keygen -s.

  • Root key: The CA's private key is stored in one place and has very limited access.
  • Signed certificates: The certificate given to the server carries the CA's signature and matches files like HostCertificate. The certificate given to the user is trusted by the server via the TrustedUserCAKeys directive and can have user-specific access restrictions via files like AuthorizedPrincipalsFile.

This setup creates a trust chain: the client accepts the CA public key, verifies the host certificate signed by the CA, and grants access.

Workflow Summary Graph

Diagram

Creating the CA Root Key

The root key should be created in a high-security directory and only accessible by root or via sudo privileges.

# Create a 4096-bit RSA key
sudo ssh-keygen -t rsa -b 4096 -f /etc/ssh/ca_key -N "" -C "My SSH CA"
# Save the public key to /etc/ssh/ca_key.pub
sudo chmod 600 /etc/ssh/ca_key
sudo chmod 644 /etc/ssh/ca_key.pub
Enter fullscreen mode Exit fullscreen mode

WARNING: Using an empty password (-N "") for the CA private key poses a security risk. In production environments, it's strongly recommended to protect the CA private key with a password and store the key offline or in a Hardware Security Module (HSM).

The ssh-keygen output typically includes (output not shown):

  • Private key: /etc/ssh/ca_key
  • Public key: /etc/ssh/ca_key.pub

A secure backup of the root key should be kept offline, such as on a USB drive or in an HSM.

Signing Host Certificates

Each server has a host key (e.g., ssh_host_rsa_key); this key needs to be certified with the CA's signature.

# Sign the host key on the server
# Replace ${HOSTNAME} and ${HOSTNAME}.example.com with your server names.
sudo ssh-keygen -s /etc/ssh/ca_key -I ${HOSTNAME} -h -n ${HOSTNAME},${HOSTNAME}.example.com /etc/ssh/ssh_host_rsa_key.pub
Enter fullscreen mode Exit fullscreen mode

This command creates a certificate named ssh_host_rsa_key-cert.pub in the same directory. Add this certificate file to the HostCertificate line in the SSH daemon's sshd_config file:

# In /etc/ssh/sshd_config
HostKey /etc/ssh/ssh_host_rsa_key
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
Enter fullscreen mode Exit fullscreen mode

WARNING: Incorrect configurations in sshd_config can disrupt SSH access. It's recommended to back up the file before making changes and, if possible, perform a dry run or validation step.

Restart the daemon after saving the changes:

sudo systemctl restart sshd
Enter fullscreen mode Exit fullscreen mode

Client-Side: Making the CA Public Key Trusted

On client machines, the CA public key is added to ~/.ssh/known_hosts or /etc/ssh/ssh_known_hosts.

# Add the CA public key (global)
# Replace *.example.com with your domain.
sudo mkdir -p /etc/ssh
sudo tee -a /etc/ssh/ssh_known_hosts <<EOF
@cert-authority *.example.com $(cat /etc/ssh/ca_key.pub)
EOF

# For a personal user (optional, the above global configuration is sufficient)
# Replace *.example.com with your domain.
# This command adds the CA public key to the user's known_hosts file with the @cert-authority directive.
tee -a ~/.ssh/known_hosts <<EOF
@cert-authority *.example.com $(cat /etc/ssh/ca_key.pub)
EOF
Enter fullscreen mode Exit fullscreen mode

This line accepts all host certificates under *.example.com signed by the CA.

User Certificate (Optional)

If you also want to manage individual user keys, you can create a user certificate with the same CA:

# Replace user01 and +52w with your username and validity period.
ssh-keygen -s /etc/ssh/ca_key -I user01 -n user01 -V +52w ~/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode

This command produces a file named id_rsa-cert.pub. On the server, to make this user certificate trusted, you need to specify the CA's public key in the TrustedUserCAKeys directive in sshd_config.

Example sshd_config configuration:

# In /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca_user_keys.pub
Enter fullscreen mode Exit fullscreen mode

Here, /etc/ssh/ca_user_keys.pub should contain the CA's public key that signed the user certificates.

Deployment and Management Strategies

When deploying SSH CA to multiple servers, the following practical tips are useful:

Strategy Description Advantage Disadvantage
Manual deployment Copy files to each server using scp/rsync Simple, low infrastructure need High error potential, not scalable
Ansible Playbook Use copy and lineinfile modules for automation Repeatable, version control Requires Ansible setup
GitOps (Flux/ArgoCD) Store CA files in a Git repo and deploy via CI/CD Change tracking, easy rollback Requires CI/CD pipeline

Example Ansible task:

- name: Deploy SSH CA and host certificates
  hosts: all
  become: true
  tasks:
    - name: Copy CA public key
      copy:
        src: ca_key.pub
        dest: /etc/ssh/ca_key.pub
        mode: '0644'
    - name: Ensure HostCertificate is configured
      lineinfile:
        path: /etc/ssh/sshd_config
        regexp: '^HostCertificate'
        line: "HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub"
    - name: Restart sshd service
      service:
        name: sshd
        state: restarted
Enter fullscreen mode Exit fullscreen mode

This playbook deploys the CA public key and host certificate in one step.

Security and Maintenance

The CA's private key should never be transferred over the network; it should only be copied with physical access or stored in an HSM.

  • Key rotation: Regularly rotating (e.g., every 6-12 months) the CA key and re-signing old certificates can enhance long-term security.
  • Revocation: OpenSSH uses Key Revocation Lists (KRLs) to revoke keys or certificates. KRLs are binary files created with ssh-keygen -k. The list of revoked keys (revoked_keys) is specified in sshd_config with the RevokedKeys directive.

WARNING: The ssh-keygen -R command removes a key from known_hosts, it does not create a revocation list. Use ssh-keygen -k for key revocation.

Conclusion

Setting up your own SSH Certificate Authority eliminates key conflicts, centralizes access management, and simplifies revocation processes.

  • Step 1: Create the CA root private key in a secure location and protect it with a password.
  • Step 2: Sign server host keys with the CA and add the HostCertificate directive to sshd_config.
  • Step 3: Make the CA public key a trusted source on client machines using the @cert-authority directive.
  • Step 4: Scale deployment with automation (Ansible, GitOps).

This setup enhances both security and operational efficiency; planning for CA rotation and revocation strategies is recommended as a next step.

Official Resources

Top comments (0)