The Black Rabbit on Allowing Root SSH
The rule of thumb is to never allow root ssh. What if you had to?
You shouldn’t allow root ssh. Many problems are solved by that simple solution.
But what if you had to?
Any admin worth their salt will either ask why or say no, and they’d be right 99.9999% of the time. I’m with them.
For the purposes of this exercise, the reasons why aren’t important. You must allow root ssh. What do you do now? It’s a non-optimal situation, but there are steps you can take to lock things down.
Edit /etc/ssh/sshd_config to require a key pair:
PermitRootLogin without-password
If you’re concerned about backward compatibility, create a 4096 bit rsa key pair. If you don’t have such worries, use an ed25519 key pair instead. Give either key a nice long and cryptic passphrase. And of course only use ssh protocol 2.
Build a bastion host, and only allow ssh connections from that host. You can add the following FROM directive to the beginning of your public key:
from="<ip address>" (rest of key continues....)
Configure iptables to only allow port 22 connections from the bastion host.
Install fail2ban. Whitelist the bastion host. Set maxretry to 1 and bantime to -1 in /etc/fail2ban/jail.local. A bantime of -1 means forever, or until you manually clear it out.
If this an external facing system, install two network cards. One is on the internal network, the other faces the world. Only allow internal ssh traffic.
Only allow specific users or groups with the AllowGroups and AllowUsers directives in sshd_config.
Don’t allow empty passwords: PermitEmptyPasswords no
Disable host based authentication: HostBasedAuthentication no
But you said “you must allow root ssh”, what if that means external too? This is an even worse situation to be in, but let’s run with it even if we’re grimacing in horror.
Consider a second bastion host on the dmz that only allows connections from known ip addresses, no ranges. All connections must use ed25519 key pairs, backward compatibility is out the window.
You could also disconnect ssh sessions after a certain amout of time, and configure a very short login grace time.
ClientAliveInterval = 10800 # 3 hours...
ClientAliveCountMax = 0 # ... and only 3 hours
LoginGraceTime = 20s # 20 seconds
Don't whitelist any external addresses in fail2ban.
Connections to dmz hosts must come from either the internal or external bastion hosts.
You could change the port from 22 to something over 2000, if only to reduce the amount of automated bot attempts. A skilled attacker will look for this, of course. You’re simply filtering out the low hanging fruit and reducing noise. This step by itself is terrible security, only mere obscurity. But it is useful as part of a broader, layered stance.
Remember to log everything, preferably to a centralized logging server with good analysis tools. Have an iron-clad recovery plan in place and be prepared to burn servers to the ground at a moment’s notice. Keep salt handy.
Well said, William