TT Lab
Get started
Learn Learning paths Courses

SSH and File Transfer

Hardening sshd

Continue in TT Lab

Goal

You harden sshd with a drop-in configuration file, verify with sshd -t and sshd -T, and then actually confirm that key access is maintained and password authentication is rejected.

Why it matters

Editing sshd on a remote server is cutting the branch you are sitting on. That is why the order is fixed: keep the session → edit → sshd -t → reload → confirm with a new session → only then end the existing session. And recent distributions split the configuration with Include /etc/ssh/sshd_config.d/*.conf. Because the first value wins when the same key appears several times, "I fixed it but it has no effect" is common. The habit of checking the final applied values with sshd -T blocks this problem at the source.\n\n## This lab runs on a virtual machine\n\nBecause sshd runs as a real systemd service, you can make it reread the configuration with systemctl reload ssh and confirm by connecting with a new session. It used to run in a Pod, where there was no systemctl and you had to handle the process directly with pkill sshd.\n\nWe took care of one thing in advance when setting up the environment. Ubuntu 24.04 has ssh.socket turned on, and in that state systemd decides the listening port — the Port in sshd_config is ignored. Even if you edit the configuration and restart, it listens only on 22, and there is neither an error nor a warning. To open the lab's port 2222, we turned off socket activation and turned on ssh.service. If you run into "I changed the port but it doesn't open" on a real server, look here first.\n\nWe leave port 22 as it is. It is so that there is a way back even if you write the configuration wrong — on a real server too, for the same reason, you open the new port first and check it before closing the old port.

Steps

  1. Create the /root/harden directory and save the complete current effective configuration to /root/harden/baseline.txt.
  2. Create /etc/ssh/sshd_config.d/90-labhub.conf and put in the following values. PasswordAuthentication no, KbdInteractiveAuthentication no, PubkeyAuthentication yes, MaxAuthTries 3, LoginGraceTime 30, X11Forwarding no, PermitEmptyPasswords no, LogLevel VERBOSE
  3. Run the syntax check, confirm that it passes, and write the exit code to /root/harden/syntax.txt in the format rc=0.
  4. From the final applied values, pick out only the four lines passwordauthentication, kbdinteractiveauthentication, maxauthtries, and logingracetime, and save them to /root/harden/effective.txt.
  5. At the end of the same file, add a Match User backup block with ForceCommand internal-sftp and AllowTcpForwarding no. Then save the effective configuration under that condition to /root/harden/match.txt. forcecommand internal-sftp must be visible in the file.
  6. In /root/.ssh/authorized_keys, put the option restrict,pty,from="127.0.0.0/8" at the very start of the line that holds the id_labhub key. (You have to turn pty back on for shell access to be maintained.)
  7. After starting sshd again, confirm two things.
    • Key access still succeeds → save the result to /root/harden/still-works.txt
    • If you request only password authentication, it is rejected → save that error output to /root/harden/password-denied.txt
  8. Make /root/harden/checklist.txt with the following 5 lines. The values are based on the sshd -T output. passwordauthentication=no / kbdinteractiveauthentication=no / pubkeyauthentication=yes / maxauthtries=3 / logingracetime=30

Notes

Recording the current effective configuration

Create the /root/harden directory and save the complete current effective configuration to /root/harden/baseline.txt.

sshd has an extended test mode that prints all the finally applied values. It is a different option from the syntax check.

Writing the drop-in configuration

Create /etc/ssh/sshd_config.d/90-labhub.conf and put in the following values. PasswordAuthentication no, KbdInteractiveAuthentication no, PubkeyAuthentication yes, MaxAuthTries 3, LoginGraceTime 30, X11Forwarding no, PermitEmptyPasswords no, LogLevel VERBOSE

Make it a .conf file under sshd_config.d. The number at the front of the file name decides the reading order.

The syntax check passes

Run the syntax check, confirm that it passes, and write the exit code to /root/harden/syntax.txt in the format rc=0.

The option that checks only the syntax prints nothing if it succeeds. Judge by the exit code.

Checking the applied values

From the final applied values, pick out only the four lines passwordauthentication, kbdinteractiveauthentication, maxauthtries, and logingracetime, and save them to /root/harden/effective.txt.

The output of the extended test mode has all lowercase keys. Pick out only the four you need.

Conditional application with a Match block

At the end of the same file, add a Match User backup block with ForceCommand internal-sftp and AllowTcpForwarding no. Then save the effective configuration under that condition to /root/harden/match.txt. forcecommand internal-sftp must be visible in the file.

The extended test mode has an option that gives connection conditions. You write the three values user, host, and addr joined by commas.

Strengthening the authorized_keys options

In /root/.ssh/authorized_keys, put the option restrict,pty,from="127.0.0.0/8" at the very start of the line that holds the id_labhub key. (You have to turn pty back on for shell access to be maintained.)

Use together the option that restricts the source and the option that turns off all features. You have to allow the loopback range for the connection to be maintained.

Check first: this step works on the ~/.ssh/id_labhub key. That key was made in the earlier lab (SSH key authentication), but each lab starts a new box, so it is not here. Check with ls ~/.ssh and if it is missing, create it first.

ssh-keygen -t ed25519 -N '' -f ~/.ssh/id_labhub
cat ~/.ssh/id_labhub.pub >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Real verification after the restart

After starting sshd again, confirm two things.

You have to start sshd again for the settings to take effect. This environment has no systemctl, so handle the process directly.

Hardening checklist

Make /root/harden/checklist.txt with the following 5 lines. The values are based on the sshd -T output. passwordauthentication=no / kbdinteractiveauthentication=no / pubkeyauthentication=yes / maxauthtries=3 / logingracetime=30

You can take the values as they are from the sshd -T output. Keep them all lowercase.