A few years ago I wrote a quite popular post for security hardening on Ubuntu 14.04, and now here’s a new version for CentOS 7 and RHEL 7. Much of it should apply to CentOS/RHEL versions 6 and 8, with some tweaks required here and there. It should also largely work with Amazon Linux and Amazon Linux 2, although again some tweaks will be required for those.
Assume that all these operations need to be performed as root, which you can do by logging in as root with
sudo -i
(or you can issue an endless series of sudo
commands if you prefer).
Update: I have now automated this process in the form of Ansible playbooks which you can use. The playbooks are in a repository on my GitHub, and I’ve written a new blog post with more details about them and how they work.
Harden SSH
I generally regard it as a sensible idea to disable root login over SSH, so in /etc/ssh/sshd_config you should change PermitRootLogin
to no
.
If SSH on your servers is open to the world then I also advise running SSH on a non-standard port in order to avoid incoming SSH hacking attempts. To do that, in /etc/ssh/sshd_config change Port
from 22
to another port of your choice, e.g. 1022
. Note that you’ll need to update your firewall or EC2 security rules accordingly.
After making changes to SSH, reload the OpenSSH server:
systemctl reload sshd
Improve IP security
Create the file /etc/sysctl.d/10-network-security.conf and add the following lines to improve IP security:
# Ignore send redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Block SYN attacks
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Log Martians
net.ipv4.conf.all.log_martians = 1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
# Ignore Directed pings
net.ipv4.icmp_echo_ignore_all = 1
Load the new rules:
sysctl --system
PHP hardening
If you’re using PHP, these are changes worth making in /etc/php.ini in order to improve the security of PHP:
- Add
exec
,system
,shell_exec
, andpassthru
todisable_functions
. - Change
expose_php
toOff
. - Ensure that
display_errors
,track_errors
andhtml_errors
are set toOff
.
Apache hardening
If you’re using Apache web server, it’s worth making sure you have the following parameters set in the config (/etc/httpd/conf/httpd.conf by default) to make sure Apache is suitably hardened:
ServerTokens Prod
ServerSignature Off
TraceEnable Off
Header unset ETag
FileETag None
Then restart Apache:
systemctl restart httpd
Install and configure ModSecurity
If you’re using Apache, the web application firewall ModSecurity is a great way to harden your web server so that it’s much less vulnerable to probes and attacks. Firstly, install the necessary packages:
yum install mod_security
Install zip/unzip if you don’t already have them:
yum install zip unzip
Next, install the Open Web Application Security Project ModSecurity Core Rule Set:
cd /tmp
curl -L -O https://github.com/coreruleset/coreruleset/archive/refs/heads/v3.3/master.zip
unzip master.zip
mv coreruleset-3.3-master /etc/httpd/owasp_crs
mv /etc/httpd/owasp_crs/crs-setup.conf.example /etc/httpd/owasp_crs/crs-setup.conf
To add the rules to Apache, edit /etc/httpd/conf.d/mod_security.conf and add the following lines near the end, just before </IfModule>
:
Include owasp_crs/crs-setup.conf
Include owasp_crs/rules/*.conf
Restart Apache to activate the new security rules:
systemctl restart httpd
Install and configure mod_evasive
If you’re using Apache then it’s a good idea to install mod_evasive to help protect against denial of service attacks. Firstly install the EPEL repository:
yum install epel-release
Then install mod_evasive:
yum install mod_evasive
Restart Apache to activate it:
systemctl restart httpd
Install and configure rootkit checkers
It’s highly desirable to get alerted if any rootkits are found on your server, so let’s install a rootkit checker:
yum install rkhunter
Let’s run rkhunter weekly instead of daily, because daily is too annoying:
mv /etc/cron.daily/rkhunter /etc/cron.weekly
Install Logwatch
Logwatch is a great tool which provides regular reports nicely summarising what’s been going on in the server logs. Install it like this:
yum install logwatch
Make it run weekly instead of daily, otherwise it gets too annoying:
mv /etc/cron.daily/0logwatch /etc/cron.weekly
Make it show output from the last week by editing the script /etc/cron.weekly/0logwatch and changing the line
$LOGWATCH_SCRIPT $OPTIONS
to the following:
$LOGWATCH_SCRIPT $OPTIONS --range 'between -7 days and -1 days'
Enable process accounting
Linux process accounting keeps track of all sorts of details about which commands have been run on the server, who ran them, when, etc. It’s a very sensible thing to enable on a server where security is a priority, so let’s install and activate it:
yum install psacct
systemctl enable psacct
systemctl start psacct
To show users’ connect times, run ac
. To show information about commands previously run by users, run sa
. To see the last commands run, run lastcomm
. Those are a few commands to give you an idea of what’s possible; just read the manpages to get more details if you need to.
I threw together a quick Bash script to send a weekly email with a summary of user activity, login information and commands run. To get the same report yourself, create a file called /etc/cron.weekly/pacct-report containing the following (don’t forget to make this file executable) (you can grab this from GitHub if you prefer):
#!/bin/bash
users=$(cat /etc/passwd | awk -F ':' '{print $1}' | sort)
echo "USERS' CONNECT TIMES"
for user in $users ; do
ac=$(ac -d $user)
[ -n "$ac" ] && echo -e "\n${user}:\n\n${ac}"
done
echo ""
echo "COMMANDS BY USER"
echo ""
for user in $users ; do
comm=$(lastcomm --user $user | awk '{print $1}' | sort | uniq -c | sort -nr)
if [ "$comm" ] ; then
echo "$user:"
echo "$comm"
fi
done
echo ""
echo "COMMANDS BY FREQUENCY OF EXECUTION"
echo ""
sa | awk '{print $1, $6}' | sort -n | head -n -1 | sort -nr
Things I haven’t covered
There are some additional issues you might want to consider which I haven’t covered here for various reasons:
- This guide assumes your server is on a network behind a firewall of some kind, whether that’s a hardware firewall of your own, EC2 security rules on Amazon Web Services, or whatever; and that the firewall is properly configured to only allow through the necessary traffic. However, if that’s not the case then you’ll need to install and configure a firewall on the server itself. The recommended software for this would probably be
firewalld
. - Given the rise in hacking, nowadays I would advise that placing your SSH server on a non-standard port (as described above) may not be sufficient on its own. Seriously consider the use of firewall rules or Security Groups (on AWS) to lock down your SSH access to a minimal number of authorised IP addresses. If that’s not an option, look into the use of fail2ban as a serious hacking prevention tool. Always monitor your security logs on a regular basis in order to identify incoming hacking attempts.
- Once you’ve hardened your server, you’re advised to run some vulnerability scans and penetration tests against it in order to check that it’s actually as invincible as you’re now hoping it is. This is a topic which requires a post all of its own so I won’t be covering it in any detail here, but a good starting point if you’re not already familiar with it is the excellent Nmap security scanner.
If you need help with server security or any other infrastructure issues, check out my SysAdmin and DevOps services and feel free to get in touch.