How To : Setup CDN + WAF

  Security

This is how we setup our own CDN + WAF. Where multi node will be deployed and act as CDN (nginx) and WAF (modsecurity) installed.

Pre-installation before setup the CDN + WAF

yum clean all
yum erase NetworkManager mariadb-libs* -y
yum install perl wget screen net-tools bind-utils ntpdate vim unzip -y

• Disable the selinux

perl -pi -e "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
setenforce 0

• Stop and disable the firewalld

systemctl stop firewalld
systemctl disable firewalld

• Customize and optimize ssh service

cp /etc/ssh/sshd_config /etc/ssh/sshd_config.tmp
cat /etc/ssh/sshd_config.tmp | sed s/"#Port 22"/"Port 9321"/g > /etc/ssh/sshd_config
echo "" >> /etc/ssh/sshd_config
echo "Protocol 2" >> /etc/ssh/sshd_config
echo "" >> /etc/ssh/sshd_config
echo "Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,arcfour" >> /etc/ssh/sshd_config
echo "MACs hmac-sha1,hmac-ripemd160" >> /etc/ssh/sshd_config
echo "" >> /etc/ssh/sshd_config
echo "Protocol 2" >> /etc/ssh/sshd_config
perl -pi -e "s/\#ClientAliveInterval 0/ClientAliveInterval 900/g" /etc/ssh/sshd_config
perl -pi -e "s/\#ClientAliveCountMax 3/ClientAliveCountMax 3/g" /etc/ssh/sshd_config
echo "TMOUT=900" >> /etc/profile
systemctl restart sshd

• Update the server time, set cronjob to update it every day and auto update it every time server rebooted.

ntpdate time.ipserverone.com
echo "/sbin/ntpdate time.ipserverone.com" >> /etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
systemctl start rc-local
(crontab -l; echo "15 00 * * * /sbin/ntpdate time.ipserverone.com > /dev/null 2>&1") | crontab -

• Create user isupport and enable root privileges.

cp /etc/sudoers /etc/sudoers.tmp
cat /etc/sudoers.tmp | sed '/NOPASSWD/ a isupport        ALL=(ALL)       NOPASSWD: ALL' > /etc/sudoers
useradd isupport

• Install development tools, update all software packages that pre-installed and reboot the server.

yum groupinstall 'development tools' -y; yum update -y; reboot

• Install Kernel Version Checker

mkdir -p /ips1
cd /ips1
wget -O /ips1/ips1-kernel-checker --user=support --password=Jz8jx001 https://ns82.small-dns.com/setup/ips1-kernel-checker
chmod +x /ips1/ips1-kernel-checker
(crontab -l; echo "30 22 * * * /ips1/ips1-kernel-checker > /dev/null 2>&1" ) | crontab -

Install libmodsecurity

yum install gcc-c++ flex bison yajl yajl-devel curl-devel curl GeoIP-devel \
doxygen zlib-devel httpd-devel pcre-devel libxml2-devel libtool autoconf \
automake openssl-devel pcre-devel -y

cd /opt
git clone https://github.com/SpiderLabs/ModSecurity
cd ModSecurity
git checkout -b v3/master origin/v3/master
sh build.sh
git submodule init
git submodule update
./configure
make && make install

useradd --no-create-home nginx
export MODSECURITY_INC="/opt/ModSecurity/headers/"
export MODSECURITY_LIB="/opt/ModSecurity/src/.libs/"
cd /opt
git clone https://github.com/SpiderLabs/ModSecurity-nginx
git clone https://github.com/openresty/headers-more-nginx-module.git

wget https://nginx.org/download/nginx-1.14.0.tar.gz
tar xvf nginx-1.14.0.tar.gz
cd nginx-1.14.0
vi install.sh

Copy and paste the following installation script,

#!/bin/bash

./configure \
        "--user=nginx" \
        "--group=nginx" \
        "--prefix=/usr" \
        "--sbin-path=/usr/sbin" \
        "--conf-path=/etc/nginx/nginx.conf" \
        "--pid-path=/var/run/nginx.pid" \
        "--http-log-path=/var/log/nginx/access_log" \
        "--error-log-path=/var/log/nginx/error_log" \
        "--without-mail_imap_module" \
        "--without-mail_smtp_module" \
        "--with-http_ssl_module" \
        "--with-http_realip_module" \
        "--with-http_stub_status_module" \
        "--with-http_gzip_static_module" \
        "--with-http_dav_module" \
        "--with-cc-opt='-D FD_SETSIZE=32768'" \
        "--with-ld-opt='-Wl,-rpath,/usr/local/lib/'" \
        "--add-module=/opt/headers-more-nginx-module" \
        "--add-module=/opt/ModSecurity-nginx"

Install the Nginx with module of modsecurity and header enabled.

sh install.sh
make && make install

Verify if the Nginx installation is OK or not.

# nginx -t
......
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
......

# nginx -V
......
nginx version: nginx/1.14.0
built by gcc 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC)
built with OpenSSL 1.0.2k-fips  26 Jan 2017
TLS SNI support enabled
configure arguments: --user=nginx --group=nginx --prefix=/usr --sbin-path=/usr/sbin --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid --http-log-path=/var/log/nginx/access_log --error-log-path=/var/log/nginx/error_log --without-mail_imap_module --without-mail_smtp_module --with-http_ssl_module --with-http_realip_module --with-http_stub_status_module --with-http_gzip_static_module --with-http_dav_module --with-cc-opt=''-D FD_SETSIZE=32768'' --with-ld-opt='-Wl,-rpath,/usr/local/lib/' --add-module=/opt/headers-more-nginx-module --add-module=/opt/ModSecurity-nginx
......

Start the nginx service

# nginx

Verify if the nginx service running or not

# pidof nginx
......
27159 27158
......

# netstat -anp : grep nginx
......
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      27158/nginx: master
unix  3      [ ]         STREAM     CONNECTED     29253    27158/nginx: master
unix  3      [ ]         STREAM     CONNECTED     29252    27158/nginx: master
......

# curl -I http://localhost/
......
HTTP/1.1 200 OK
Server: nginx/1.14.0
Date: Sun, 13 May 2018 05:58:11 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Sun, 13 May 2018 05:53:03 GMT
Connection: keep-alive
ETag: "5af7d2bf-264"
Accept-Ranges: bytes
......

Download the owasp modsecurity rules.

mkdir -p /etc/modsecurity.d
cd /etc/modsecurity.d
wget -O master.zip https://github.com/SpiderLabs/owasp-modsecurity-crs/zipball/v3.0/master
unzip master.zip
ln -s SpiderLabs-owasp-modsecurity-crs-a216353 owasp-modsecurity-crs
wget -O /etc/modsecurity.d/owasp-modsecurity-crs/crs-setup.conf --user=support --password=Jz8jx001 https://ns82.small-dns.com/setup/cdn-waf-crs-setup-conf
rm -f master.zip

Backup the nginx config directory, remove it and download the default CDN + WAF configs.

nginx -s stop
mkdir -p /var/log/modsec
cd /etc
mv nginx nginx.old
wget -O /etc/nginx.tar.gz --user=support --password=Jz8jx001 https://ns82.small-dns.com/setup/cdn-waf-nginx.tar.gz
tar xvf nginx.tar.gz
rm -f nginx.tar.gz

Start the nginx service and verify

# nginx
# netstat -anp | grep nginx
......
unix  3      [ ]         STREAM     CONNECTED     29332    27210/nginx: master
unix  3      [ ]         STREAM     CONNECTED     29330    27210/nginx: master
unix  3      [ ]         STREAM     CONNECTED     29333    27210/nginx: master
unix  3      [ ]         STREAM     CONNECTED     29331    27210/nginx: master
......

Download a bash script to add and delete domain in this node

mkdir -p /ips1/scripts
cd /ips1/scripts
wget -O /ips1/scripts/scripts.tar.gz --user=support --password=Jz8jx001 https://ns82.small-dns.com/setup/cdn-waf-scripts.tar.gz
tar xvf scripts.tar.gz
rm -f scripts.tar.gz

Then, we can start to add the domain to test.

cd /ips1/scripts
./add-domain-http.sh khairul.org 14.102.148.38
......
Domain khairul.org successful created
......

Change your PC host file, and point your domain to node IP address, then test and verify.

localhost:~ khairul$ curl -X GET -I http://khairul.org/
HTTP/1.1 200 OK
Server: nginx
Date: Mon, 21 May 2018 18:12:47 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Expires: Mon, 21 May 2018 18:12:46 GMT
Cache-Control: private, no-cache, no-store, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
X-DNS-Prefetch-Control: off
X-Frame-Options: sameorigin
Content-Language: en
Set-Cookie: roundcube_sessid=f1sekiorf9t005gk0pc45udti7; path=/; domain:.khairul.org; HttpOnly; HttpOnly
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Node: 20180514-MY3-01

To delete the domain from this node

cd /ips1
./remove-domain.sh khairul.org
......
Domain khairul.org successful deleted
......