Mastering SSH Certificates: A Comprehensive Guide

SSH certificates offer a powerful and secure alternative to traditional key-based authentication. In this guide, we'll walk you through the process of implementing SSH certificate authentication, from creating a Certificate Authority (CA) to configuring servers and clients. We'll also provide practical tips and tricks to make your journey smoother.

Overall Process Flow

The process of implementing SSH certificate authentication involves several key steps:

  1. Create a Certificate Authority (CA)
  2. Configure the remote server
  3. Sign the user's public SSH key with the CA
  4. Use the new certificate for authentication

Let's dive into each step with examples.

1. Create a Certificate Authority (CA)

The first step is to generate a CA key pair. This will be used to sign both host and user certificates.

1ssh-keygen -t ed25519 -f ca-key -m PEM

This command creates two files: ca-key (private key) and ca-key.pub (public key). Keep the private key secure and distribute the public key to your servers.

2. Configure the Remote Server

Next, we need to configure the SSH server to trust our new CA. Here's how:

Update Trusted SSH CA Public Key

Navigate to the SSH directory and create a file containing the SSH CA public key:

1cd /etc/ssh
2sudo echo "ssh-ed25519 YOUR_CA_PUBLIC_KEY_HERE" > my-org-trusted-CA.pem

Create AuthorizedPrincipalsFile Structure

Set up the AuthorizedPrincipalsFile to control which SSH principals are accepted:

1cd /etc/ssh
2mkdir auth_principals/
3cd auth_principals
4sudo echo "superuser" > admin
5sudo echo "operator" > ubuntu

This will allow the users to login as admin if they have the superuser principal in their certificate and they'll be able to login as ubuntu if the certificate is signed with the operator principal. Of course if the certificate has both(In my experimentation a scert can have upt 254 principals assigned) then the user can login as either.

Note

Note on Sudo Access Control It's important to be aware that SSH certificate authentication doesn't natively provide a way to control sudo access. However, if you need fine-grained sudo access control based on SSH certificates, consider exploring Uber's PAM SSH Certificates module. This open-source project extends the functionality of SSH certificates to manage sudo permissions. Learn more about Uber's PAM SSH Certificates module - https://github.com/uber/pam-ussh

Update sshd_config

Add the following to your sshd_config file:

1AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
2ChallengeResponseAuthentication no
3PasswordAuthentication no
4TrustedUserCAKeys /etc/ssh/my-org-trusted-CA.pem

Don't forget to restart the SSH service:

1sudo service sshd restart

3. Sign the User's Public SSH Key

Now that our CA is set up and the server is configured, we can sign user keys:

1ssh-keygen -s ca-key -I "username@hostname user key" -n "username,superusers" -V -5m:+3650d ~/.ssh/id_rsa.pub

This command signs the user's public key, creating a certificate valid for 10 years (adjust as needed).

4. Use the New Certificate for Authentication

The user can now use their new certificate to authenticate. They don't need to do anything special - their SSH client will automatically use the certificate.

Advanced Tips and Tricks

Inspecting Certificates

To inspect a user's SSH certificate:

1ssh-keygen -Lf path/to/user-cert.pub

This will show details like principals, validity period, and signing CA.

Creating and Signing Host Keys

For host keys:

  1. Create the key:

    1ssh-keygen -f ssh_host_rsa_key -N '' -b 4096 -t rsa
    
  2. Sign it:

    1ssh-keygen -s ca-key -I host.example.com -h -n host.example.com,127.0.0.1 -V +52w ssh_host_rsa_key.pub
    

Extracting Public Keys

To extract a public key from a private key:

1ssh-keygen -y -e -f ssh_key

Testing with Docker

For development and testing, you can use a Docker container as an SSH server. Here's how:

  1. Create a Dockerfile:
 1FROM ubuntu:latest
 2
 3RUN apt update && apt install openssh-server sudo -y
 4
 5RUN useradd -rm -d /home/ubuntu -s /bin/bash -g root -G sudo -u 1000 ubuntu 
 6RUN echo 'ubuntu:test' | chpasswd
 7
 8EXPOSE 22
 9
10COPY script.sh /script.sh
  1. Create a script.sh:
 1#!/bin/bash
 2mkdir -p /etc/ssh/auth_principals/
 3cp /tmp/principals/* /etc/ssh/auth_principals/
 4chmod 644 /etc/ssh/auth_principals/*
 5
 6cp /tmp/sshd_config /etc/ssh/
 7cp /tmp/myCA.pub /etc/ssh/myCA.pub
 8
 9while true; do
10  /usr/sbin/sshd -Dddd -p 22 &
11  pid=$!
12  wait $pid
13  echo "sshd exited, restarting..."
14done
  1. Build and run the container:
 1docker build . -t ssh-server
 2docker run -it --rm \
 3  --name=openssh-server \
 4  --hostname=openssh-server \
 5  -p 2222:22 \
 6  -v $(pwd)/ca-users.pub:/tmp/myCA.pub \
 7  -v $(pwd)/sshd_config:/tmp/sshd_config \
 8  -v $(pwd)/principal_file:/tmp/principals/ubuntu \
 9  -v $(pwd)/ssh_host_rsa_key:/etc/ssl/ssh_host_rsa_key \
10  -v $(pwd)/ssh_host_rsa_key.pub:/etc/ssl/ssh_host_rsa_key.pub \
11  ssh-server bash script.sh

This setup allows you to quickly test your SSH certificate configuration in a controlled environment.