SSH certificate authentication
My increasing reliance on SSH key authentication has highlighted its scalability challenges. Although a substantial improvement over password authentication, the inherent difficulties in managing and distributing keys prevent quick and efficient scaling. Consequently, I've been researching more scalable SSH authentication solutions. This is how I came across SSH certificate authentication, and I'm particularly intrigued by it due to its numerous advantages.
Certificate Authority
For the Certificate Authority (CA), I will use my host machine so that I don't need to spin up another dedicated LXC container for CA functionality. Here is how I prepare my CA setup.
# Generate a ssh private/public key pair for CA
tyla@e32:~/ssh/ca$ sh-keygen -t rsa -f homelab_ssh_ca -C "Homelab SSH CA"
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in homelab_ssh_ca
Your public key has been saved in homelab_ssh_ca.pub
The key fingerprint is:
SHA256:UKnsJE3QJQPfrEe2+P6BVz9SNN1wIq3b3FGdIQ0hpk8 Homelab SSH CA
The key's randomart image is:
+---[RSA 3072]----+
| o+o.o. o.=*.=|
| .o*. o ..oB+|
| +o.=. E .o +|
| . =* .o .. o |
| +o S ..+...|
| .o . ..oo .|
| o o . o |
| . . . . . |
| ... |
+----[SHA256]-----+
tyla@e32:~/ssh/ca$ ll
total 16
drwxrwxr-x 2 tyla tyla 4096 May 25 21:18 ./
drwxr--r-- 3 tyla tyla 4096 May 25 12:51 ../
-rw------- 1 tyla tyla 2602 May 25 21:18 homelab_ssh_ca
-rw-r--r-- 1 tyla tyla 568 May 25 21:18 homelab_ssh_ca.pub
tyla@e32:~/ssh/ca$ cat homelab_ssh_ca.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCd1bStWHNLF5fJqNFxCwcsFv9NWXnhgA2tvkWIQHeVHe8b3Hen9710i8083sq/gwKXQJpQ4gywdDVjsRsn6QIZGZ6iqqSZ0sEHS4zRzFCzRqTq5iPQ7TvWLzPabXo/AYY8ia/QtXu9Wigq2ePMA76WykCkg4LCz0DaSfQ59BvAi5iupEbyUQul4FULyI9fb3zO2CuFDnCzKC+g0iXKWpYC30edsr3qAIQvO2VK+qPK7xictEEkjDAQX+FqlqWOuobz+qc/hfm7y1rH8nikCoZ9lbS3ZDiOEBxtJH8thukGFnwdF6jueol+skpiKWSPq7MpxJ3YvN1QoQGKV/vaeBIFEmUVl8wR8Qb6SSqq44OBqyju7Z4aaCn94sIXTEHjTzuFEj1eaOXinygYW3RiwF6HHmythVWac7qnkw0uXIOQPlqYqt6HrYjRtFTbuTXFf9srhO5cjben/lllqjMUZcQu/RRC/Wz8anGDPmk/t78bUo3qch6MTo9vPqXgAixFD58= Homelab SSH CA
Lab environment setup with LXD
Prior to outlining the configuration steps, there are two preparatory actions I'd like to take. The first is to launch three LXC containers, specifically named server1, server2, and client1. The second is to retrieve the IP addresses of these containers to facilitate DNS configuration via the /etc/hosts
file.
Spin up server1, server2 and client1 LXC containers.
# Spin up 2 LXC containers for server1 and server2
tyla@e32:~$ for i in {1..2}; do lxc launch ubuntu:24.04 server$i; done
Launching server1
Launching server2
# Spin up a LXC container for client1
tyla@e32:~$ lxc launch ubuntu:24.04 client1
Launching client1
# Check the IP Addresses
tyla@e32:~$ lxc list
+---------+---------+---------------------+-----------------------------------------------+-----------+-----------+
| NAME | STATE | IPV4 | IPV6 | TYPE | SNAPSHOTS |
+---------+---------+---------------------+-----------------------------------------------+-----------+-----------+
| client1 | RUNNING | 10.18.34.46 (eth0) | fd42:2751:df65:31e1:216:3eff:fea7:ec91 (eth0) | CONTAINER | 0 |
+---------+---------+---------------------+-----------------------------------------------+-----------+-----------+
| server1 | RUNNING | 10.18.34.5 (eth0) | fd42:2751:df65:31e1:216:3eff:fec6:b1ec (eth0) | CONTAINER | 0 |
+---------+---------+---------------------+-----------------------------------------------+-----------+-----------+
| server2 | RUNNING | 10.18.34.232 (eth0) | fd42:2751:df65:31e1:216:3eff:fe4b:6237 (eth0) | CONTAINER | 0 |
+---------+---------+---------------------+-----------------------------------------------+-----------+-----------+
# Update /etc/hosts file accordingly
tyla@e32:~$ sudo vi /etc/hosts
127.0.0.1 localhost
127.0.1.1 e32
10.18.34.5 server1 server1.home.lab
10.18.34.232 server2 server2.home.lab
10.18.34.46 client1 client1.home.lab
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
# Verify if the DNS names work
tyla@e32:~$ ping server1.home.lab
PING server1 (10.18.34.5) 56(84) bytes of data.
64 bytes from server1 (10.18.34.5): icmp_seq=1 ttl=64 time=0.047 ms
^C
--- server1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.047/0.047/0.047/0.000 ms
tyla@e32:~$ ping server2.home.lab
PING server2 (10.18.34.232) 56(84) bytes of data.
64 bytes from server2 (10.18.34.232): icmp_seq=1 ttl=64 time=0.051 ms
^C
--- server2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.051/0.051/0.051/0.000 ms
tyla@e32:~$ ping client1.home.lab
PING client1 (10.18.34.46) 56(84) bytes of data.
64 bytes from client1 (10.18.34.46): icmp_seq=1 ttl=64 time=0.050 ms
^C
--- client1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.050/0.050/0.050/0.000 ms
Server-side setup
Here is how we configure server-side ssh setup.
Fetch the server1's
/etc/ssh/ssh_host_rsa_key.pub
tyla@e32:~/ssh/ca$ scp ubuntu@server1:/etc/ssh/ssh_host_rsa_key.pub .
ssh_host_rsa_key.pub 100% 566 1.1MB/s 00:00
Sign the host public key with CA's private key.
tyla@e32:~/ssh/ca$ ssh-keygen -s homelab_ssh_ca -I server1 -V +52w -h -n server1.home.lab ssh_host_rsa_key.pub
Signed host key ssh_host_rsa_key-cert.pub: id "server1" serial 0 for server1.home.lab valid from 2025-05-25T21:22:00 to 2026-05-24T21:23:51
Move the signed host public key and CA public key back to server1's
/etc/ssh/
directory, and configure ssh daemon.
tyla@e32:~/ssh/ca$ scp ssh_host_rsa_key-cert.pub ubuntu@server1:
ssh_host_rsa_key-cert.pub 100% 1855 4.8MB/s 00:00
tyla@e32:~/ssh/ca$ scp homelab_ssh_ca.pub ubuntu@server1:
homelab_ssh_ca.pub 100% 568 1.5MB/s 00:00
tyla@e32:~/ssh/ca$ ssh ubuntu@server1
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun May 25 11:25:02 UTC 2025
System load: 0.16
Usage of /: 2.8% of 17.60GB
Memory usage: 0%
Swap usage: 0%
Temperature: 40.0 C
Processes: 28
Users logged in: 1
IPv4 address for eth0: 10.18.34.5
IPv6 address for eth0: fd42:2751:df65:31e1:216:3eff:fec6:b1ec
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Sun May 25 11:19:56 2025 from 10.18.34.1
ubuntu@server1:~$ ll
total 14
drwxr-x--- 4 ubuntu ubuntu 11 May 25 11:25 ./
drwxr-xr-x 3 root root 3 May 25 09:52 ../
-rw------- 1 ubuntu ubuntu 628 May 25 11:25 .bash_history
-rw-r--r-- 1 ubuntu ubuntu 220 Mar 31 2024 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu 3771 Mar 31 2024 .bashrc
drwx------ 2 ubuntu ubuntu 3 May 25 10:19 .cache/
-rw-r--r-- 1 ubuntu ubuntu 807 Mar 31 2024 .profile
drwx------ 2 ubuntu ubuntu 3 May 25 09:52 .ssh/
-rw-r--r-- 1 ubuntu ubuntu 0 May 25 10:26 .sudo_as_admin_successful
-rw-r--r-- 1 ubuntu ubuntu 96 May 25 11:13 homelab_ssh_ca.pub
-rw-r--r-- 1 ubuntu ubuntu 1855 May 25 11:25 ssh_host_rsa_key-cert.pub
-rw-r--r-- 1 ubuntu ubuntu 568 May 25 11:27 homelab_ssh_ca.pub
ubuntu@server1:~$ sudo mv *.pub /etc/ssh/
ubuntu@server1:~$ cd /etc/ssh/
ubuntu@server1:/etc/ssh$ ll
total 65
drwxr-xr-x 4 root root 16 May 25 11:28 ./
drwxr-xr-x 104 root root 196 May 25 10:58 ../
-rw-r--r-- 1 ubuntu ubuntu 568 May 25 11:27 homelab_ssh_ca.pub
-rw-r--r-- 1 root root 620042 Apr 22 11:51 moduli
-rw-r--r-- 1 root root 1649 Apr 22 11:51 ssh_config
drwxr-xr-x 2 root root 2 Apr 22 11:51 ssh_config.d/
-rw------- 1 root root 505 May 25 09:52 ssh_host_ecdsa_key
-rw-r--r-- 1 root root 174 May 25 09:52 ssh_host_ecdsa_key.pub
-rw------- 1 root root 399 May 25 09:52 ssh_host_ed25519_key
-rw-r--r-- 1 root root 94 May 25 09:52 ssh_host_ed25519_key.pub
-rw------- 1 root root 2602 May 25 09:52 ssh_host_rsa_key
-rw-r--r-- 1 ubuntu ubuntu 1855 May 25 11:25 ssh_host_rsa_key-cert.pub
-rw-r--r-- 1 root root 566 May 25 09:52 ssh_host_rsa_key.pub
-rw-r--r-- 1 root root 342 Dec 7 2020 ssh_import_id
-rw-r--r-- 1 root root 3349 May 25 11:14 sshd_config
drwxr-xr-x 2 root root 3 May 16 12:54 sshd_config.d/
ubuntu@server1:/etc/ssh$ sudo chown root:root homelab_ssh_ca.pub
ubuntu@server1:/etc/ssh$ sudo chown root:root ssh_host_rsa_key-cert.pub
ubuntu@server1:/etc/ssh$ ll
total 65
drwxr-xr-x 4 root root 16 May 25 11:28 ./
drwxr-xr-x 104 root root 196 May 25 10:58 ../
-rw-r--r-- 1 root root 568 May 25 11:27 homelab_ssh_ca.pub
-rw-r--r-- 1 root root 620042 Apr 22 11:51 moduli
-rw-r--r-- 1 root root 1649 Apr 22 11:51 ssh_config
drwxr-xr-x 2 root root 2 Apr 22 11:51 ssh_config.d/
-rw------- 1 root root 505 May 25 09:52 ssh_host_ecdsa_key
-rw-r--r-- 1 root root 174 May 25 09:52 ssh_host_ecdsa_key.pub
-rw------- 1 root root 399 May 25 09:52 ssh_host_ed25519_key
-rw-r--r-- 1 root root 94 May 25 09:52 ssh_host_ed25519_key.pub
-rw------- 1 root root 2602 May 25 09:52 ssh_host_rsa_key
-rw-r--r-- 1 root root 1855 May 25 11:25 ssh_host_rsa_key-cert.pub
-rw-r--r-- 1 root root 566 May 25 09:52 ssh_host_rsa_key.pub
-rw-r--r-- 1 root root 342 Dec 7 2020 ssh_import_id
-rw-r--r-- 1 root root 3349 May 25 11:14 sshd_config
drwxr-xr-x 2 root root 3 May 16 12:54 sshd_config.d/
ubuntu@server1:/etc/ssh$ sudo -i
root@server1:~# echo "HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub" >> /etc/ssh/sshd_config
root@server1:~# echo "TrustedUserCAKeys /etc/ssh/homelab_ssh_ca.pub" >> /etc/ssh/sshd_config
root@server1:~# cat /etc/ssh/sshd_config
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
KbdInteractiveAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin prohibit-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
TrustedUserCAKeys /etc/ssh/homelab_ssh_ca.pub
root@server1:~# systemctl restart ssh
root@server1:~# systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled)
Active: active (running) since Sun 2025-05-25 11:36:47 UTC; 5s ago
TriggeredBy: ● ssh.socket
Docs: man:sshd(8)
man:sshd_config(5)
Process: 1112 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
Main PID: 1114 (sshd)
Tasks: 1 (limit: 38326)
Memory: 1.2M (peak: 1.6M)
CPU: 21ms
CGroup: /system.slice/ssh.service
└─1114 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
May 25 11:36:47 server1 systemd[1]: Starting ssh.service - OpenBSD Secure Shell server...
May 25 11:36:47 server1 sshd[1114]: Server listening on :: port 22.
May 25 11:36:47 server1 systemd[1]: Started ssh.service - OpenBSD Secure Shell server.
root@server1:~# vi /etc/hosts
127.0.0.1 localhost
10.18.34.5 server1 server1.home.lab
10.18.34.232 server2 server2.home.lab
10.18.34.46 client1 client1.home.lab
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
root@server1:~#
logout
ubuntu@server1:/etc/ssh$
logout
Connection to server1 closed.
# Cleanup host public key from server1
tyla@e32:~/ssh/ca$ rm ssh_host*
Repeat the same configuration process on server2.
tyla@e32:~/ssh/ca$ scp ubuntu@server2:/etc/ssh/ssh_host_rsa_key.pub .
ssh_host_rsa_key.pub 100% 566 1.0MB/s 00:00
tyla@e32:~/ssh/ca$ ssh-keygen -s homelab_ssh_ca -I server2 -V +52w -h -n server2.home.lab ssh_host_rsa_key.pub
Signed host key ssh_host_rsa_key-cert.pub: id "server2" serial 0 for server2.home.lab valid from 2025-05-25T21:40:00 to 2026-05-24T21:40:59
tyla@e32:~/ssh/ca$ scp ssh_host_rsa_key-cert.pub ubuntu@server2:
ssh_host_rsa_key-cert.pub 100% 1855 5.2MB/s 00:00
tyla@e32:~/ssh/ca$ scp homelab_ssh_ca.pub ubuntu@server2:
homelab_ssh_ca.pub 100% 568 1.9MB/s 00:00
tyla@e32:~/ssh/ca$ ssh ubuntu@server2
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun May 25 11:42:37 UTC 2025
System load: 1.03
Usage of /: 2.8% of 17.60GB
Memory usage: 0%
Swap usage: 0%
Temperature: 38.0 C
Processes: 22
Users logged in: 0
IPv4 address for eth0: 10.18.34.232
IPv6 address for eth0: fd42:2751:df65:31e1:216:3eff:fe4b:6237
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Sun May 25 10:53:27 2025 from 10.18.34.1
ubuntu@server2:~$ ll
total 15
drwxr-x--- 4 ubuntu ubuntu 11 May 25 11:42 ./
drwxr-xr-x 3 root root 3 May 25 09:52 ../
-rw------- 1 ubuntu ubuntu 223 May 25 10:57 .bash_history
-rw-r--r-- 1 ubuntu ubuntu 220 Mar 31 2024 .bash_logout
-rw-r--r-- 1 ubuntu ubuntu 3771 Mar 31 2024 .bashrc
drwx------ 2 ubuntu ubuntu 3 May 25 10:38 .cache/
-rw-r--r-- 1 ubuntu ubuntu 807 Mar 31 2024 .profile
drwx------ 2 ubuntu ubuntu 3 May 25 09:52 .ssh/
-rw-r--r-- 1 ubuntu ubuntu 0 May 25 10:39 .sudo_as_admin_successful
-rw-r--r-- 1 ubuntu ubuntu 568 May 25 11:42 homelab_ssh_ca.pub
-rw-r--r-- 1 ubuntu ubuntu 1855 May 25 11:42 ssh_host_rsa_key-cert.pub
ubuntu@server2:~$ sudo mv *.pub /etc/ssh/
ubuntu@server2:~$ cd /etc/ssh
ubuntu@server2:/etc/ssh$ ll
total 66
drwxr-xr-x 4 root root 17 May 25 11:43 ./
drwxr-xr-x 104 root root 196 May 25 10:57 ../
-rw-r--r-- 1 ubuntu ubuntu 568 May 25 11:42 homelab_ssh_ca.pub
-rw-r--r-- 1 root root 620042 Apr 22 11:51 moduli
-rw-r--r-- 1 root root 1649 Apr 22 11:51 ssh_config
drwxr-xr-x 2 root root 2 Apr 22 11:51 ssh_config.d/
-rw------- 1 root root 505 May 25 09:52 ssh_host_ecdsa_key
-rw-r--r-- 1 root root 174 May 25 09:52 ssh_host_ecdsa_key.pub
-rw------- 1 root root 399 May 25 09:52 ssh_host_ed25519_key
-rw-r--r-- 1 root root 94 May 25 09:52 ssh_host_ed25519_key.pub
-rw------- 1 root root 2602 May 25 09:52 ssh_host_rsa_key
-rw-r--r-- 1 ubuntu ubuntu 1855 May 25 11:42 ssh_host_rsa_key-cert.pub
-rw-r--r-- 1 root root 566 May 25 09:52 ssh_host_rsa_key.pub
-rw-r--r-- 1 root root 342 Dec 7 2020 ssh_import_id
-rw-r--r-- 1 root root 3310 May 25 10:47 sshd_config
drwxr-xr-x 2 root root 3 May 16 12:54 sshd_config.d/
ubuntu@server2:/etc/ssh$ sudo chown root:root homelab_ssh_ca.pub
ubuntu@server2:/etc/ssh$ sudo chown root:root ssh_host_rsa_key-cert.pub
ubuntu@server2:/etc/ssh$ ll
total 66
drwxr-xr-x 4 root root 17 May 25 11:43 ./
drwxr-xr-x 104 root root 196 May 25 10:57 ../
-rw-r--r-- 1 root root 568 May 25 11:42 homelab_ssh_ca.pub
-rw-r--r-- 1 root root 620042 Apr 22 11:51 moduli
-rw-r--r-- 1 root root 1649 Apr 22 11:51 ssh_config
drwxr-xr-x 2 root root 2 Apr 22 11:51 ssh_config.d/
-rw------- 1 root root 505 May 25 09:52 ssh_host_ecdsa_key
-rw-r--r-- 1 root root 174 May 25 09:52 ssh_host_ecdsa_key.pub
-rw------- 1 root root 399 May 25 09:52 ssh_host_ed25519_key
-rw-r--r-- 1 root root 94 May 25 09:52 ssh_host_ed25519_key.pub
-rw------- 1 root root 2602 May 25 09:52 ssh_host_rsa_key
-rw-r--r-- 1 root root 1855 May 25 11:42 ssh_host_rsa_key-cert.pub
-rw-r--r-- 1 root root 566 May 25 09:52 ssh_host_rsa_key.pub
-rw-r--r-- 1 root root 342 Dec 7 2020 ssh_import_id
-rw-r--r-- 1 root root 3310 May 25 10:47 sshd_config
drwxr-xr-x 2 root root 3 May 16 12:54 sshd_config.d/
ubuntu@server2:/etc/ssh$ sudo -i
root@server2:~# echo "HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub" >> /etc/ssh/sshd_config
root@server2:~# echo "TrustedUserCAKeys /etc/ssh/homelab_ssh_ca.pub" >> /etc/ssh/sshd_config
root@server2:~# cat /etc/ssh/sshd_config
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Include /etc/ssh/sshd_config.d/*.conf
#Port 22
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 2m
#PermitRootLogin prohibit-password
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
#PubkeyAuthentication yes
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
#PasswordAuthentication yes
#PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
KbdInteractiveAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the KbdInteractiveAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via KbdInteractiveAuthentication may bypass
# the setting of "PermitRootLogin prohibit-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and KbdInteractiveAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding yes
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
TrustedUserCAKeys /etc/ssh/homelab_ssh_ca.pub
root@server2:~# systemctl restart ssh
root@server2:~# systemctl status ssh
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/usr/lib/systemd/system/ssh.service; disabled; preset: enabled)
Active: active (running) since Sun 2025-05-25 11:51:22 UTC; 3s ago
TriggeredBy: ● ssh.socket
Docs: man:sshd(8)
man:sshd_config(5)
Process: 814 ExecStartPre=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS)
Main PID: 816 (sshd)
Tasks: 1 (limit: 38326)
Memory: 1.2M (peak: 1.5M)
CPU: 22ms
CGroup: /system.slice/ssh.service
└─816 "sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups"
May 25 11:51:22 server2 systemd[1]: Starting ssh.service - OpenBSD Secure Shell server...
May 25 11:51:22 server2 sshd[816]: Server listening on :: port 22.
May 25 11:51:22 server2 systemd[1]: Started ssh.service - OpenBSD Secure Shell server.
root@server2:~# vi /etc/hosts
127.0.0.1 localhost
10.18.34.5 server1 server1.home.lab
10.18.34.232 server2 server2.home.lab
10.18.34.46 client1 client1.home.lab
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
# Cleanup host public key from server2
tyla@e32:~/ssh/ca$ rm ssh_host*
Client-side setup
Here is how the client-side configured.
Generate RSA key pair on client1 and sign its public key with CA private key, then moved the signed public key back to the client1.
tyla@e32:~/ssh/ca$ ssh ubuntu@client1
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun May 25 11:54:49 UTC 2025
System load: 0.88
Usage of /: 2.8% of 17.60GB
Memory usage: 0%
Swap usage: 0%
Temperature: 41.0 C
Processes: 22
Users logged in: 0
IPv4 address for eth0: 10.18.34.46
IPv6 address for eth0: fd42:2751:df65:31e1:216:3eff:fea7:ec91
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Sun May 25 11:17:19 2025 from 10.18.34.1
ubuntu@client1:~$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ubuntu/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ubuntu/.ssh/id_rsa
Your public key has been saved in /home/ubuntu/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:y46bZgUA0tE+ISoOVDTOT/k1NAI8di5rMngpNsDn2wk ubuntu@client1
The key's randomart image is:
+---[RSA 3072]----+
|..=B.... o |
| o= =+..o . |
|o. =.=+ o |
|=. .=.o.. . |
|= + .oooS |
| * E o ... |
|. + B ..o |
| . oo+ |
| o+.. |
+----[SHA256]-----+
ubuntu@client1:~$
logout
Connection to client1 closed.
tyla@e32:~/ssh/ca$ scp ubuntu@client1:.ssh/id_rsa.pub .
id_rsa.pub 100% 568 1.3MB/s 00:00
tyla@e32:~/ssh/ca$ ll
total 20
drwxrwxr-x 2 tyla tyla 4096 May 25 21:57 ./
drwxr--r-- 3 tyla tyla 4096 May 25 12:51 ../
-rw------- 1 tyla tyla 2602 May 25 21:18 homelab_ssh_ca
-rw-r--r-- 1 tyla tyla 568 May 25 21:18 homelab_ssh_ca.pub
-rw-r--r-- 1 tyla tyla 568 May 25 21:57 id_rsa.pub
tyla@e32:~/ssh/ca$ ssh-keygen -s homelab_ssh_ca -I client1 -n ubuntu -V +52w id_rsa.pub
Signed user key id_rsa-cert.pub: id "client1" serial 0 for ubuntu valid from 2025-05-25T22:00:00 to 2026-05-24T22:01:24
tyla@e32:~/ssh/ca$ ll
total 24
drwxrwxr-x 2 tyla tyla 4096 May 25 22:01 ./
drwxr--r-- 3 tyla tyla 4096 May 25 12:51 ../
-rw------- 1 tyla tyla 2602 May 25 21:18 homelab_ssh_ca
-rw-r--r-- 1 tyla tyla 568 May 25 21:18 homelab_ssh_ca.pub
-rw-r--r-- 1 tyla tyla 2017 May 25 22:01 id_rsa-cert.pub
-rw-r--r-- 1 tyla tyla 568 May 25 21:57 id_rsa.pub
tyla@e32:~/ssh/ca$ scp id_rsa-cert.pub ubuntu@client1:.ssh/
id_rsa-cert.pub 100% 2017 5.4MB/s 00:00
Create
/etc/ssh/ssh_known_hosts
file with CA public key for Trust On First Use (TOFU) identity verification process.
@cert-authority *.home.lab ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCd1bStWHNLF5fJqNFxCwcsFv9NWXnhgA2tvkWIQHeVHe8b3Hen9710i8083sq/gwKXQJpQ4gywdDVjsRsn6QIZGZ6iqqSZ0sEHS4zRzFCzRqTq5iPQ7TvWLzPabXo/AYY8ia/QtXu9Wigq2ePMA76WykCkg4LCz0DaSfQ59BvAi5iupEbyUQul4FULyI9fb3zO2CuFDnCzKC+g0iXKWpYC30edsr3qAIQvO2VK+qPK7xictEEkjDAQX+FqlqWOuobz+qc/hfm7y1rH8nikCoZ9lbS3ZDiOEBxtJH8thukGFnwdF6jueol+skpiKWSPq7MpxJ3YvN1QoQGKV/vaeBIFEmUVl8wR8Qb6SSqq44OBqyju7Z4aaCn94sIXTEHjTzuFEj1eaOXinygYW3RiwF6HHmythVWac7qnkw0uXIOQPlqYqt6HrYjRtFTbuTXFf9srhO5cjben/lllqjMUZcQu/RRC/Wz8anGDPmk/t78bUo3qch6MTo9vPqXgAixFD58= Homelab SSH CA
Verify the ssh certification authentication from client1 to server1 and server2.
tyla@e32:~/ssh/ca$ ssh ubuntu@client1
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun May 25 12:03:25 UTC 2025
System load: 0.22
Usage of /: 2.8% of 17.60GB
Memory usage: 0%
Swap usage: 0%
Temperature: 38.0 C
Processes: 22
Users logged in: 0
IPv4 address for eth0: 10.18.34.46
IPv6 address for eth0: fd42:2751:df65:31e1:216:3eff:fea7:ec91
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Sun May 25 11:54:50 2025 from 10.18.34.1
# Verify server1 login from client1
ubuntu@client1:~$ ssh ubuntu@server1.home.lab
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun May 25 12:03:43 UTC 2025
System load: 0.17
Usage of /: 2.8% of 17.60GB
Memory usage: 0%
Swap usage: 0%
Temperature: 40.0 C
Processes: 22
Users logged in: 0
IPv4 address for eth0: 10.18.34.5
IPv6 address for eth0: fd42:2751:df65:31e1:216:3eff:fec6:b1ec
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Sun May 25 11:36:37 2025 from 10.18.34.1
ubuntu@server1:~$
logout
Connection to server1.home.lab closed.
# Verify server2 login from client1
ubuntu@client1:~$ ssh ubuntu@server2.home.lab
Welcome to Ubuntu 24.04.2 LTS (GNU/Linux 6.8.0-60-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Sun May 25 12:04:37 UTC 2025
System load: 0.36
Usage of /: 2.8% of 17.60GB
Memory usage: 0%
Swap usage: 0%
Temperature: 38.0 C
Processes: 22
Users logged in: 0
IPv4 address for eth0: 10.18.34.232
IPv6 address for eth0: fd42:2751:df65:31e1:216:3eff:fe4b:6237
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Sun May 25 11:43:07 2025 from 10.18.34.1
ubuntu@server2:~$
In summary, while the initial setup of an SSH certificate authority may require some effort, the long-term benefits in terms of simplified management, enhanced security, and improved scalability make SSH certificate authentication a worthwhile investment for any organisation or individual managing multiple SSH connections.
Last updated
Was this helpful?