Skip to content

Instantly share code, notes, and snippets.

@icicimov
Created December 16, 2019 23:32
Show Gist options
  • Save icicimov/69456f82e60ea6c53feb341f021fd089 to your computer and use it in GitHub Desktop.
Save icicimov/69456f82e60ea6c53feb341f021fd089 to your computer and use it in GitHub Desktop.
ModSecurity setup for Haproxy
#!/bin/bash
set -e
set -o pipefail
#HAPROXY_MAJOR="1.8"
#HAPROXY_VERSION="1.8.23"
#HAPROXY_MD5="6c35b83a9969449c4b79783a2119551e"
#HAPROXY_MAJOR="1.9"
#HAPROXY_VERSION="1.9.13"
#HAPROXY_MD5="c2364536409044e7cfa646c7e6d2711f"
HAPROXY_MAJOR="2.0"
HAPROXY_VERSION="2.0.10"
HAPROXY_MD5="501f490f0fb6c01099686d2f0e02f644"
MODSEC_VERSION="2.9.2"
MODSEC_MD5="4d9454efb19269c4288ae408ea438b76"
MODSEC_URL="https://www.modsecurity.org/tarball/${MODSEC_VERSION}/modsecurity-${MODSEC_VERSION}.tar.gz"
OWASP_MODSEC_VERSION="v3.0.2"
OWASP_MODSEC_MD5="9cef8c63937a92dc350275fcf348baab"
# Vars in case of modsecurity service setup
MODSEC_USER="modsecurity"
MODSEC_PORT="12345"
MODSEC_WORKERS="10"
MODSEC_CAPS="" # eg. "-c pipelining -c async"
MODSEC_DEBUG="" # eg. "-d" for debug mode
APR_VERSION="1.7.0"
APR_UTIL_VERSION="1.6.1"
APR_URL="http://apache.mirror.digitalpacific.com.au//apr"
APR_COMPILE="n"
# Must run as root
if [ "$(id -u)" != "0" ]; then
echo "This script must be run as root" 1>&2
exit 1
fi
# Cleanup
function sources_cleanup {
rm -rf /usr/src/haproxy /usr/src/modsecurity /usr/src/apr /usr/src/apr-util
}
# Dependencies
function install_dep {
DEBIAN_FRONTEND=noninteractive
apt install -y --no-install-recommends libexpat1-dev libyajl-dev \
apache2-dev libapr1 libapr1-dev libaprutil1 libaprutil1-dev libldap2-dev \
libsctp-dev libsctp1 uuid-dev libxml2-dev
}
# APR and APR-UTIL
function install_apr {
curl -fsSL ${APR_URL}/apr-${APR_VERSION}.tar.gz -o /tmp/apr.tar.gz
curl -fsSL ${APR_URL}/apr-util-${APR_UTIL_VERSION}.tar.gz -o /tmp/apr-util.tar.gz
mkdir -p /usr/src/apr
mkdir -p /usr/src/apr-util
tar -xzf /tmp/apr.tar.gz --strip-components=1 -C /usr/src/apr
rm /tmp/apr.tar.gz
cd /usr/src/apr
./configure --prefix=/usr/local/apr
make && make install
sudo tar -xzf /tmp/apr-util.tar.gz --strip-components=1 -C /usr/src/apr-util
rm /tmp/apr-util.tar.gz
cd /usr/src/apr-util
./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr \
--with-openssl=/opt/openssl/include/openssl --with-crypto
make && make install
rm -rf /usr/src/apr /usr/src/apr-util
}
# mod-security standalone
function install_modsecurity {
curl -fsSL ${MODSEC_URL} -o /tmp/modsecurity.tar.gz
echo "${MODSEC_MD5} /tmp/modsecurity.tar.gz" | md5sum -c
mkdir -p /usr/src/modsecurity
tar -xzf /tmp/modsecurity.tar.gz --strip-components=1 -C /usr/src/modsecurity
rm /tmp/modsecurity.tar.gz
cd /usr/src/modsecurity
if [[ "$APR_COMPILE" == [nN0]* ]]; then
./configure --prefix=$PWD/INSTALL \
--disable-apache2-module \
--enable-standalone-module \
--enable-pcre-study \
--without-lua \
--enable-pcre-jit \
--with-apxs=/usr/bin/apxs
elif [[ "$APR_COMPILE" == [yY1]* ]]; then
cp /usr/local/apr/include/apr-1/ap*.h apache2/
cp /usr/local/apr-util/include/apr-1/ap*.h apache2/
./configure --prefix=$PWD/INSTALL \
--disable-apache2-module \
--enable-standalone-module \
--enable-pcre-study \
--without-lua \
--enable-pcre-jit \
--with-apxs=/usr/bin/apxs \
--with-apr=/usr/local/apr
fi
make -C standalone install
mkdir -p $PWD/INSTALL/include
cp standalone/*.h apache2/*.h $PWD/INSTALL/include
curl -fsSL https://www.haproxy.org/download/${HAPROXY_MAJOR}/src/haproxy-${HAPROXY_VERSION}.tar.gz -o /tmp/haproxy.tar.gz
echo "$HAPROXY_MD5 /tmp/haproxy.tar.gz" | md5sum -c
mkdir -p /usr/src/haproxy
tar -xzf /tmp/haproxy.tar.gz -C /usr/src/haproxy --strip-components=1
rm /tmp/haproxy.tar.gz
if [[ "$APR_COMPILE" == [nN0]* ]]; then
make -C /usr/src/haproxy/contrib/modsecurity \
MODSEC_INC=/usr/src/modsecurity/INSTALL/include \
MODSEC_LIB=/usr/src/modsecurity/INSTALL/lib \
APACHE2_INC=/usr/include/apache2
elif [[ "$APR_COMPILE" == [yY1]* ]]; then
# statically link to apr-1 we built
sed -i 's#-lapr-1#/usr/local/apr/lib/libapr-1.a#' /usr/src/haproxy/contrib/modsecurity/Makefile
make LDFLAGS="-Wl,--copy-dt-needed-entries" \
-C /usr/src/haproxy/contrib/modsecurity \
MODSEC_INC=/usr/src/modsecurity/INSTALL/include \
MODSEC_LIB=/usr/src/modsecurity/INSTALL/lib \
APACHE2_INC=/usr/include/apache2 \
APR_INC=/usr/local/apr/include
fi
#mv /usr/src/haproxy/contrib/modsecurity/modsecurity /usr/local/bin/
make -C /usr/src/haproxy/contrib/modsecurity install
rm -rf /usr/src/haproxy /usr/src/modsecurity
}
# OWASP
function owasp_modsecurity {
mkdir -p /etc/modsecurity/owasp-modsecurity-crs
wget -qO/etc/modsecurity/modsecurity.conf https://github.com/SpiderLabs/ModSecurity/raw/v2/master/modsecurity.conf-recommended
wget -qO/etc/modsecurity/unicode.mapping https://github.com/SpiderLabs/ModSecurity/raw/v2/master/unicode.mapping
wget -qO/tmp/owasp.tar.gz https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/${OWASP_MODSEC_VERSION}.tar.gz
echo "$OWASP_MODSEC_MD5 /tmp/owasp.tar.gz" | md5sum -c
tar xzf /tmp/owasp.tar.gz --strip-components=1 -C /etc/modsecurity/owasp-modsecurity-crs
rm /tmp/owasp.tar.gz
find /etc/modsecurity/owasp-modsecurity-crs -name '*.example' -type f \
| while read -r f; do cp -p "$f" "${f%.example}"; done
sed -i.example 's/^SecRuleEngine .*/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf
sed -i.example 's/^\(SecDefaultAction "phase:[12]\),log,auditlog,pass"/\1,log,noauditlog,deny,status:403"/' \
/etc/modsecurity/owasp-modsecurity-crs/crs-setup.conf
find /etc/modsecurity/owasp-modsecurity-crs -maxdepth 1 -name '*.conf' -type f \
| sort | sed 's/^/Include /' > /etc/modsecurity/owasp-modsecurity-crs.conf
find /etc/modsecurity/owasp-modsecurity-crs/rules -maxdepth 1 -name '*.conf' -type f \
| sort | sed 's/^/Include /' >> /etc/modsecurity/owasp-modsecurity-crs.conf
}
# ModSecurity service setup
function setup_modsecurity {
id -u $MODSEC_USER 2>&1>/dev/null || useradd -c "ModSecurity User" -r -M -s /bin/false $MODSEC_USER
cat > /etc/default/modsecurity <<-EOF
# User and Group
USER="$MODSEC_USER"
GROUP="$MODSEC_USER"
# Listen port
PORT="$MODSEC_PORT"
# Number of workers
NUM_WORKERS="$MODSEC_WORKERS"
# Uncomment for debug mode
DEBUG="$MODSEC_DEBUG"
# Config files to load
EXTRAOPTS="-f /etc/modsecurity/modsecurity.conf -f /etc/modsecurity/owasp-modsecurity-crs.conf"
# Example for adding capabilities, one or more of fragmentation,pipelining,async
# EXTRACAPS="-c fragmentation -c pipelining -c async"
EXTRACAPS="$MODSEC_CAPS"
EOF
sys_init=$(cat /proc/1/comm)
# Systemd service
[[ $sys_init == "systemd" ]] && {
cat > /etc/systemd/system/modsecurity.service <<-'END'
[Unit]
Description=Haproxy modsecurity-spoa agent
After=network.target
[Service]
User=${USER}
Group=${GROUP}
PermissionsStartOnly=true
UMask=0007
KillMode=process
Restart=on-failure
RestartSec=10
NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
EnvironmentFile=/etc/default/modsecurity
ExecStart=/usr/local/bin/modsecurity ${DEBUG} -n ${NUM_WORKERS} -p ${PORT} $EXTRACAPS $EXTRAOPTS
[Install]
WantedBy=multi-user.target
END
} && systemctl daemon-reload \
&& systemctl start modsecurity.service \
&& systemctl enable modsecurity.service
# Upstart service
[[ $sys_init == "init" ]] && {
cat > /etc/init/modsecurity.conf <<-'END'
# Ubuntu upstart file at /etc/init/modsecurity.conf
description "Haproxy modsecurity-spoa agent"
kill timeout 60 # wait 60s between SIGTERM and SIGKILL.
respawn
console output
pre-start script
if [ -f /etc/default/modsecurity ]; then . /etc/default/modsecurity; fi
DAEMONUSER=${USER:-modsecurity}
DAEMONGROUP=${GROUP:-modsecurity}
LOGDIR=${LOGDIR:-/var/log/modsecurity}
if [ ! -d ${LOGDIR} ]; then
mkdir -p ${LOGDIR} && chown ${DAEMONUSER}:${DAEMONGROUP} ${LOGDIR}
fi
touch /var/run/modsecurity.pid
chown $DAEMONUSER /var/run/modsecurity.pid
end script
start on runlevel [2345]
stop on runlevel [06]
script
ENABLE_DAEMON="yes"
DAEMON=/usr/local/bin/modsecurity
DAEMONUSER=${USER:-modsecurity}
DAEMONGROUP=${GROUP:-modsecurity}
LOGDIR=${LOGDIR:-/var/log/modsecurity}
if [ -f /etc/default/modsecurity ]; then . /etc/default/modsecurity; fi
DAEMON_OPTS="-- "${DAEMON_OPTS:-"$DEBUG -n $NUM_WORKERS -p $PORT $EXTRACAPS $EXTRAOPTS"}
if [ "x$ENABLE_DAEMON" = "xyes" ]
then
exec start-stop-daemon --start \
--chuid $DAEMONUSER:$DAEMONGROUP \
--pidfile /var/run/modsecurity.pid \
--make-pidfile \
--exec $DAEMON $DAEMON_OPTS >> ${LOGDIR}/modsecurity.log 2>&1
fi
end script
END
} && initctl reload-configuration && initctl start modsecurity
}
sources_cleanup
install_dep
[[ "$APR_COMPILE" == [yY1]* ]] && install_apr
install_modsecurity
owasp_modsecurity
setup_modsecurity
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment