Securing a new Ubuntu install

First steps

So you've provisioned a shiny new Ubuntu OS on Digital Ocean or Linode, and the first thing you will want to do is lock it down. It's scary how quickly automated bots will find the newly provisioned server, start scanning for open ports and attempting to log in so they can turn your shiny server into a spewer of Viagra emails and promises of millions of dollars if you'll just hand over your name, date of birth and passport number.

Once the machine has booted up, you need to ssh to the server using it's IP address.

$ ssh root@SERVER_IP_ADDRESS

Once logged in the first thing to do is get any and all updates for the OS. So at the prompt run:

$ apt-get update

Followed by:

$ apt-get upgrade

Once all the updates have installed it may ask you to reboot.

A wild User has appeared

Now you want to create a new user account for all your normal use of the server. It's never good practise to be logged in as root on your system. Given the supreme power that root wields on a Linux server, it's far too easy to cause irreperable harm without meaning to.

In these examples we'll use the example username bob (as it's small and easy to remember).

So at the terminal enter:

$ adduser bob

The system will ask you a few questions, one of which being what password you want. Make sure you enter a strong one.

Relevant XKCD

The rest of the questions you will mostly leave blank if you are anything like me.

Escalating privileges

So this new user account just has standard user priviledges which won't be enough for those odd occasions when we do actually need to perform adminstration functions on the server.

To do this we will make use of the sudo command. "Sudo" gets put in front of any command that you wish to run with root priviledges. But to make use of this command we first need to add the user to the sudo group.

So still logged in as root, enter the following:

$ gpasswd -a bob sudo

Before performing the next step you may want to log out of root, log in with your normal account and ensure that the sudo command works as expected.

Disable root SSH login

So now you have your normal user account with sudo priviledges, you want to disable remote root access to the server. Root is one of the first user names the bots will attempt to access when scanning your server. Disallowing anyone to log in as root remotely removes that risk entirely, as now the attacker needs to know your personal username (you didn't use something simple like admin did you?) as well as your very strong password.

So enter the following:

$ sudo vim /etc/ssh/sshd_config

Then search the file for the section which says PermitRootLogin and set it to no.

PermitRootLogin no  

Save the file and exit vim. However, before restarting the ssh service make double (or triple) sure that your normal account has sudo priviledges otherwise you will have just locked yourself out of being able to admin your own server!

Once you are sure your account has the correct access, enter the following:

$ sudo service ssh restart

Public Key Authentication

The next step is to setup Public Key Authentication so you don't need to type in that pesky password every time you access the server.

If you don't already have an ssh key setup, then creating one is simple. At the console of your local machine, enter the following:

$ ssh-keygen -t rsa -C "your_email@example.com"
# Creates a new ssh key, using the provided email as a label
# Generating public/private rsa key pair.
# Enter file in which to save the key (/Users/you/.ssh/id_rsa): [Press enter]

This generates a private key, id_rsa, and a public key, id_rsa.pub, in the .ssh directory of the localuser's home directory. The private key is exactly that, private; do not share it with anyone.

Then from the home directory on your local machine enter the following:

$ cat ~/.ssh/id_rsa.pub

This will print your newly generated public key to your console which you can then copy to your new server.

So ssh back into your server using your normal user account, and make sure you are in your user's home directory. Which in this this example looks like:

$ pwd
/home/bob

Now create a new folder called .ssh. We also need to restrict the permissions so that if we have any other users on this system they can't access our ssh information.

$ mkdir .ssh
$ chmod 700 .ssh

Now create a file in the .ssh directory called authorized_keys.

$ vim .ssh/authorized_keys

Paste your public key into the file, save it and exit. Then restrict access to it.

$ chmod 600 .ssh/authorized_keys

You should now be able to log out, and then log back in using your private key as authentication.

Firewall

Next up is to setup a basic firewall. A firewall basically denies incoming traffic to every port on your server. Ubuntu has a simple one called ufw already installed. All we need to do to make use of it is tell it which ports we actually want to open to accept traffic, and then turn it on.

As we ssh into this remote server, that's the first port we need to open, otherwise we will manage to lock ourselves out of our own server again.

$ sudo ufw allow ssh

This is the bare minimum you need to setup, but if you plan on using your server for additional services (such as a webserver) you will need to open each port required. Http(s) for example requires the following:

$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp

And email would also require:

$ sudo ufw allow 25/tcp

Once you think you have finished adding enough services you can see the rules with the following:

$ sudo ufw show added

And if you're happy with everything, lets turn it on!

$ sudo ufw enable

You will be asked to confirm that you want to turn the firewall on - you did add the ssh rule right? - and once accepted the firewall will apply all your rules to all incoming traffic.

NTP

Installing NTP will allow your computer to stay in sync with other servers. On Ubuntu all that is required to setup time synchronisation is type in the following:

$ sudo apt-get update
$ sudo apt-get install ntp

Read only shared memory

A common exploit vector is going through shared memory (which can let you change the UID of running programs and other malicious actions). It can also be used as a place to drop files once an initial break-in has been made.

So the first thing we will do is secure the shared memory. Enter the following into the command prompt:

$ sudo vim /etc/fstab

Then add the following line at the bottom of the file:

tmpfs /dev/shm   tmpfs defaults,ro     0    0  

Exit and save the file, then reboot the system.

Fail2ban

Lots of servers get a steady stream of attacks on ssh. To make it harder for any would-be attacker we can use Fail2ban which makes use of iptables to block an attacker for a defined period of time.

$ sudo apt-get update
$ sudo apt-get install fail2ban

The fail2ban service keeps its configuration files in the /etc/fail2ban directory. The default configuration file is called jail.conf. Since this file can end up getting modified by package upgrades, we shouldn't edit this file in-place, but rather copy it so that we can make our changes in relative safety.

In order for fail2ban to find the configuration file we need to copy the default file to jail.local.

$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local

Once the file is copied, we can open it for editing to see how everything works.

sudo vim /etc/fail2ban/jail.local  

The first section in the file is labelled [DEFAULT] and the settings listed in there are applied to all following services.

The first thing to change is the length of time that a ban is instituted for.

bantime = 1800  

We also need to configure the email address to which all alert information will be sent to.

destemail = admin@example.com  

You can also set the sendername to something else if you'd like. It's useful to have a value that can be easily filtered using your mail service though, else your inbox may get flooded with alerts if there are a lot of break in attempts from various places (and there will be).

Further down the file you will see a setting called action.

action = %(action_)s  

You will want to change the line to look like the following:

action = %(action_mwl)s  

This will enable the email of all reports and will also include the log files for easier debugging in the event that something does happen.

The last section of the file lists all the different services that fail2ban can be configured for. We want to ensure that fail2ban is setup for ssh - and if for example you are running a blog or website on nginx then you will also want to enable it for http authorisation attempts.

Simply locate both the [ssh] and [nginx-http-auth] sections and set enabled to true in both.

enabled = true  

Once you're happy with your settings save and exit the file, then restart the fail2ban service.

$ sudo service fail2ban restart

It won't be long until you start receiving emails informing you of all the IP addresses that have been blocked.

Restrict access to "su"

We only want to allow admin users to use the su command. This helps prevent privilege escalation attacks. Ubuntu may already have an admin group but if not, run the following:

$ sudo groupadd admin

Then add yourself to the group

$ sudo usermod -a -G admin bob

Now restrict access to /bin/su to admin group members

$ sudo dpkg-statoverride --update --add root admin 4750 /bin/su

You can then check these permission with the following:

$ ls -lh /bin/su

And you should see the following:

-rwsr-x--- 1 root admin 31k 2011-11-24 14:16 /bin/su

Sysctl Hardening

Now to harden the IP stack.

$ sudo vi /etc/sysctl.conf

Now locate the line:

net.ipv4.conf.all.accept_source_route=0  

You should just have to uncomment it. Then below it add the following line:

net.ipv4.conf.default.accept_source_route=0  

You could use the sysctl command to do these instead but this way they will persist beyond a reboot.

Check for rootkit presence

Chkrootkit scans the system for evidence that a rootkit has been installed. This is a confidence test to be used to check whether your system has been compromised. It’s worth running periodically.

To install:

$ sudo apt-get install -y chkrootkit

Then to run it:

$ sudo chkrootkit

At the time of writing there seems to be bug with chkrootkit that lists /sbin/init as containing a Suckit rootkit infection. This is a false positive.

Detect attempted intrusions

Psad is a collection of lightweight daemons that log attempted intrusions, in particular monitoring iptables.

$ sudo apt-get install -y psad

The daemons will run automatically once installation is complete. To check the current status:

$ sudo psad -S

You can modify the psad settings to e-mail the admin on the event of an intrusion detection.

Watch those logs

The most detailed and informative logs in the world are about as much use as a chocolate teapot if no one looks at them. Logwatch winnows the deluge down to a succinct report which hopefully you will look at.

$ sudo apt-get install -y logwatch

Then to produce the report:

$ sudo logwatch | less

Ongoing maintenance

Now that the server is more secure, once a week perform on-going maintenance like ensuring your software is up to date:

$ sudo apt-get update
$ sudo apt-get upgrade

And done

That's it. Your server should now be a lot more secure than it was before. However bear in mind, no matter how secure a system, a determined and skilled attacker will always find a way in; but at least now the job is a lot harder and this should protect you from the majority of bots out there.

Enjoy your new server!