The Order and Verification of sshd Hardening
In one line
When you change the sshd configuration, the most important thing is not what value you put in but in what order you check. If you get it wrong, you lock yourself out.
Why this exists
Editing the sshd configuration on a remote server is like cutting the branch you are sitting on. If the configuration is wrong, sshd does not start, and if it does not start, there is no way in. On a cloud instance with no console access, you may have to recreate the whole instance.
That is why there is a procedure.
- Keeping the current session, open one more new terminal
- Edit the configuration file
- Check the syntax with
sshd -t - Reload the service
- Without closing the existing session, confirm the connection in the new terminal
- Close the existing session only after the confirmation is done
A great many people skip steps 3 and 5. And some of them end up going to the data center at dawn.
How it works
There are two check commands.
sshd -t # 문법만 검사
sshd -T | sort | head -40 # 실제 적용될 유효 설정 전체 출력
sshd -T -C user=deploy,host=10.0.3.14,addr=10.0.3.14 | grep -i 'passwordauth\|pubkey'
-t looks only at the syntax. -T shows all the values that are finally applied. The reason this difference matters is that recent distributions split the configuration into fragments.
Include /etc/ssh/sshd_config.d/*.conf
If the same key appears several times, sshd uses the first value. So if the Include is at the front of the file, the fragment files win, and if it is at the back, the main body wins. Half of "I definitely fixed it but it has no effect" comes from here. The habit of checking with -T blocks this problem at the source.
Recommended settings and the meaning of each value.
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
MaxAuthTries 3
LoginGraceTime 30
ClientAliveInterval 300
ClientAliveCountMax 2
AllowGroups sshusers
X11Forwarding no
PermitEmptyPasswords no
LogLevel VERBOSE
- The default of
PermitRootLoginisprohibit-password. Even in the default state, root's password login is already blocked and key login is allowed. To block it completely,no. - The default of
PasswordAuthenticationisyes. If you have switched to key authentication, you must change it explicitly tono. - The default of
KbdInteractiveAuthenticationis alsoyes. You may think you blocked passwords but people sometimes get in through this path, so turn it off as well. The old nameChallengeResponseAuthenticationis a deprecated alias. MaxAuthTriesdefaults to 6. When failures reach half of this value, they start being recorded in the log.LoginGraceTimedefaults to 120 seconds. It is better to shorten it so that connections that have not logged in are not held open long.LogLevel VERBOSEleaves the fingerprint of the key used for authentication in the log. If you have an audit requirement, it is effectively essential.
You create exceptions with a Match block.
Match Group sftponly
ChrootDirectory /srv/sftp/%u
ForceCommand internal-sftp
AllowTcpForwarding no
When its condition matches, Match overrides the settings up to the next Match or the end of the file. If the same keyword is satisfied in several Match blocks, only the first one applies. Because order changes the result, always verify with sshd -T -C ....
What it looks like in the field
Layered diagnosis when you cannot connect. Telling the three messages apart is half of the diagnosis.
Connection refused→ the daemon is not runningConnection timed out→ the path is blockedPermission denied (publickey)→ it connected and failed at authentication
And a tip for reading ssh -vvv. If it does not get as far as debug1: Connecting to, it is a network problem, and if Authentications that can continue repeats after Offering public key, the server rejected that key.
How not to lock yourself out while locking things down
Tightening the sshd configuration is one of the few jobs that can push you out of the machine yourself. If you keep to the order, that risk disappears.
Never cut the current session. Even if you restart sshd, connections already established are maintained. So keep that session alive and test the connection in a new window. If it works, then close the original session, and if it does not, revert from the original session.
sshd -t # 문법 검사. 통과해야 재시작한다
systemctl reload sshd
ssh -o BatchMode=yes user@host true # 다른 창에서
Look at both configuration locations. Recent distributions read /etc/ssh/sshd_config.d/*.conf
and the value that comes first wins. If you edited the main file and it has no effect, a drop-in
is deciding earlier.
sshd -T | grep -iE 'permitrootlogin|passwordauth|pubkeyauth|port'
sshd -T shows the values that will actually apply. It is more accurate than reading the files.
Do not tighten everything at once. Before you turn off password authentication, first check that everyone can get in with keys. If you turn it off without checking, from that moment some people cannot get in, and they learn of it when they need to.
Changing the port is noise reduction, not security. The automatic scan logs shrink but it does not stop real
attacks. Instead, restricting the allowed source addresses with a firewall or
blocking repeated failures with fail2ban is what is effective.
The three things that are really valuable are these.
| Setting | Effect |
|---|---|
PasswordAuthentication no |
Brute force does not work |
PermitRootLogin no |
You have to discover one more account name |
AllowGroups ssh-users |
A new account does not automatically gain access |
Secure console access. Check in advance whether you can get in through the cloud's serial console or IPMI. Tightening the sshd configuration on a server reachable only by ssh becomes a job with no way back.
What you will do in the next lab
You harden sshd with a drop-in configuration file and verify with sshd -t and sshd -T. You create a Match block and even check conditional application, and at the end you actually test whether key access still works and password authentication is rejected.