Let’s look at my SSH configurations!
File Layout
Starting with Ubuntu 22.04 LTS and Debian 12, the OpenSSH version in the distribution is new enough that the Include
directive is supported, and works properly with Match
blocks in included files. Therefore, most of the global stuff ends up in /etc/ssh/sshd_config.d/01-security.conf
and further modifications are made at higher numbers.
Core Security
To minimize surface area, I turn off features I don’t use, if possible:
GSSAPIAuthentication no
HostbasedAuthentication no
PasswordAuthentication no
PermitEmptyPasswords no
AllowTcpForwarding no
X11Forwarding no
Compression no
PermitUserRC no
# Debian and derivatives
DebianBanner no
Some of these are defaults, unless the distribution changes them, which means “explicit is better than implicit” is strongly advised.
Next, I use a group to permit access, allowing me to explicitly add the members to the group without needing to edit the ssh config when things change. Don’t forget to groupadd ssh-users
(once) and gpasswd -a USER ssh-users
(for each user.) Then, permit only that group:
AllowGroups ssh-users
# extra paranoia
PermitRootLogin no
Note that all of the above may be overridden in Match
blocks, where required. TCP forwarding may also be more finely controlled through PermitListen
and PermitOpen
directives.
Note also that my systems are essentially single-user. The group doesn't permit any sharing (and doesn't participate in quotas or anything) that would otherwise be forbidden.
Performance
Machines I use for ssh and sshd are all amd64, so for personal usage, I bump the AES algorithms to the front of the list:
Ciphers ^aes256-gcm@openssh.com,aes256-ctr
SFTP
The biggest trouble is the SFTP subsystem. I comment that out in the main config, then set it in my own:
# /etc/ssh/sshd_config:
#Subsystem sftp ...
# /etc/ssh/sshd_config/02-sftp.conf:
Subsystem sftp internal-sftp
Match group sftp-only
# ForceCommand, ChrootDirectory, etc.
I forget the details of what goes in that Match
block. It’s work stuff, set up a while ago now.
[Updated 2024-08-15: It seems that Subsystem
is permitted inside a Match
block as of OpenSSH 9.5, which is included in Ubuntu 24.04 LTS. My statements above apply to 22.04, which uses version 8.9; or to Debian 12, with 9.2.]
Ongoing Hardening
I occasionally run ssh-audit and check out what else shows up. Note that you may need to run it with the --skip-rate-test
option these days, particularly if you have set up fail2ban
(guess how I know.)
There are also other hardening guides on the internet; I have definitely updated my moduli to only include 3072-bit and up options. Incidentally, if you wonder how that works:
awk '$5 >= 3071' ...
The default action for awk is print
, so that command prints lines that fulfill the condition. The fifth field is the length of the modulus, so that’s what we compare to. The actual bit count is 3071 instead of 3072, because the first digit must be 1 to make a 3072-bit number, so there are only 3071 bits that aren’t predetermined.
Client Config Sample
Host site-admin
# [HostName, Port, User undisclosed]
IdentityFile ~/.ssh/id_admin
IdentitiesOnly yes
Host 192.168.*
# Allow talking to Dropbear 2022.83+ on this subnet
KexAlgorithms +curve25519-sha256,curve25519-sha256@libssh.org
MACs +hmac-sha2-256
Host *
Ciphers aes256-gcm@openssh.com,aes256-ctr
KexAlgorithms sntrup761x25519-sha512@openssh.com
MACs hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com
GSSAPIAuthentication no
It’s mostly post-quantum, or assigning a very specific private key to the administrative user on my Web server.