Hardened CentOS6 LEMP on Linode
December 11, 2011 by Jaryd Malbin
Part 1: Preliminary Setup
Lets start with a Linode512. I'll deploy the server with about 2.2GB dedicated to the "CentOS 6.0 Disk Image". This will leave ample room for a custom partitioning table (note: use Linode's partitioning tools if you're interested in using their backup service). Here's how I lay mine out:
CentOS 6.0 Disk Image: 5GB
Swap: 512MB
/home: 2GB
/root: 2GB
/data: 10GB
Next you're going to need to edit the configuration profile and assign the newly created partitions under Block Device Assignment. Save, then boot. Once your Linode boots connect via SSH or launch the ajax console (find the IP under the Remote Access tab).
# mkdir /data
# mkdir /new/root
# mount /dev/xvdc /home
# mount /dev/xvdd /root
# mount /dev/xvde /data
Your mountpoints will vary -- be sure to check your configuration profile.
# cp .* /new/root
// Add your new mounts to fstab
# vim /etc/fstab
/dev/xvdc /home ext3 defaults,nosuid,nodev 0 0
/dev/xvdd /root ext3 defaults,nodev 0 0
/dev/xvde /data ext3 defaults,noexec,nosuid,nodev 0 0
Reboot and verify your disks are properly mounted, then delete the /new/root dir.
# rm -rf /new/root
Finally, we'll update your Linode's hostname.
# echo "HOSTNAME=replaceme" >> /etc/sysconfig/network
# hostname "replaceme"
# vim /etc/hosts
12.34.56.78 replaceme.domain.tld replaceme
Hardened CentOS6 LEMP on Linode
December 11, 2011 by Jaryd Malbin
Part 2: Grsecurity
This article documents installing a grsec patched kernel. The grsec patch is a series of kernel modifications that enable the administrator to further enhance the security of the stock Linux kernel.
# wget http://www.kernel.org/pub/linux/kernel/v2.6/longterm/v2.6.32/linux-2.6.32.51.tar.gz
# tar xzvf linux*
# patch p1 < ../grsec*
# cd ..;mv linux-2.6.32.51 linux-2.6.32.51-grsec; cd linux*
# make menuconfig
// do not enable "Deny writing to /dev/kmem, /dev/mem, and /dev/port"
# mkdir /lib/modules/2.6.32.51-grsec
# make modules && make install
# mkdir -p /boot/grub;vim /boot/grubmenu.lst
title grsec-2.6.32.51-grsec
root (hd0)
kernel /boot/vmlinuz-2.6.32.51-grsec root=/dev/xvda console=tty0 console=hvc0 ro quiet
initrd /boot/initramfs-2.6.32.51-grsec.img
Shut down the Linode from the GUI manager and once again edit the configuration profile. Under Boot Settings change the kernel to "pv-grub-x86_32", and boot.
Hardened CentOS6 LEMP on Linode
December 11, 2011 by Jaryd Malbin
Part 3: SSHD
SSH is unquestionably awesome and virtually ubiquitous in serverland. Beyond remote connections, it is great for automated secure file transfer (SCP + keys), and tunneling/proxying when you don't need a full VPN solution. As great as it is there are certain pitfalls in its default configuration that are important to be aware of and to mitigate.
First we will build openssh from source and patch it with the HPN (High Performance Enabled SSH/SCP)
Build, Install
# wget http://filedump.se.rit.edu/pub/OpenBSD/OpenSSH/portable/openssh-5.8p1.tar.gz
# tar xzvf openssh*.tar.gz;cd openssh*
#define SSH_RELEASE SSH_VERSION
# ./configure && make
# make install
# rm -rf /etc/ssh/*
# ln -sv /usr/local/etc/ssh* /etc/ssh/
# ln -sv /usr/local/sbin/sshd /usr/sbin/
# ln -sv /usr/local/bin/ssh* /usr/bin/
# ln -sv /usr/local/bin/scp /usr/bin/
# chmod +x /etc/init.d/ssh
# service sshd start
# ssh -v root@localhost
# chkconfig sshd on
Configure SSH
Now that we have our custom patched sshd we can do some hardening. Please note that the configuration used below forces SSH to authenticate through public key only. For a guide to create sshkeys
# useradd -m -s /bin/bash jmalbin
# passwd
# vim /etc/ssh/sshd_config
Protocol 2
SyslogFacility AUTHPRIV
LogLevel INFO
AllowUsers jmalbin
PermitRootLogin no
RSAAuthentication yes
PubkeyAuthentication yes
PasswordAuthentication no
AllowTcpForwarding no
SSHD must be restarted before the configuration changes take effect, but it is not yet advisable to do so. We have not yet configured IPTables, and so if you restart now and lose connection you will be locked out of your machine.
SSH Keys
Note: These instructions are largely lifted from Smylers August 16th, 2011 blog post"SSH Can Do That? Productivity Tips for Working with Remote Servers". This guide is intended for use on a *nix platform. If you need to generate keys in a Windows operating environment then google 'puttygen'.
$ ssh-keygen
// Locate your public key (extension .pub) and copy it onto your server
$ ssh -i ~/.ssh/id_rsa jmalbin@your.host.tld
You're almost done, but don't forget that you must configure IPTables before you can safely restart SSHD with your new configuration.
Hardened CentOS6 LEMP on Linode
December 14, 2011 by Jaryd Malbin
Part 4: nginx
Nginx is a F/OSS (Free Open Source Software) high-performance HTTP server and reverse proxy. It has garnered significant attention in the last few months, announcing the 1.0 release and $3M of Series A funding.
# rpm -Uvh http://download.fedora.redhat.com/pub/epel/6/i386/epel-release-6-5.noarch.rpm
# rpm -Uvh http://dl.iuscommunity.org/pub/ius/stable/Redhat/6/i386/ius-release-1.0-8.ius.el6.noarch.rpm
# yum install pcre-devel
# cd /opt;wget http://nginx.org/download/nginx-1.0.11.tar.gz;tar -xzvf nginx*;cd nginx*;mkdir /var/lib/nginx
# vim src/http/ngx_http_header_filter_module.c +48
static char ngx_http_server_string[] = "Ninja Web" CRLF;
static char ngx_http_server_full_string[] = "Ninja Web" CRLF;
# make && make install
# useradd -s /sbin/nologin nginx
# cd /root/;wget -O init-rpm.sh http://jarydmalbin.com/scripts/662-init-rpm.sh;mv init-rpm.sh /etc/rc.d/init.d/nginx;chmod +x /etc/rc.d/init.d/nginx;chkconfig --add nginx;chkconfig nginx on
# /etc/init.d/nginx start
# ln -s /opt/nginx/conf/ /etc/nginx
# curl -v localhost
Bear in mind, your httpd won't be accessible outside of localhost because we have not yet configured IPTables.
Hardened CentOS6 LEMP on Linode
December 14, 2011 by Jaryd Malbin
Part 5: PHP
In this configuration we will use PHP-FPM (PHP FastCGI Process Manager) to get nginx serving PHP. By using PHP-FPM as opposed to Apache's mod_php we have a clear demarcation between the web and php processes. In this configuration it is more apt to think of PHP as its own application server. This has numerous benefits from a management perspective, and also reduces system overhead.
In addition to PHP-FPM, we will be installing the Suhosin protection system, and performing some baseline modifications to the php.ini file.
Install and Configure PHP
# yum -y install php53u-cli php53u php53u-fpm php53u-mysql php53u-suhosin
# vim /etc/php.ini
disable_functions = php_uname, getmyuid, getmypid, passthru, leak, listen, diskfreespace, tmpfile, link, ignore_user_abord, shell_exec, dl, set_time_limit, exec, system, highlight_file, source, show_source, fpaththru, virtual, posix_ctermid, posix_getcwd, posix_getegid, posix_geteuid, posix_getgid, posix_getgrgid, posix_getgrnam, posix_getgroups, posix_getlogin, posix_getpgid, posix_getpgrp, posix_getpid, posix, _getppid, posix_getpwnam, posix_getpwuid, posix_getrlimit, posix_getsid, posix_getuid, posix_isatty, posix_kill, posix_mkfifo, posix_setegid, posix_seteuid, posix_setgid, posix_setpgid, posix_setsid, posix_setuid, posix_times, posix_ttyname, posix_uname, proc_open, proc_close, proc_get_status, proc_nice, proc_terminate, phpinfo
display_errors = Off
register_globals = Off
allow_url_fopen = Off
allow_url_include = Off
expose_php = Off
file_uploads = Off
upload_tmp_dir = /var/php_tmp
upload_max_filesize = 2M
session.save_path = /var/lib/php/session
session.cookie_httponly = 1
session.cookie_domain = example.com
Your results may vary; these security options might need to be tweaked depending on your server and site requirements.
Configure Nginx for PHP
# mkdir /opt/nginx/conf/sites-enabled;vim /opt/nginx/conf/nginx.conf
include /opt/nginx/conf/sites-enabled/*;
# vim /etc/nginx/sites-enabled/example.com
listen 80;
server_name www.example.com example.com;
access_log /data/www/example.com/logs/access.log;
error_log /data/www/example.com/logs/error.log;
root /data/www/example.com/public_html;
location / {
index index.php index.html index.htm;
if (-f $request_filename) {
break;
}
rewrite ^.(.+)$ /index.php?url=$1 last;
}
location ~ .*\.php[345]?$ {
include /opt/nginx/conf/fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /data/www/example.com/public_html$fastcgi_script_name;
}
}
# touch /data/www/example.com/logs/access.log;touch /data/www/example.com/logs/error.log
# mkdir /data/www/example.com/public_html
# echo "hello world" > /data/www/example.com/public_html/index.php
# service php-fpm start
# service nginx restart
# service iptables stop
# curl -v example.com
# service iptables start
Hardened CentOS6 LEMP on Linode
December 14, 2011 by Jaryd Malbin
Part 6: IPTables
Some people prefer to use the iptables command line utility to modify their firewall. I'm not of this camp. I like vim :). Before we can get IPTables configured we have to sort out an init/Linode issue.
# cd /etc/init.d
# mv iptables ~/iptables.bak
# wget jarydmalbin.com/scripts/iptinit && cat iptinit | tr -d '\r' > iptables
# chmod +x iptables;rm -rf iptinit
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -i eth0 -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
# http
-A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT
-A INPUT -i eth0 -m state --state NEW -m tcp -p tcp -s 12.34.56.78 --dport 22 -j ACCEPT
-A INPUT -i eth0 -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -i eth0 -j REJECT --reject-with icmp-host-prohibited
COMMIT
For more advanced IPTables hardening techniques I recommend you refer to Neat Tricks with IPTables and IPTables Tips and Tricks. I highly suggest you consider implementing these.
# service iptables restart
