Modsecurity as a service 13/61313/2
authorJingLu5 <lvjing5@huawei.com>
Fri, 24 Aug 2018 02:55:14 +0000 (10:55 +0800)
committerJingLu5 <lvjing5@huawei.com>
Tue, 28 Aug 2018 08:29:03 +0000 (16:29 +0800)
JIRA: CLOVER-68

1. Add Dockerfile and related files to build clover's modsecurity Docekr container
2. Add mainfest to install the Modsecurity in kubernetes cluster

Change-Id: Ia92926e730c04720f931999d7ec30565ce9e54be
Signed-off-by: JingLu5 <lvjing5@huawei.com>
samples/services/modsecurity/docker/.htaccess [new file with mode: 0644]
samples/services/modsecurity/docker/Dockerfile [new file with mode: 0644]
samples/services/modsecurity/docker/apache2.conf [new file with mode: 0644]
samples/services/modsecurity/docker/build.sh [new file with mode: 0644]
samples/services/modsecurity/docker/docker-entrypoint.sh [new file with mode: 0644]
samples/services/modsecurity/docker/proxy.conf [new file with mode: 0644]
samples/services/modsecurity/yaml/manifest.template [new file with mode: 0644]
samples/services/modsecurity/yaml/modsecurity-deployment.yaml [new file with mode: 0644]
samples/services/modsecurity/yaml/modsecurity-service.yaml [new file with mode: 0644]
samples/services/modsecurity/yaml/render_yaml.py [new file with mode: 0644]

diff --git a/samples/services/modsecurity/docker/.htaccess b/samples/services/modsecurity/docker/.htaccess
new file mode 100644 (file)
index 0000000..a2b059c
--- /dev/null
@@ -0,0 +1,3 @@
+RewriteEngine on\r
+RewriteCond %{REQUEST_URI} !^/index.html$\r
+RewriteRule . /index.html [L]
\ No newline at end of file
diff --git a/samples/services/modsecurity/docker/Dockerfile b/samples/services/modsecurity/docker/Dockerfile
new file mode 100644 (file)
index 0000000..5a01f21
--- /dev/null
@@ -0,0 +1,37 @@
+FROM owasp/modsecurity:v2-ubuntu-apache\r
+MAINTAINER Jing Lu lvjing5@huawei.com\r
+\r
+ARG COMMIT=v3.1/dev\r
+ARG REPO=SpiderLabs/owasp-modsecurity-crs\r
+ENV PARANOIA=1\r
+\r
+RUN a2enmod rewrite\r
+\r
+RUN apt-get update && \\r
+    apt-get -y install python git ca-certificates iproute2 vim\r
+\r
+RUN cd /opt && \\r
+  git clone https://github.com/${REPO}.git owasp-modsecurity-crs-3.1 && \\r
+  cd owasp-modsecurity-crs-3.1 && \\r
+  git checkout -qf ${COMMIT}\r
+\r
+RUN cd /opt && \\r
+  cp -R /opt/owasp-modsecurity-crs-3.1/ /etc/apache2/modsecurity.d/owasp-crs/ && \\r
+  mv /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf.example /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf && \\r
+  cd /etc/apache2/modsecurity.d && \\r
+  printf "include modsecurity.d/owasp-crs/crs-setup.conf\ninclude modsecurity.d/owasp-crs/rules/*.conf" > include.conf && \\r
+  sed -i -e 's/SecRuleEngine DetectionOnly/SecRuleEngine On/g' /etc/apache2/modsecurity.d/modsecurity.conf && \\r
+  a2enmod proxy proxy_http\r
+\r
+COPY proxy.conf           /etc/apache2/modsecurity.d/proxy.conf\r
+COPY docker-entrypoint.sh /\r
+\r
+RUN chmod 777 /docker-entrypoint.sh\r
+\r
+COPY .htaccess            /var/www/html/.htaccess\r
+COPY apache2.conf         /etc/apache2/apache2.conf\r
+\r
+EXPOSE 80\r
+\r
+ENTRYPOINT ["/docker-entrypoint.sh"]\r
+CMD ["apachectl", "-D", "FOREGROUND"]\r
diff --git a/samples/services/modsecurity/docker/apache2.conf b/samples/services/modsecurity/docker/apache2.conf
new file mode 100644 (file)
index 0000000..f7c62d6
--- /dev/null
@@ -0,0 +1,227 @@
+# This is the main Apache server configuration file.  It contains the
+# configuration directives that give the server its instructions.
+# See http://httpd.apache.org/docs/2.4/ for detailed information about
+# the directives and /usr/share/doc/apache2/README.Debian about Debian specific
+# hints.
+#
+#
+# Summary of how the Apache 2 configuration works in Debian:
+# The Apache 2 web server configuration in Debian is quite different to
+# upstream's suggested way to configure the web server. This is because Debian's
+# default Apache2 installation attempts to make adding and removing modules,
+# virtual hosts, and extra configuration directives as flexible as possible, in
+# order to make automating the changes and administering the server as easy as
+# possible.
+
+# It is split into several files forming the configuration hierarchy outlined
+# below, all located in the /etc/apache2/ directory:
+#
+#      /etc/apache2/
+#      |-- apache2.conf
+#      |       `--  ports.conf
+#      |-- mods-enabled
+#      |       |-- *.load
+#      |       `-- *.conf
+#      |-- conf-enabled
+#      |       `-- *.conf
+#      `-- sites-enabled
+#              `-- *.conf
+#
+#
+# * apache2.conf is the main configuration file (this file). It puts the pieces
+#   together by including all remaining configuration files when starting up the
+#   web server.
+#
+# * ports.conf is always included from the main configuration file. It is
+#   supposed to determine listening ports for incoming connections which can be
+#   customized anytime.
+#
+# * Configuration files in the mods-enabled/, conf-enabled/ and sites-enabled/
+#   directories contain particular configuration snippets which manage modules,
+#   global configuration fragments, or virtual host configurations,
+#   respectively.
+#
+#   They are activated by symlinking available configuration files from their
+#   respective *-available/ counterparts. These should be managed by using our
+#   helpers a2enmod/a2dismod, a2ensite/a2dissite and a2enconf/a2disconf. See
+#   their respective man pages for detailed information.
+#
+# * The binary is called apache2. Due to the use of environment variables, in
+#   the default configuration, apache2 needs to be started/stopped with
+#   /etc/init.d/apache2 or apache2ctl. Calling /usr/bin/apache2 directly will not
+#   work with the default configuration.
+
+
+# Global configuration
+#
+
+#
+# ServerRoot: The top of the directory tree under which the server's
+# configuration, error, and log files are kept.
+#
+# NOTE!  If you intend to place this on an NFS (or otherwise network)
+# mounted filesystem then please read the Mutex documentation (available
+# at <URL:http://httpd.apache.org/docs/2.4/mod/core.html#mutex>);
+# you will save yourself a lot of trouble.
+#
+# Do NOT add a slash at the end of the directory path.
+#
+#ServerRoot "/etc/apache2"
+
+#
+# The accept serialization lock file MUST BE STORED ON A LOCAL DISK.
+#
+#Mutex file:${APACHE_LOCK_DIR} default
+
+#
+# The directory where shm and other runtime files will be stored.
+#
+
+DefaultRuntimeDir ${APACHE_RUN_DIR}
+
+#
+# PidFile: The file in which the server should record its process
+# identification number when it starts.
+# This needs to be set in /etc/apache2/envvars
+#
+PidFile ${APACHE_PID_FILE}
+
+#
+# Timeout: The number of seconds before receives and sends time out.
+#
+Timeout 300
+
+#
+# KeepAlive: Whether or not to allow persistent connections (more than
+# one request per connection). Set to "Off" to deactivate.
+#
+KeepAlive On
+
+#
+# MaxKeepAliveRequests: The maximum number of requests to allow
+# during a persistent connection. Set to 0 to allow an unlimited amount.
+# We recommend you leave this number high, for maximum performance.
+#
+MaxKeepAliveRequests 100
+
+#
+# KeepAliveTimeout: Number of seconds to wait for the next request from the
+# same client on the same connection.
+#
+KeepAliveTimeout 5
+
+
+# These need to be set in /etc/apache2/envvars
+User ${APACHE_RUN_USER}
+Group ${APACHE_RUN_GROUP}
+
+#
+# HostnameLookups: Log the names of clients or just their IP addresses
+# e.g., www.apache.org (on) or 204.62.129.132 (off).
+# The default is off because it'd be overall better for the net if people
+# had to knowingly turn this feature on, since enabling it means that
+# each client request will result in AT LEAST one lookup request to the
+# nameserver.
+#
+HostnameLookups Off
+
+# ErrorLog: The location of the error log file.
+# If you do not specify an ErrorLog directive within a <VirtualHost>
+# container, error messages relating to that virtual host will be
+# logged here.  If you *do* define an error logfile for a <VirtualHost>
+# container, that host's errors will be logged there and not here.
+#
+ErrorLog ${APACHE_LOG_DIR}/error.log
+
+#
+# LogLevel: Control the severity of messages logged to the error_log.
+# Available values: trace8, ..., trace1, debug, info, notice, warn,
+# error, crit, alert, emerg.
+# It is also possible to configure the log level for particular modules, e.g.
+# "LogLevel info ssl:warn"
+#
+LogLevel warn
+
+# Include module configuration:
+IncludeOptional mods-enabled/*.load
+IncludeOptional mods-enabled/*.conf
+
+# Include list of ports to listen on
+Include ports.conf
+
+
+# Sets the default security model of the Apache2 HTTPD server. It does
+# not allow access to the root filesystem outside of /usr/share and /var/www.
+# The former is used by web applications packaged in Debian,
+# the latter may be used for local directories served by the web server. If
+# your system is serving content from a sub-directory in /srv you must allow
+# access here, or in any related virtual host.
+<Directory />
+       Options FollowSymLinks
+       AllowOverride None
+       Require all denied
+</Directory>
+
+<Directory /usr/share>
+       AllowOverride None
+       Require all granted
+</Directory>
+
+<Directory /var/www/>
+       Options Indexes FollowSymLinks
+       AllowOverride All
+       Require all granted
+</Directory>
+
+#<Directory /srv/>
+#      Options Indexes FollowSymLinks
+#      AllowOverride None
+#      Require all granted
+#</Directory>
+
+
+
+
+# AccessFileName: The name of the file to look for in each directory
+# for additional configuration directives.  See also the AllowOverride
+# directive.
+#
+AccessFileName .htaccess
+
+#
+# The following lines prevent .htaccess and .htpasswd files from being
+# viewed by Web clients.
+#
+<FilesMatch "^\.ht">
+       Require all denied
+</FilesMatch>
+
+
+#
+# The following directives define some format nicknames for use with
+# a CustomLog directive.
+#
+# These deviate from the Common Log Format definitions in that they use %O
+# (the actual bytes sent including headers) instead of %b (the size of the
+# requested file), because the latter makes it impossible to detect partial
+# requests.
+#
+# Note that the use of %{X-Forwarded-For}i instead of %h is not recommended.
+# Use mod_remoteip instead.
+#
+LogFormat "%v:%p %h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
+LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%h %l %u %t \"%r\" %>s %O" common
+LogFormat "%{Referer}i -> %U" referer
+LogFormat "%{User-agent}i" agent
+
+# Include of directories ignores editors' and dpkg's backup files,
+# see README.Debian for details.
+
+# Include generic snippets of statements
+IncludeOptional conf-enabled/*.conf
+
+# Include the virtual host configurations:
+IncludeOptional sites-enabled/*.conf
+
+# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
diff --git a/samples/services/modsecurity/docker/build.sh b/samples/services/modsecurity/docker/build.sh
new file mode 100644 (file)
index 0000000..ea0feed
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+IMAGE_PATH=${IMAGE_PATH:-"localhost:5000"}
+IMAGE_NAME=${IMAGE_NAME:-"clover-ns-modsecurity-crs"}
+
+docker build -t $IMAGE_NAME .
+docker tag $IMAGE_NAME $IMAGE_PATH/$IMAGE_NAME
+docker push $IMAGE_PATH/$IMAGE_NAME
diff --git a/samples/services/modsecurity/docker/docker-entrypoint.sh b/samples/services/modsecurity/docker/docker-entrypoint.sh
new file mode 100644 (file)
index 0000000..e8e3013
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+python -c "import re;import os;out=re.sub('(#SecAction[\S\s]*id:900000[\s\S]*paranoia_level=1\")','SecAction \\\\\n  \"id:900000, \\\\\n   phase:1, \\\\\n   nolog, \\\\\n   pass, \\\\\n   t:none, \\\\\n   setvar:tx.paranoia_level='+os.environ['PARANOIA']+'\"',open('/etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf','r').read());open('/etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf','w').write(out)" && \
+python -c "import re;import os;out=re.sub('(#SecAction[\S\s]*id:900330[\s\S]*total_arg_length=64000\")','SecAction \\\\\n \"id:900330, \\\\\n phase:1, \\\\\n nolog, \\\\\n pass, \\\\\n t:none, \\\\\n setvar:tx.total_arg_length=64000\"',open('/etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf','r').read());open('/etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf','w').write(out)" && \
+
+if [ ! -z $PROXY ]; then
+  if [ $PROXY -eq 1 ]; then
+    APACHE_ARGUMENTS='-D crs_proxy'
+    if [ -z "$UPSTREAM" ]; then
+      export UPSTREAM=$(/sbin/ip route | grep ^default | perl -pe 's/^.*?via ([\d.]+).*/$1/g'):81
+    fi
+  fi
+fi
+
+
+exec "$@" $APACHE_ARGUMENTS
diff --git a/samples/services/modsecurity/docker/proxy.conf b/samples/services/modsecurity/docker/proxy.conf
new file mode 100644 (file)
index 0000000..4dee0c9
--- /dev/null
@@ -0,0 +1,3 @@
+<IfDefine crs_proxy>
+  ProxyPass "/" "http://${UPSTREAM}/"
+</IfDefine>
diff --git a/samples/services/modsecurity/yaml/manifest.template b/samples/services/modsecurity/yaml/manifest.template
new file mode 100644 (file)
index 0000000..afeb9dc
--- /dev/null
@@ -0,0 +1,38 @@
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+  name: {{ deploy_name }}
+  labels:
+    app: {{ deploy_name }}
+spec:
+  replicas: 1
+  template:
+    metadata:
+      labels:
+        app: {{ deploy_name }}
+    spec:
+      containers:
+        - name: {{ deploy_name }}
+          image: {{ image_path }}/{{ image_name }}:{{ image_tag }}
+          ports:
+           - containerPort: {{ http_port }}
+          env:
+            - name: PARANOIA
+              value: {{ paranoia_level }}
+
+---
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ deploy_name }}
+  labels:
+    app: {{ deploy_name }}
+spec:
+  ports:
+  - port: {{ http_port }}
+    name: http-modsecurity-crs
+    targetPort: {{ http_port }}
+  selector:
+    app: {{ deploy_name }}
+---
diff --git a/samples/services/modsecurity/yaml/modsecurity-deployment.yaml b/samples/services/modsecurity/yaml/modsecurity-deployment.yaml
new file mode 100644 (file)
index 0000000..450ede5
--- /dev/null
@@ -0,0 +1,22 @@
+apiVersion: extensions/v1beta1\r
+kind: Deployment\r
+metadata:\r
+  name: modsecurity-crs\r
+spec:\r
+  replicas: 1\r
+  selector:\r
+    matchLabels:\r
+      app: modsecurity-crs\r
+  template:\r
+    metadata:\r
+      labels:\r
+        app: modsecurity-crs\r
+    spec:\r
+      containers:\r
+        - name: modsecurity-crs\r
+          image: clover/clover-ns-modsecurity-crs\r
+          ports:\r
+            - containerPort: 80\r
+          env:\r
+            - name: PARANOIA\r
+              value: '1'\r
diff --git a/samples/services/modsecurity/yaml/modsecurity-service.yaml b/samples/services/modsecurity/yaml/modsecurity-service.yaml
new file mode 100644 (file)
index 0000000..8548dca
--- /dev/null
@@ -0,0 +1,13 @@
+apiVersion: v1\r
+kind: Service\r
+metadata:\r
+  name: modsecurity-crs\r
+spec:\r
+  type: NodePort\r
+  ports:\r
+  - port: 80\r
+    name: http-modsecurity-crs\r
+    protocol: TCP\r
+    targetPort: 80\r
+  selector:\r
+    app: modsecurity-crs\r
diff --git a/samples/services/modsecurity/yaml/render_yaml.py b/samples/services/modsecurity/yaml/render_yaml.py
new file mode 100644 (file)
index 0000000..54f8069
--- /dev/null
@@ -0,0 +1,60 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+import argparse
+
+from jinja2 import Template
+
+
+def render_yaml(args):
+    template_file = 'manifest.template'
+    out_file = 'modsecurity.yaml'
+
+    try:
+        with open(template_file) as f:
+            tmpl = Template(f.read())
+        output = tmpl.render(
+            image_path=args['image_path'],
+            image_name=args['image_name'],
+            image_tag=args['image_tag'],
+            deploy_name=args['deploy_name'],
+            http_port=args['http_port'],
+            paranoia_level=args['paranoia_level']
+        )
+        with open(out_file, "wb") as fh:
+            fh.write(output)
+        return "Generated manifest for {}".format(args['deploy_name'])
+    except Exception as e:
+        print(e)
+        return "Unable to generate manifest for {}".format(
+                                        args['deploy_name'])
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+            '--image_name', default='clover-ns-modsecurity-crs',
+            help='The image name to use')
+    parser.add_argument(
+            '--image_path', default='localhost:5000',
+            help='The path to the image to use')
+    parser.add_argument(
+            '--image_tag', default='latest',
+            help='The image tag to use')
+    parser.add_argument(
+            '--deploy_name', default='modsecurity-crs',
+            help='The k8s deploy name to use')
+    parser.add_argument(
+            '--http_port', default='80',
+            help='Analyze http traffic on this port')
+    parser.add_argument(
+            '--paranoia_level', default='1',
+            help='The modsecurity paranoia level')
+
+    args = parser.parse_args()
+    print(render_yaml(vars(args)))
+