There is no such thing as a completely secure server: as long as you provide public access to services running on a server, there is a risk that somebody at some point is going to try something like a privilege escalation or denial of service. What one can do is to minimize the chance of success of such attack or at least to minimize the damages.
I am not going to provide here some “high tech” security mechanisms but rather some “common sense” ones; such measures will most likely prevent speculative attackers or bots from doing their stuff. Let’s start with the first trick from the book:
1. Set up iptables
One may think: why set the firewall up? If I provide 3 services to the world and those are the only ones with listening sockets, why would I need a completely configured firewall?
The answer is: the firewall is always necessary. Having a policy of “deny all + exceptions” will render useless any rogue service that an attacker may inject through some privilege escalation attack.
On a RedHat (CentOS) system one will find the firewall configuration file as /etc/sysconfig/iptables. A typical restrictive configuration might be:
*filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT ACCEPT [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m multiport --dports 22,80,443 -j ACCEPT
The configuration above allows new tcp traffic (new connections) to ports 22 (ssh), 80 (http) and 443 (https), while allowing all outgoing traffic and also the responses received in relation to such traffic. It also allows icmp (ping), but denies everything else.
SELinux is that “thing” that breaks functionalities and makes sysadmins think there is some magical force preventing whatever process to write on a 777 permission file or connecting to a socket. Usually learning how to configure SELinux and disable particular restrictions is the best way to go, but when deploying multiple nodes for dev testing or qa behind a firewall or in a private network (virtual cloud) the fast solution is preferred.
Some typical “access denied” issues caused by SELinux are:
Configuring the database engine to access files on a different mount point (e.g. some storage freshly allocated in AWS). The database works flawlessly with data files on a certain path but after mounting the storage and putting the same file on the same path, the startup fails.
Postfix cannot deliver local mails through the LMTP socket (e.g. used by Cyrus Imap or Dovecot).
Errors with accessing paths in PHP scripts (well, not always a bad thing, this one).
Taking down SELinux is easy. The config file is /etc/selinux/config and the typical content is:
# This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - SELinux is fully disabled. SELINUX=enforcing # SELINUXTYPE= type of policy in use. Possible values are: # targeted - Only targeted network daemons are protected. # strict - Full SELinux protection. SELINUXTYPE=targeted # SETLOCALDEFS= Check local definition changes SETLOCALDEFS=0
The obvious “fix” is to replace enforcing with any of the other 2 options. The “permissive” one will fill up a log with various warnings and would-be restrictions that can help do some proper configuration. But the real solution is to just put “disabled” in there and forget about it. *
Oh, and the node must be restarted:
$ sudo telinit 6
That’s it, have fun!
* No, this is not the real solution on a security-aware environment. Learning SELinux is the actual way to go for the long term (while I agree to you that the syntax is messy and the controls are way too fine grained, which is a good and a bad thing at the same time). More reading on this topic: