Chapter 10: Secure remote access

Configuring and hardening the SSH server

The SSH server, sshd, is the most exposed service on most machines, and the one you use to repair everything else. That is why changing its configuration deserves care: a typo can lock you out of the very server you are managing. This lesson shows where the settings live, how sshd decides between conflicting lines, and a routine for changing it safely.

Where the settings are

The server reads /etc/ssh/sshd_config. Its first active line includes every file in /etc/ssh/sshd_config.d/ (Include /etc/ssh/sshd_config.d/*.conf), so you can keep local changes in a small file of your own instead of editing the packaged one. On RHEL the directory already holds files from the distribution and from cloud-init:

[root@servera ~]# ls /etc/ssh/sshd_config.d
50-cloud-init.conf  50-redhat.conf
[root@servera ~]# grep -n "^Include" /etc/ssh/sshd_config
15:Include /etc/ssh/sshd_config.d/*.conf

Settings you will meet most often:

SettingDoesHardened value
PermitRootLoginMay root log in over SSH? prohibit-password (the default here) allows root with a key onlyno once everyone can use sudo
PasswordAuthenticationAllow password loginsno, once keys work
PubkeyAuthenticationAllow key loginsyes
MaxAuthTriesFailed attempts per connection3
X11ForwardingGraphical forwardingno on servers
AllowUsers / AllowGroupsOnly these accounts may log inA short list
PortThe listening portChanging it is not real protection

The first value wins

When an option appears more than once, sshd keeps the first value it reads, and the drop-in files are read in alphabetical order, before the rest of the main file. This surprises almost everybody, so look at it carefully:

Which line wins?: sshd uses the first value it finds. Step through the files in the order sshd reads them.

Cloud-init ships 50-cloud-init.conf with PasswordAuthentication yes. A 99-hardening.conf saying no is read later and ignored. Name your file 10-hardening.conf so it is read first:

[root@servera ~]# printf 'PasswordAuthentication no\nX11Forwarding no\nMaxAuthTries 3\n' > /etc/ssh/sshd_config.d/10-hardening.conf
[root@servera ~]# sshd -T | grep -E '^(passwordauthentication|x11forwarding|maxauthtries) '
maxauthtries 3
passwordauthentication no
x11forwarding no

Never trust the file you wrote: sshd -T shows the value sshd would really use. sshd -t only checks the syntax, and prints nothing when it is fine; a typo is reported with its line:

[root@servera ~]# sshd -t
/etc/ssh/sshd_config.d/20-typo.conf: line 1: Bad configuration option: PasswordAuthenticaton
/etc/ssh/sshd_config.d/20-typo.conf: terminating, 1 bad configuration options

Change it without locking yourself out

Change sshd without locking yourself out: Step through the safe routine.

[root@servera ~]# sshd -t && systemctl reload sshd
[root@servera ~]# journalctl -u sshd -n 2 --no-pager

reload makes sshd re-read its files while existing connections stay up; a full restart would drop them. And if a change denies you access, the session you kept open, or the console, is how you undo it.

Watching what happens

Every login, accepted or refused, is logged with the user, the source address and the method:

[root@servera ~]# journalctl -u sshd --no-pager | tail -3 | cut -c40-
sshd-session[1049]: Accepted publickey for ops from 172.25.251.9 port 41346 ssh2: ED25519 SHA256:5AQb...
sshd-session[1049]: pam_unix(sshd:session): session opened for user ops(uid=1001) by (uid=0)
sshd-session[1049]: pam_unix(sshd:session): session closed for user ops

The same lines appear in /var/log/secure. After you disable passwords, a refused attempt from a client looks like this:

[student@workstation ~]$ ssh -o PubkeyAuthentication=no ops@servera true
ops@servera: Permission denied (publickey,gssapi-keyex,gssapi-with-mic).

Note that password is gone from the list of accepted methods.

Try it

Check your understanding