Server hardening tips

You got a Linux server and you want to prevent security issues: follow these instructions.

In this article I write what I do when I get a Linux server. Steps are really minimal ‘cause I am lazy. I hope they are enough to prevent security issues.

I assume OS is a Centos 7. If you are using Ubuntu, few modifications are needed, using apt-get instead of yum, service instead of systemctl, etc. Aside few details, the same concepts applies on both as well as other Linux distros.

ASAP

Do the following steps As Soon As Possible, i.e. when you access the server the first time.
  1. Login as root and change password, use a passphrase.
  2. Create a new user.
  3. Configure ssh, in particular to disable root access.
  4. Update software.

Configure ssh

If you login as root you will see a message like

Using username "root".
Last failed login: Fri Jan 16 07:09:14 CST 2015 from 183.136.216.4 on ssh:notty
There were 20011 failed login attempts since the last successful login.
Last login: Tue Jan 15 09:56:30 2015 from host16-249-static.143-193-b.business.telecomitalia.it

Yes, there will a lot of failed login attempts. It is incredible how the number grows. The Internet is a jungle!

Edit your /etc/ssh/sshd_config and set

Protocol 2
PermitRootLogin no
MaxAuthTries 2

So root user cannot login and any other user is disconnected if password is wrong.

Commit changes restarting ssh daemon

# systemctl restart sshd

For instance to change default port, for instance to 222

sudo perl -i -p -e 's/Port 22/Port 222/' /etc/ssh/sshd_config

After this you should not see the failed login attempts warning. Test it with

$ grep failed /var/log/secure | more

See also what does it mean “POSSIBLE BREAK-IN ATTEMPT!” in /var/log/secure.

Many articles recommend to change default ssh port. It is not really a security enhancement, but, yes it can reduce the number of break-in attempts. One really benefit that I found about changing port number is to set it to 443 to bypass restrictive corporate firewalls.
Consider using ssh-keygen and ssh-copy-id to configure ssh access without password.

How to

Update software

Keep kernel and other software up to date.

# yum update -y

You can schedule yum updates with yum-cron

# yum install yum-cron -y
# systemctl enable yum-cron.service
# systemctl start yum-cron
Automatic updates should be configured only in a test environment.

Run a server on port 80

If you want to run a server on port 80, do not run it has root. Use CAP_NET_BIND_SERVICE capabilities instead. Suppose, for example, you want to run a server using nodejs.

$ su -
# yum install libpcap -y
# setcap cap_net_bind_service=ep /path/to/node

Check it out with

$ getcap /path/to/node
/path/to/node = cap_net_bind_service+ep

Now any user can run a nodejs server on port 80. See also how do I grant permission on port <1024, in particular this quote.

Note that I used /path/to/node instead of /usr/bin/node cause I highly recommend to separate user software from system software. In this particular case, if you update Node using yum you will loose the cap_net_bind_service=ep setting and your server will fail to restart on port 80.

Restrict ssh access

As you can read in Configure ssh section, there are many login attempts. See it your self (sit down first 😱 )

tail -f /var/log/secure

You can use TCP wrapper lib to filter access to your host. Note that the following instructions work because sshd is compatible with tcpwrappers, in fact

$ ldd /usr/sbin/sshd | grep libwrap
        libwrap.so.0 => /lib64/libwrap.so.0 (0x00007fac80451000)

First of all remove ssh access to everyone, make sure your /etc/hosts.deny has the following line

sshd: ALL

Now you can give access selectively. For example, if you want to allow ssh access only from a class C IPv4 subnet, for instance 10.20.30 add to your /etc/hosts.allow the row

sshd: 10.20.30.

You are done! Now only accesses from trusted origin can enter.

How to block a country

Sadly, if you check where does the ssh failed login attempts come form, it turns out they are from China. You can use IPdeny lists to block or allow connections coming from a country.

For example, to deny connections from China you can launch, as root

echo -e \# $(date +%F): IP blocks from http://www.ipdeny.com/ipblocks/data/countries/cn.zone >> /etc/hosts.deny
#                                "cn" stands for China. Extract class B subnets.  Prepend "sshd:"; append "." .
#                                                     ↓                        ↓                              ↓
curl -L http://www.ipdeny.com/ipblocks/data/countries/cn.zone 2> /dev/null     | cut -d . -f1-2 | sort | uniq | while read subnet; do echo sshd: ${subnet}.; done >> /etc/hosts.deny
# Double check results appended to /etc/hosts.deny config!

Yes, double check results appended to your /etc/hosts.deny config file and compare them with your last logins. Just use a simple last | head -20 and more /etc/hosts.deny with a little bit from your brain.

Update server time

It is also a really good idea to sync server time. Some softwares like aws-sdk could break if timestamp is wrong.

Add this entry to root crontab

# Update server time.
0 * * * * ntpdate -s time.nist.gov

References