This is the first post of what I hope will be a series. In each post I will explain my configuration files in detail. Specifically, I will explain what were my goals when configuring that exact service, and why I set each configuration to its current value. These should not be considered as definite guides to these services, just real-world configuration examples and the reasoning behind them.
By writing these, I hope to provide useful real-world configuration examples that are easy to understand and thus easy to adjust, instead of the usual
copy this configuration if you want to do X.
This post could either be read as a whole, or as a reference (click on a line to jump to its explanation).
What is this config for?
The goal of these configuration changes is to harden the security and ease the management of
sshd. Another nice-to-have goal is to make the configuration generic enough so it could be reused among servers without sacrificing security or configurability.
The configuration below only includes values that I have changed, so default values are omitted.
The config file
Click on a line to jump to its explanation.
PermitRootLogin no AuthorizedKeysFile /etc/ssh/authorized_keys/%u PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no AuthenticationMethods publickey AllowGroups wheel ssh-user ssh-sftp-user UsePAM yes X11Forwarding yes PrintMotd no # pam does that # Harden crypto KexAlgorithms firstname.lastname@example.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 Ciphers email@example.com,firstname.lastname@example.org,email@example.com,aes256-ctr,aes192-ctr,aes128-ctr MACs firstname.lastname@example.org,email@example.com,firstname.lastname@example.org,hmac-sha2-512,hmac-sha2-256,email@example.com Subsystem sftp internal-sftp Match Group ssh-sftp-user X11Forwarding no AllowTcpForwarding no PermitTTY no ChrootDirectory %h ForceCommand internal-sftp
Reviewing the config
Disable root login. I don't allow directly logging in as the root user, only through
Usually, authorised keys are located in each user's home directory at: ~/.ssh/authorized_keys. This config changes it to be in a system directory. I also restrict the permissions of each file to be only writeable by root. This prevents an attacker compromising a user from adding his own pubkey to the list of authorised keys, and let me manage the users on the server in a centralised way. For example using a git repository that sends emails to all the admins.
PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no AuthenticationMethods publickey
These directives control how one is allowed to authenticate to the server. I'm not interested in challenge-response, so that's off. I also don't trust users with setting secure passwords, so that's disabled. I also don't allow empty passwords, but since I don't allow passwords at all, this line is redundant.
AuthenticationMethods controls which methods are allowed to be used to connect to the server. This makes sure we only allow public key authentication.
One added benefit to disabling password authentication is that bots don't try to bruteforce passwords on the server.
AllowGroups wheel ssh-user ssh-sftp-user
This line only allows users of the wheel (admins), ssh-user (any ssh user), and ssh-sftp-user (sftp only) groups to login. This makes administration easier and thus safer because it essentially makes ssh authentication into a normal UNIX group.
Enabling PAM does two major things. The first is handling authentication, though that is disabled because we explicitly disabled password and challenge-response above. The second is handling account checks (e.g. if the account allowed in PAM) and establishing the environment (e.g. print the MOTD), which is why this is turned on.
This allows running X applications on the server with the GUI forwarded to my laptop. I sometimes use this.
PrintMotd no # pam does that
As the comment says, PAM already handles sessions and prints the Motd.
# Harden crypto KexAlgorithms firstname.lastname@example.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 Ciphers email@example.com,firstname.lastname@example.org,email@example.com,aes256-ctr,aes192-ctr,aes128-ctr MACs firstname.lastname@example.org,email@example.com,firstname.lastname@example.org,hmac-sha2-512,hmac-sha2-256,email@example.com
These directives restrict the key-exchange algorithm, ciphers and MACs sshd will be allowed to choose. This prevents outdated and insecure clients from connecting. While writing this post, I updated these to follow Mozilla guidelines, though I already had very similar lists before.
Note: I no longer ssh into my server from Android, but in the past I had issues because the client i was using didn't support recent enough Ciphers, so watch out with this one.
Subsystem sftp internal-sftp
This directive configures sshd to use the built-in sftp daemon. This is required for the ChrootDirectory configuration used below.
Match Group ssh-sftp-user
This directive means that the rest of the file (until the next
Match directive) will only apply to users of the group ssh-sftp-user. I use it to better lock-down users that should only have sftp (file transfer) access.
Match directive takes effect until the end of the file, the next
Match or the next
Host. Do not get confused by the indentation, because it doesn't affect the scope!
X11Forwarding no AllowTcpForwarding no PermitTTY no
Disable X11 (discussed above) and TCP forwarding. TCP forwarding let users tunnel traffic through the server, for example using the
-R flags to the
Lock these users to their home directories for extra safety. This requires the lock directory to be owned by root and not writable by anyone else. For example: drwxr-x--- 7 root backup 4096 Feb 9 11:49 backup
Don't allow these users to run any commands other than the internal sftp implementation, again, to further restrict their access.