We’ve already locked things down pretty well just by requiring that clients authenticate via key exchange, rather than by username and password. When we prohibit password authentication, the bad guys can do brute-force password attacks against us until the cows come home, and it won’t do them any good. (Although, in truth, they’ll just give up as soon as they find that password authentication has been disabled.) For an extra measure of security, we can also set up a couple of access control mechanisms that will allow only certain users, groups, or client machines to log in to an SSH server. These two mechanisms are as follows:
- Whitelists within the sshd_config file
- TCP Wrappers, via the /etc/hosts.allow and /etc/hosts.deny files
The four access control directives that you can set within sshd_config are as follows:
For each directive, you can specify more than one username or group name, separating them with a blank space. Also, these four directives are processed in the order that I’ve listed them here. In other words, if a user is listed with both the DenyUsers and the AllowUsers directives, DenyUsers takes precedence. If a user is listed with DenyUsers and is a member of a group that’s listed with AllowGroups, DenyUsers again takes precedence. To demonstrate this, let’s complete a lab.
This lab will work on any of your VMs. Follow these steps:
- On the VM that you wish to configure, create user accounts for Frank, Charlie, and Maggie. On Ubuntu, do the following:
sudo adduser frank . . .
On CentOS, do the following:
sudo useradd frank sudo passwd frank . . .
- Create the webadmins group and add Frank to it:
sudo groupadd webadmins sudo usermod -a -G webadmins frank
- From either your host machine or from another VM, have the three users log in. Then, log them back out.
- Open the /etc/ssh/sshd_config file in your favorite text editor. At the bottom of the file, add an AllowUsers line with your own username, like so:
- Then, restart the SSH service and verify that it has started correctly:
For Ubuntu: sudo systemctl restart ssh sudo systemctl status ssh For CentOS: sudo systemctl restart sshd sudo systemctl status sshd
- Repeat step 3. This time, these three kitties shouldn’t be able to log in. Open the /etc/ssh/sshd_config file in your text editor. This time, add an AllowGroups line to the bottom of the file for the webadmins group, like so:
- Restart the SSH service and verify that it started properly.
From either your host machine or another VM, have Frank try to log in. You’ll see that even though he’s a member of the webadmins group, he’ll still be denied. That’s because the AllowUsers line with your own username takes precedence.
- Open sshd_config in your text editor and remove the AllowUsers line that you inserted in step 4. Restart the SSH service and verify that it started properly.
- Try to log into your own account, and then try to log into the accounts of all the other users. You should now see that Frank is the only one who is allowed to log in. The only way that any of the other users can now log into the VM is from the VM’s local console.
- Log into your own account at the VM’s local console. Delete the AllowGroups line from sshd_config and restart the SSH service.
You’ve reached the end of the lab – congratulations!
You’ve just seen how to configure a whitelist on the daemon level, using the SSH daemon’s own configuration file. Next, we’ll look at configuring whitelists at the network level.
It’s a strange name, but a simple concept. TCP Wrappers – singular, not plural – listens to incoming network connections, and either allows or denies connection requests. Whitelists and blacklists are configured in the /etc/hosts.allow file and the /etc/hosts.deny file. Both of these files work together. If you create a whitelist in hosts.allow without adding anything to hosts.deny, nothing will be blocked. That’s because TCP Wrappers consults hosts.allow first, and if it finds a whitelisted item there, it will just skip over looking in hosts.deny. If a connection request comes in for something that isn’t whitelisted, TCP Wrappers will consult hosts.allow, find that there’s nothing there for the source of this connection request, and then will consult hosts.deny. If nothing is in hosts.deny, the connection request will still go through. So, after you configure hosts.allow, you have to also configure hosts.deny in order to block anything.
Now, here’s something that’s extremely important. Always, always, configure hosts.allow before you configure hosts.deny. That’s because as soon as you save either one of these files, the new configuration immediately takes effect. So, if you configure the blocking rule in hosts.deny while logged in remotely, your SSH connection will break just as soon as you save the file. The only way to get back in will be to enter the server room and reconfigure things from the local console. Your best bet is to get used to the idea of always configuring hosts.allow first, even when you’re working from the local console. That way, you’ll always be sure. (Amazingly, though, there are other TCP Wrappers tutorials out there that tell you to configure hosts.deny first. What are these guys thinking?)
You can do some rather fancy tricks with TCP Wrappers, but for now, I just want to keep things simple. So, let’s look at some of the most-used configurations.
To whitelist a single IP address, place a line like this into the /etc/hosts.allow file:
Then, place this line into the /etc/hosts.deny file:
Now, if you try to log in from anywhere else besides the IP address that’s listed in hosts.allow, you will be denied access.
You can also list either multiple IP addresses or network addresses in hosts.allow. For details on how to do this, see the hosts.allow man page.
As I mentioned previously, you can do some fancy things with TCP Wrappers. But, now that the Red Hat folk have deprecated it, you’re probably better off just setting up firewall rules instead. On the other hand, TCP Wrappers could come in handy whenever you need to configure an access control rule very quickly.