From ac16622a4c39ce55460606898b29c8eafd782437 Mon Sep 17 00:00:00 2001 From: Jit <86168235+Xhoenix@users.noreply.github.com> Date: Sun, 21 Jan 2024 15:09:14 +0530 Subject: [PATCH 1/6] docs: update docker buildx documentation link (#187) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 33d0ce7f..a0051c42 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ docker buildx create --use --platform linux/amd64,linux/i386,linux/arm64,linux/a docker buildx bake -f docker-bake.hcl ``` -We require a version of `buildx` >= v0.9.1. [Visit the official documentation](https://docs.docker.com/build/buildx/install/) for instructions on installing and upgrading `buildx`. You can check which version you have using: +We require a version of `buildx` >= v0.9.1. [Visit the official documentation](https://docs.docker.com/build/architecture/#install-buildx) for instructions on installing and upgrading `buildx`. You can check which version you have using: ```bash docker buildx version From de08b3b81d9048a2f9bb93c23b5a831a962ced61 Mon Sep 17 00:00:00 2001 From: Max Leske Date: Wed, 24 Jan 2024 14:51:07 +0100 Subject: [PATCH 2/6] feat: drop support for overriding USER Overrideing the USER only makes sense if it can be configured at build time, as that user needs to exist on the system. For containers, this functionality doesn't make much sense anyway. Fixes #184 --- README-containers.md | 2 -- README.md | 4 ---- apache/Dockerfile | 2 -- apache/Dockerfile-alpine | 3 --- apache/conf/extra/httpd-modsecurity.conf | 5 ----- nginx/Dockerfile | 2 -- nginx/Dockerfile-alpine | 2 -- 7 files changed, 20 deletions(-) diff --git a/README-containers.md b/README-containers.md index 9e1ee282..3cbaa853 100644 --- a/README-containers.md +++ b/README-containers.md @@ -174,8 +174,6 @@ All these variables impact in configuration directives in the modsecurity engine | Name | Description| | -- | -- | -| USER | Name (or #number) of the user to run httpd or nginx as (Default: `www-data` (httpd), `nginx` (nginx)) | -| GROUP | Name (or #number) of the group to run httpd as (Default: `www-data`) | | BACKEND | Backend address (and optional port) of the backend server. (Default: the container's default router, port 81) (Examples: 192.0.2.2, 192.0.2.2:80, ) | ### CRS specific diff --git a/README.md b/README.md index a0051c42..f810310a 100644 --- a/README.md +++ b/README.md @@ -259,8 +259,6 @@ All these variables impact in configuration directives in the modsecurity engine | Name | Description| | -------- | ------------------------------------------------------------------- | -| USER | A string value indicating the name (or #number) of the user to run httpd or nginx as (Default: `www-data` (httpd), `nginx` (nginx)) | -| GROUP | A string value indicating the name (or #number) of the group to run httpd as (Default: `www-data`) | | BACKEND | The backend address (and optional port) of the backend server. (Default: the container's default router, port 81) (Examples: 192.0.2.2, 192.0.2.2:80, ) | ### CRS specific @@ -359,8 +357,6 @@ docker run -dti -p 80:80 --rm \ -e TIMEOUT=60 \ -e LOGLEVEL=warn \ -e ERRORLOG='/proc/self/fd/2' \ - -e USER=daemon \ - -e GROUP=daemon \ -e SERVER_ADMIN=root@localhost \ -e SERVER_NAME=localhost \ -e PORT=80 \ diff --git a/apache/Dockerfile b/apache/Dockerfile index 29c9ae78..a6658370 100644 --- a/apache/Dockerfile +++ b/apache/Dockerfile @@ -134,8 +134,6 @@ ENV APACHE_ALWAYS_TLS_REDIRECT=off \ SSL_USE_STAPLING=On \ TIMEOUT=60 \ WORKER_CONNECTIONS=400 \ - USER=www-data \ - GROUP=www-data \ # CRS specific variables PARANOIA=1 \ ANOMALY_INBOUND=5 \ diff --git a/apache/Dockerfile-alpine b/apache/Dockerfile-alpine index a0397d49..05657fad 100644 --- a/apache/Dockerfile-alpine +++ b/apache/Dockerfile-alpine @@ -144,9 +144,6 @@ ENV APACHE_ALWAYS_TLS_REDIRECT=off \ SSL_USE_STAPLING=On \ TIMEOUT=60 \ WORKER_CONNECTIONS=400 \ - # overridden variables - USER=www-data \ - GROUP=www-data \ # CRS specific variables PARANOIA=1 \ ANOMALY_INBOUND=5 \ diff --git a/apache/conf/extra/httpd-modsecurity.conf b/apache/conf/extra/httpd-modsecurity.conf index d59e8887..5c268138 100644 --- a/apache/conf/extra/httpd-modsecurity.conf +++ b/apache/conf/extra/httpd-modsecurity.conf @@ -7,11 +7,6 @@ ErrorLog ${ERRORLOG} # https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#secserversignature SecServerSignature ${MODSEC_SERVER_SIGNATURE} - - User ${USER} - Group ${GROUP} - - RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500 diff --git a/nginx/Dockerfile b/nginx/Dockerfile index e1c2dbf0..8b21e6c7 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -160,8 +160,6 @@ ENV ACCESSLOG=/var/log/nginx/access.log \ WORKER_CONNECTIONS=1024 \ LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib \ NGINX_ENVSUBST_OUTPUT_DIR=/etc/nginx \ - # overridden variables - USER=nginx \ # CRS specific variables PARANOIA=1 \ ANOMALY_INBOUND=5 \ diff --git a/nginx/Dockerfile-alpine b/nginx/Dockerfile-alpine index 8a1d5b31..eef38cbf 100644 --- a/nginx/Dockerfile-alpine +++ b/nginx/Dockerfile-alpine @@ -155,8 +155,6 @@ ENV ACCESSLOG=/var/log/nginx/access.log \ WORKER_CONNECTIONS=1024 \ LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib \ NGINX_ENVSUBST_OUTPUT_DIR=/etc/nginx \ - # overridden variables - USER=nginx \ # CRS specific variables PARANOIA=1 \ ANOMALY_INBOUND=5 \ From a4396f4d1fd3a10fa3943d8a044827885901b301 Mon Sep 17 00:00:00 2001 From: Taavi Ansper <46354923+TafkaMax@users.noreply.github.com> Date: Sat, 27 Jan 2024 16:47:31 +0200 Subject: [PATCH 3/6] feat: add Openresty as webserver option (#118) --- README.md | 19 +- docker-bake.hcl | 12 +- openresty/Dockerfile-alpine | 250 ++++++++++++++++++ .../20-envsubst-on-templates.sh | 39 +++ .../25-listen-on-ipv6-by-default.sh | 67 +++++ .../30-tune-worker-processes.sh | 188 +++++++++++++ .../90-copy-modsecurity-config.sh | 14 + .../docker-entrypoint.d/91-update-resolver.sh | 12 + .../docker-entrypoint.d/92-update-real_ip.sh | 13 + openresty/docker-entrypoint.sh | 47 ++++ openresty/openssl.conf | 15 ++ openresty/templates/nginx.conf.template | 32 +++ 12 files changed, 705 insertions(+), 3 deletions(-) create mode 100644 openresty/Dockerfile-alpine create mode 100755 openresty/docker-entrypoint.d/20-envsubst-on-templates.sh create mode 100755 openresty/docker-entrypoint.d/25-listen-on-ipv6-by-default.sh create mode 100755 openresty/docker-entrypoint.d/30-tune-worker-processes.sh create mode 100755 openresty/docker-entrypoint.d/90-copy-modsecurity-config.sh create mode 100755 openresty/docker-entrypoint.d/91-update-resolver.sh create mode 100755 openresty/docker-entrypoint.d/92-update-real_ip.sh create mode 100755 openresty/docker-entrypoint.sh create mode 100644 openresty/openssl.conf create mode 100644 openresty/templates/nginx.conf.template diff --git a/README.md b/README.md index f810310a..4cf701f1 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,15 @@ We also build [alpine linux](https://www.alpinelinux.org/) variants of the base * `3-nginx-alpine-YYYYMMDDHHMM`, `3.3-nginx-alpine-YYYYMMDDHHMM`, `3.3.5-nginx-alpine-YYYYMMDDHHMM`, `nginx-alpine` ([master/nginx/Dockerfile-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile-alpine) – *last stable ModSecurity v3 on Nginx 1.25.3 official alpine stable base image, and latest stable Core Rule Set 3.3.5* * `3-apache-alpine-YYYYMMDDHHMM`, `3.3-apache-alpine-YYYYMMDDHHMM`, `3.3.5-apache-alpine-YYYYMMDDHHMM`, `apache-alpine` ([master/apache/Dockerfile-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile-alpine)) – *last stable ModSecurity v2 on Apache 2.4.58 official alpine stable base image, and latest stable Core Rule Set 3.3.5* -⚠️ We changed tags to [support production usage](https://github.com/coreruleset/modsecurity-crs-docker/issues/67). Now, if you want to use the "rolling version", use the tag `owasp/modsecurity-crs:nginx-alpine` or `owasp/modsecurity-crs:apache-alpine`. If you need a stable long term image, use the one with the full CRS version, in addition to the build date in `YYYYMMDDHHMM` format, example `owasp/modsecurity-crs:3.3.5-nginx-alpine-202209141209` or `owasp/modsecurity-crs:3.3.5-apache-alpine-202209141209` for example. You have been warned. +⚠️ We changed tags to [support production usage](https://github.com/coreruleset/modsecurity-crs-docker/issues/67). Now, if you want to use the "rolling version", use the tag `owasp/modsecurity-crs:nginx-alpine` or `owasp/modsecurity-crs:apache-alpine` or `owasp/modsecurity-crs:openresty-alpine-fat`. If you need a stable long term image, use the one with the full CRS version, in addition to the build date in `YYYYMMDDHHMM` format (e.g., `owasp/modsecurity-crs:3.3.5-nginx-alpine-202209141209`). + +### Notes regarding Openresty version of this image. + +We currently only provide a version of the Openresty image based on **Alpine Linux**. The Dockerfile for Openresty resides in the [docker-openresty repository](https://github.com/openresty/docker-openresty/blob/master/alpine/Dockerfile.fat). ## Supported architectures -We added the [docker buildx](https://github.com/docker/buildx) support to our docker builds so additional architectures are supported now. As we create our containers based on the official apache and nginx ones, we can only support the architectures they support. +We added the [docker buildx](https://github.com/docker/buildx) support to our docker builds so additional architectures are supported now. As we create our containers based on the official Apache httpd, nginx and Openresty ones, we can only support the architectures they support. There is a new file `docker-bake.hcl` used for this purpose. To build for new platforms, just use this example: @@ -70,6 +74,13 @@ To build a specific target for a single platform only (replace target and platfo docker buildx bake -f docker-bake.hcl --set "*.platform=linux/amd64" nginx-alpine ``` +### Notes regarding Openresty version of the image. + +Openresty image builds currently support only these architectures: + +* linux/amd64 +* linux/arm64 + ## CRS Versions > Hey, I used some specific git version with the containers? What happened? @@ -218,6 +229,10 @@ Note: Apache access and metric logs can be disabled by exporting the `nologging= | TIMEOUT | Number of seconds for a keep-alive client connection to stay open on the server side (Default: `60s`) | | WORKER_CONNECTIONS | Maximum number of simultaneous connections that can be opened by a worker process (Default: `1024`) | +### Openresty ENV Variables + +Openresty uses the same environment variables as the nginx version. + ### ModSecurity ENV Variables All these variables impact in configuration directives in the modsecurity engine running inside the container. The [reference manual](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)) has the extended documentation, and for your reference we list the specific directive we change when you modify the ENV variables for the container. diff --git a/docker-bake.hcl b/docker-bake.hcl index 64d06d6d..cf8b54a2 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -41,7 +41,8 @@ group "default" { "apache", "apache-alpine", "nginx", - "nginx-alpine" + "nginx-alpine", + "openresty-alpine-fat" ] } @@ -87,3 +88,12 @@ target "nginx-alpine" { vtag("${crs-version}", "-nginx-alpine") ) } + +target "openresty-alpine-fat" { + inherits = ["platforms-base"] + platforms = ["linux/amd64", "linux/arm64/v8"] + dockerfile="openresty/Dockerfile-alpine" + tags = concat(tag("openresty-alpine-fat"), + vtag("${crs-version}", "-openresty-alpine-fat") + ) +} diff --git a/openresty/Dockerfile-alpine b/openresty/Dockerfile-alpine new file mode 100644 index 00000000..9ab3e381 --- /dev/null +++ b/openresty/Dockerfile-alpine @@ -0,0 +1,250 @@ +# Current latest Openresty version is here. +# Also specify the nginx core used. (Openresty, adds their own version numbers after the nginx one, so we can't use the same number for both Openresty and nginx) +ARG OPENRESTY_VERSION="1.25.3.1" \ + NGINX_VERSION="1.25.3" \ + MODSEC_VERSION="3.0.11" + +FROM openresty/openresty:${OPENRESTY_VERSION}-alpine-fat as build + +ARG MODSEC_VERSION \ + OPENRESTY_VERSION \ + NGINX_VERSION + +# Note: pcre-dev (PCRE 1) is required by the build description, +# even though the build will use PCRE2. +RUN set -eux; \ + apk add --no-cache --virtual .build-deps \ + autoconf \ + automake \ + ca-certificates \ + coreutils \ + curl-dev \ + g++ \ + gcc \ + geoip-dev \ + git \ + libc-dev \ + libfuzzy2-dev \ + libmaxminddb-dev \ + libstdc++ \ + libtool \ + libxml2-dev \ + libxml2 \ + libxslt-dev \ + libxslt \ + linux-headers \ + lmdb-dev \ + make \ + patch \ + pkgconfig \ + pcre-dev \ + pcre2-dev \ + yajl-dev \ + gd \ + gd-dev \ + zlib-dev + + +WORKDIR /sources + +# Download ModSecurity and compile it. +RUN set -eux; \ + git clone https://github.com/SpiderLabs/ModSecurity --branch v"${MODSEC_VERSION}" --depth 1 --recursive; \ + cd ModSecurity; \ + ARCH=$(gcc -print-multiarch); \ + sed -ie "s/i386-linux-gnu/${ARCH}/g" build/ssdeep.m4; \ + sed -ie "s/i386-linux-gnu/${ARCH}/g" build/pcre2.m4; \ + ./build.sh; \ + ./configure --with-yajl --with-ssdeep --with-lmdb --with-geoip --enable-silent-rules --with-pcre2; \ + make install; \ + strip /usr/local/modsecurity/lib/lib*.so* + +# We use latest version of the ModSecurity nginx connector. +# Download Openresty bundle for the specific version. We can then get the compilation options for nginx from the installed Openresty in the docker image to be used with the 'configure' script inside the openresty bundle to configure the ModSecurity-nginx module and then build it. I did not find the configure script inside the Openresty Docker image. +# Specify the LUAJIT_LIB and LUAJIT_INC that are already installed in the base image. +RUN set -eux; \ + git clone -b master --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git; \ + wget --quiet https://openresty.org/download/openresty-"${OPENRESTY_VERSION}".tar.gz; \ + tar -xzf openresty-"${OPENRESTY_VERSION}".tar.gz; \ + cd ./openresty-"${OPENRESTY_VERSION}"/bundle/nginx-${NGINX_VERSION}; \ + export LUAJIT_LIB="/usr/local/openresty/luajit/lib"; \ + export LUAJIT_INC="/usr/local/openresty/luajit/include/luajit-2.1"; \ + COMPILEOPTIONS=$(openresty -V 2>&1| grep -i "arguments"|cut -d ":" -f2-); \ + eval ./configure $COMPILEOPTIONS --add-dynamic-module=../../../ModSecurity-nginx; \ + make modules; \ + cp objs/ngx_http_modsecurity_module.so /usr/local/openresty/nginx/modules/; \ + mkdir /etc/modsecurity.d; \ + wget --quiet https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/modsecurity.conf-recommended \ + -O /etc/modsecurity.d/modsecurity.conf; \ + wget --quiet https://raw.githubusercontent.com/SpiderLabs/ModSecurity/v3/master/unicode.mapping \ + -O /etc/modsecurity.d/unicode.mapping + + +# Generate self-signed certificates (if needed) +RUN mkdir -p /usr/share/TLS +COPY openresty/openssl.conf /usr/share/TLS +RUN /usr/local/openresty/openssl/bin/openssl req -x509 -days 365 -new \ + -config /usr/share/TLS/openssl.conf \ + -keyout /usr/share/TLS/server.key \ + -out /usr/share/TLS/server.crt + +# Generate/Download Diffie-Hellman parameter files +RUN /usr/local/openresty/openssl/bin/openssl dhparam -out /usr/share/TLS/dhparam-1024.pem 1024 +RUN curl -sSL https://ssl-config.mozilla.org/ffdhe2048.txt -o /usr/share/TLS/dhparam-2048.pem +RUN curl -sSL https://ssl-config.mozilla.org/ffdhe4096.txt -o /usr/share/TLS/dhparam-4096.pem + +FROM openresty/openresty:${OPENRESTY_VERSION}-alpine-fat as crs_release + +ARG CRS_RELEASE + +# hadolint ignore=DL3008,SC2016 +RUN set -eux; \ + apk add --no-cache \ + ca-certificates \ + curl \ + gnupg; \ + mkdir /opt/owasp-crs; \ + curl -SL https://github.com/coreruleset/coreruleset/archive/v${CRS_RELEASE}.tar.gz -o v${CRS_RELEASE}.tar.gz; \ + curl -SL https://github.com/coreruleset/coreruleset/releases/download/v${CRS_RELEASE}/coreruleset-${CRS_RELEASE}.tar.gz.asc -o coreruleset-${CRS_RELEASE}.tar.gz.asc; \ + gpg --fetch-key https://coreruleset.org/security.asc; \ + gpg --verify coreruleset-${CRS_RELEASE}.tar.gz.asc v${CRS_RELEASE}.tar.gz; \ + tar -zxf v${CRS_RELEASE}.tar.gz --strip-components=1 -C /opt/owasp-crs; \ + rm -f v${CRS_RELEASE}.tar.gz coreruleset-${CRS_RELEASE}.tar.gz.asc; \ + mv -v /opt/owasp-crs/crs-setup.conf.example /opt/owasp-crs/crs-setup.conf + +FROM openresty/openresty:${OPENRESTY_VERSION}-alpine-fat + +ARG MODSEC_VERSION + +LABEL maintainer="Taavi Ansper " + +ENV ACCESSLOG=/var/log/nginx/access.log \ + BACKEND=http://localhost:80 \ + DNS_SERVER= \ + ERRORLOG=/var/log/nginx/error.log \ + LOGLEVEL=warn \ + METRICS_ALLOW_FROM='127.0.0.0/24' \ + METRICS_DENY_FROM='all' \ + METRICSLOG=/dev/null \ + MODSEC_AUDIT_ENGINE="RelevantOnly" \ + MODSEC_AUDIT_LOG_FORMAT=JSON \ + MODSEC_AUDIT_LOG_TYPE=Serial \ + MODSEC_AUDIT_LOG=/dev/stdout \ + MODSEC_AUDIT_LOG_PARTS='ABIJDEFHZ' \ + MODSEC_AUDIT_STORAGE=/var/log/modsecurity/audit/ \ + MODSEC_DATA_DIR=/tmp/modsecurity/data \ + MODSEC_DEBUG_LOG=/dev/null \ + MODSEC_DEBUG_LOGLEVEL=0 \ + MODSEC_DEFAULT_PHASE1_ACTION="phase:1,pass,log,tag:'\${MODSEC_TAG}'" \ + MODSEC_DEFAULT_PHASE2_ACTION="phase:2,pass,log,tag:'\${MODSEC_TAG}'" \ + MODSEC_PCRE_MATCH_LIMIT_RECURSION=100000 \ + MODSEC_PCRE_MATCH_LIMIT=100000 \ + MODSEC_REQ_BODY_ACCESS=on \ + MODSEC_REQ_BODY_LIMIT=13107200 \ + MODSEC_REQ_BODY_LIMIT_ACTION="Reject" \ + MODSEC_REQ_BODY_JSON_DEPTH_LIMIT=512 \ + MODSEC_REQ_BODY_NOFILES_LIMIT=131072 \ + MODSEC_RESP_BODY_ACCESS=on \ + MODSEC_RESP_BODY_LIMIT=1048576 \ + MODSEC_RESP_BODY_LIMIT_ACTION="ProcessPartial" \ + MODSEC_RESP_BODY_MIMETYPE="text/plain text/html text/xml" \ + MODSEC_RULE_ENGINE=on \ + MODSEC_STATUS_ENGINE="Off" \ + MODSEC_TAG=modsecurity \ + MODSEC_TMP_DIR=/tmp/modsecurity/tmp \ + MODSEC_TMP_SAVE_UPLOADED_FILES="on" \ + MODSEC_UPLOAD_DIR=/tmp/modsecurity/upload \ + PORT=80 \ + NGINX_ALWAYS_TLS_REDIRECT=off \ + SET_REAL_IP_FROM="127.0.0.1" \ + REAL_IP_HEADER="X-REAL-IP" \ + REAL_IP_PROXY_HEADER="X-REAL-IP" \ + REAL_IP_RECURSIVE="on" \ + PROXY_TIMEOUT=60s \ + PROXY_SSL_CERT=/usr/local/openresty/nginx/conf/server.crt \ + PROXY_SSL_CERT_KEY=/usr/local/openresty/nginx/conf/server.key \ + PROXY_SSL_DH_BITS=2048 \ + PROXY_SSL_PROTOCOLS="TLSv1.2 TLSv1.3" \ + PROXY_SSL_CIPHERS="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384" \ + PROXY_SSL_PREFER_CIPHERS=off \ + PROXY_SSL_VERIFY=off \ + PROXY_SSL_OCSP_STAPLING=off \ + SERVER_NAME=localhost \ + SSL_PORT=443 \ + TIMEOUT=60s \ + WORKER_CONNECTIONS=1024 \ + # Change this from normal nginx setup. Do not add /usr/lib or /lib + LD_LIBRARY_PATH=/usr/local/lib:/usr/local/openresty \ + NGINX_ENVSUBST_OUTPUT_DIR=/usr/local/openresty/nginx/conf \ + # CRS specific variables + PARANOIA=1 \ + ANOMALY_INBOUND=5 \ + ANOMALY_OUTBOUND=4 \ + BLOCKING_PARANOIA=1 + +COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/ +COPY --from=build /usr/local/openresty/nginx/modules/ngx_http_modsecurity_module.so /usr/local/openresty/nginx/modules/ngx_http_modsecurity_module.so +COPY --from=build /usr/share/TLS/server.key /usr/local/openresty/nginx/conf/server.key +COPY --from=build /usr/share/TLS/server.crt /usr/local/openresty/nginx/conf/server.crt +COPY --from=build /usr/share/TLS/dhparam-* /etc/ssl/certs/ +COPY --from=build /etc/modsecurity.d/unicode.mapping /etc/modsecurity.d/unicode.mapping +COPY --from=build /etc/modsecurity.d/modsecurity.conf /etc/modsecurity.d/modsecurity.conf +COPY --from=crs_release /opt/owasp-crs /opt/owasp-crs +# We use the templating mechanism from the nginx image here. +# Everything from templates except the nginx configuration, is the same for Openresty. +COPY nginx/templates/conf.d /usr/local/openresty/nginx/templates/conf.d +COPY nginx/templates/includes /usr/local/openresty/nginx/templates/includes +COPY nginx/templates/modsecurity.d /usr/local/openresty/nginx/templates/modsecurity.d +# Copy the nginx configuration separately +COPY src/etc/modsecurity.d/modsecurity-override.conf /usr/local/openresty/nginx/templates/modsecurity.d/modsecurity-override.conf.template +COPY src/etc/modsecurity.d/setup.conf /usr/local/openresty/nginx/templates/modsecurity.d/setup.conf.template +COPY src/bin/healthcheck /usr/local/bin/healthcheck +COPY src/opt/modsecurity/activate-plugins.sh /docker-entrypoint.d/94-activate-plugins.sh +COPY src/opt/modsecurity/activate-rules.sh /docker-entrypoint.d/95-activate-rules.sh + +# Openresty specific block. +COPY openresty/templates/nginx.conf.template /usr/local/openresty/nginx/templates +COPY openresty/docker-entrypoint.sh / +COPY openresty/docker-entrypoint.d/*.sh /docker-entrypoint.d/ + + +RUN set -eux; \ + apk add --no-cache \ + curl \ + curl-dev \ + libfuzzy2 \ + libmaxminddb-dev \ + libstdc++ \ + libxml2-dev \ + lmdb-dev \ + moreutils \ + tzdata \ + pcre \ + pcre2 \ + # Alpine needs GNU 'sed' because the 'sed' program shipped with busybox does not support 'z' parameter for separating lines with a 'NUL' character. + sed \ + yajl; \ + # Install lua modules here + luarocks install lua-resty-openidc; \ + mkdir /var/log/nginx; \ + mkdir -p /tmp/modsecurity/data; \ + mkdir -p /tmp/modsecurity/upload; \ + mkdir -p /tmp/modsecurity/tmp; \ + mkdir -p /usr/local/modsecurity; \ + # Comment out the SecDisableBackendCompression option since it is not supported in V3 + sed -i 's/^\(SecDisableBackendCompression .*\)/# \1/' /usr/local/openresty/nginx/templates/modsecurity.d/modsecurity-override.conf.template; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ + ln -sv /opt/owasp-crs /etc/modsecurity.d/; \ + chmod -R g=u /var/log/ /var/run/ /usr/local/openresty/nginx/ /etc/modsecurity.d/ + +EXPOSE 80 + +HEALTHCHECK CMD /usr/local/bin/healthcheck + +# The Openresty image is not based on the nginx image. +# This Dockerfile integrates the docker-entrypoint and envsubst logic from there into here. +ENTRYPOINT ["/docker-entrypoint.sh"] + +CMD ["/usr/local/openresty/bin/openresty", "-g", "daemon off;"] diff --git a/openresty/docker-entrypoint.d/20-envsubst-on-templates.sh b/openresty/docker-entrypoint.d/20-envsubst-on-templates.sh new file mode 100755 index 00000000..b90d9a9c --- /dev/null +++ b/openresty/docker-entrypoint.d/20-envsubst-on-templates.sh @@ -0,0 +1,39 @@ +#!/bin/sh + +set -e + +ME=$(basename $0) + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +auto_envsubst() { + local template_dir="${NGINX_ENVSUBST_TEMPLATE_DIR:-/usr/local/openresty/nginx/templates}" + local suffix="${NGINX_ENVSUBST_TEMPLATE_SUFFIX:-.template}" + local output_dir="${NGINX_ENVSUBST_OUTPUT_DIR:-/usr/local/openresty/nginx/conf}" + local filter="${NGINX_ENVSUBST_FILTER:-}" + + local template defined_envs relative_path output_path subdir + defined_envs=$(printf '${%s} ' $(awk "END { for (name in ENVIRON) { print ( name ~ /${filter}/ ) ? name : \"\" } }" < /dev/null )) + [ -d "$template_dir" ] || return 0 + if [ ! -w "$output_dir" ]; then + entrypoint_log "$ME: ERROR: $template_dir exists, but $output_dir is not writable" + return 0 + fi + find "$template_dir" -follow -type f -name "*$suffix" -print | while read -r template; do + relative_path="${template#$template_dir/}" + output_path="$output_dir/${relative_path%$suffix}" + subdir=$(dirname "$relative_path") + # create a subdirectory where the template file exists + mkdir -p "$output_dir/$subdir" + entrypoint_log "$ME: Running envsubst on $template to $output_path" + envsubst "$defined_envs" < "$template" > "$output_path" + done +} + +auto_envsubst + +exit 0 diff --git a/openresty/docker-entrypoint.d/25-listen-on-ipv6-by-default.sh b/openresty/docker-entrypoint.d/25-listen-on-ipv6-by-default.sh new file mode 100755 index 00000000..8c75c997 --- /dev/null +++ b/openresty/docker-entrypoint.d/25-listen-on-ipv6-by-default.sh @@ -0,0 +1,67 @@ +#!/bin/sh +# vim:sw=4:ts=4:et + +set -e + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +ME=$(basename $0) +DEFAULT_CONF_FILE="usr/local/openresty/nginx/conf/conf.d/default.conf" + +# check if we have ipv6 available +if [ ! -f "/proc/net/if_inet6" ]; then + entrypoint_log "$ME: info: ipv6 not available" + exit 0 +fi + +if [ ! -f "/$DEFAULT_CONF_FILE" ]; then + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE is not a file or does not exist" + exit 0 +fi + +# check if the file can be modified, e.g. not on a r/o filesystem +touch /$DEFAULT_CONF_FILE 2>/dev/null || { entrypoint_log "$ME: info: can not modify /$DEFAULT_CONF_FILE (read-only file system?)"; exit 0; } + +# check if the file is already modified, e.g. on a container restart +grep -q "listen \[::]\:80;" /$DEFAULT_CONF_FILE && { entrypoint_log "$ME: info: IPv6 listen already enabled"; exit 0; } + +if [ -f "/etc/os-release" ]; then + . /etc/os-release +else + entrypoint_log "$ME: info: can not guess the operating system" + exit 0 +fi + +entrypoint_log "$ME: info: Getting the checksum of /$DEFAULT_CONF_FILE" + +case "$ID" in + "debian") + CHECKSUM=$(dpkg-query --show --showformat='${Conffiles}\n' nginx | grep $DEFAULT_CONF_FILE | cut -d' ' -f 3) + echo "$CHECKSUM /$DEFAULT_CONF_FILE" | md5sum -c - >/dev/null 2>&1 || { + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + exit 0 + } + ;; + "alpine") + CHECKSUM=$(apk manifest nginx 2>/dev/null| grep $DEFAULT_CONF_FILE | cut -d' ' -f 1 | cut -d ':' -f 2) + echo "$CHECKSUM /$DEFAULT_CONF_FILE" | sha1sum -c - >/dev/null 2>&1 || { + entrypoint_log "$ME: info: /$DEFAULT_CONF_FILE differs from the packaged version" + exit 0 + } + ;; + *) + entrypoint_log "$ME: info: Unsupported distribution" + exit 0 + ;; +esac + +# enable ipv6 on default.conf listen sockets +sed -i -E 's,listen 80;,listen 80;\n listen [::]:80;,' /$DEFAULT_CONF_FILE + +entrypoint_log "$ME: info: Enabled listen on IPv6 in /$DEFAULT_CONF_FILE" + +exit 0 diff --git a/openresty/docker-entrypoint.d/30-tune-worker-processes.sh b/openresty/docker-entrypoint.d/30-tune-worker-processes.sh new file mode 100755 index 00000000..6314e52e --- /dev/null +++ b/openresty/docker-entrypoint.d/30-tune-worker-processes.sh @@ -0,0 +1,188 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +ME=$( basename "$0" ) +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +[ "${NGINX_ENTRYPOINT_WORKER_PROCESSES_AUTOTUNE:-}" ] || exit 0 + +touch /usr/local/openresty/nginx/nginx.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /usr/local/openresty/nginx/nginx.conf (read-only file system?)"; exit 0; } + +ceildiv() { + num=$1 + div=$2 + echo $(( (num + div - 1) / div )) +} + +get_cpuset() { + cpusetroot=$1 + cpusetfile=$2 + ncpu=0 + [ -f "$cpusetroot/$cpusetfile" ] || return 1 + for token in $( tr ',' ' ' < "$cpusetroot/$cpusetfile" ); do + case "$token" in + *-*) + count=$( seq $(echo "$token" | tr '-' ' ') | wc -l ) + ncpu=$(( ncpu+count )) + ;; + *) + ncpu=$(( ncpu+1 )) + ;; + esac + done + echo "$ncpu" +} + +get_quota() { + cpuroot=$1 + ncpu=0 + [ -f "$cpuroot/cpu.cfs_quota_us" ] || return 1 + [ -f "$cpuroot/cpu.cfs_period_us" ] || return 1 + cfs_quota=$( cat "$cpuroot/cpu.cfs_quota_us" ) + cfs_period=$( cat "$cpuroot/cpu.cfs_period_us" ) + [ "$cfs_quota" = "-1" ] && return 1 + [ "$cfs_period" = "0" ] && return 1 + ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) + [ "$ncpu" -gt 0 ] || return 1 + echo "$ncpu" +} + +get_quota_v2() { + cpuroot=$1 + ncpu=0 + [ -f "$cpuroot/cpu.max" ] || return 1 + cfs_quota=$( cut -d' ' -f 1 < "$cpuroot/cpu.max" ) + cfs_period=$( cut -d' ' -f 2 < "$cpuroot/cpu.max" ) + [ "$cfs_quota" = "max" ] && return 1 + [ "$cfs_period" = "0" ] && return 1 + ncpu=$( ceildiv "$cfs_quota" "$cfs_period" ) + [ "$ncpu" -gt 0 ] || return 1 + echo "$ncpu" +} + +get_cgroup_v1_path() { + needle=$1 + found= + foundroot= + mountpoint= + + [ -r "/proc/self/mountinfo" ] || return 1 + [ -r "/proc/self/cgroup" ] || return 1 + + while IFS= read -r line; do + case "$needle" in + "cpuset") + case "$line" in + *cpuset*) + found=$( echo "$line" | cut -d ' ' -f 4,5 ) + break + ;; + esac + ;; + "cpu") + case "$line" in + *cpuset*) + ;; + *cpu,cpuacct*|*cpuacct,cpu|*cpuacct*|*cpu*) + found=$( echo "$line" | cut -d ' ' -f 4,5 ) + break + ;; + esac + esac + done << __EOF__ +$( grep -F -- '- cgroup ' /proc/self/mountinfo ) +__EOF__ + + while IFS= read -r line; do + controller=$( echo "$line" | cut -d: -f 2 ) + case "$needle" in + "cpuset") + case "$controller" in + cpuset) + mountpoint=$( echo "$line" | cut -d: -f 3 ) + break + ;; + esac + ;; + "cpu") + case "$controller" in + cpu,cpuacct|cpuacct,cpu|cpuacct|cpu) + mountpoint=$( echo "$line" | cut -d: -f 3 ) + break + ;; + esac + ;; + esac +done << __EOF__ +$( grep -F -- 'cpu' /proc/self/cgroup ) +__EOF__ + + case "${found%% *}" in + "/") + foundroot="${found##* }$mountpoint" + ;; + "$mountpoint") + foundroot="${found##* }" + ;; + esac + echo "$foundroot" +} + +get_cgroup_v2_path() { + found= + foundroot= + mountpoint= + + [ -r "/proc/self/mountinfo" ] || return 1 + [ -r "/proc/self/cgroup" ] || return 1 + + while IFS= read -r line; do + found=$( echo "$line" | cut -d ' ' -f 4,5 ) + done << __EOF__ +$( grep -F -- '- cgroup2 ' /proc/self/mountinfo ) +__EOF__ + + while IFS= read -r line; do + mountpoint=$( echo "$line" | cut -d: -f 3 ) +done << __EOF__ +$( grep -F -- '0::' /proc/self/cgroup ) +__EOF__ + + case "${found%% *}" in + "") + return 1 + ;; + "/") + foundroot="${found##* }$mountpoint" + ;; + "$mountpoint" | /../*) + foundroot="${found##* }" + ;; + esac + echo "$foundroot" +} + +ncpu_online=$( getconf _NPROCESSORS_ONLN ) +ncpu_cpuset= +ncpu_quota= +ncpu_cpuset_v2= +ncpu_quota_v2= + +cpuset=$( get_cgroup_v1_path "cpuset" ) && ncpu_cpuset=$( get_cpuset "$cpuset" "cpuset.effective_cpus" ) || ncpu_cpuset=$ncpu_online +cpu=$( get_cgroup_v1_path "cpu" ) && ncpu_quota=$( get_quota "$cpu" ) || ncpu_quota=$ncpu_online +cgroup_v2=$( get_cgroup_v2_path ) && ncpu_cpuset_v2=$( get_cpuset "$cgroup_v2" "cpuset.cpus.effective" ) || ncpu_cpuset_v2=$ncpu_online +cgroup_v2=$( get_cgroup_v2_path ) && ncpu_quota_v2=$( get_quota_v2 "$cgroup_v2" ) || ncpu_quota_v2=$ncpu_online + +ncpu=$( printf "%s\n%s\n%s\n%s\n%s\n" \ + "$ncpu_online" \ + "$ncpu_cpuset" \ + "$ncpu_quota" \ + "$ncpu_cpuset_v2" \ + "$ncpu_quota_v2" \ + | sort -n \ + | head -n 1 ) + +sed -i.bak -r 's/^(worker_processes)(.*)$/# Commented out by '"$ME"' on '"$(date)"'\n#\1\2\n\1 '"$ncpu"';/' /usr/local/openresty/nginx/nginx.conf diff --git a/openresty/docker-entrypoint.d/90-copy-modsecurity-config.sh b/openresty/docker-entrypoint.d/90-copy-modsecurity-config.sh new file mode 100755 index 00000000..162b530e --- /dev/null +++ b/openresty/docker-entrypoint.d/90-copy-modsecurity-config.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +ME=$( basename "$0" ) +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +touch /etc/modsecurity.d/modsecurity-override.conf 2>/dev/null || { echo >&2 "$ME: error: can not modify /etc/modsecurity.d/modsecurity-override.conf (read-only file system?)"; exit 1; } + +cp /usr/local/openresty/nginx/conf/modsecurity.d/*.conf /etc/modsecurity.d 2>/dev/null || { echo >&2 "$ME: error: cannot copy config files to /etc/modsecurity.d"; exit 2; } + +exit 0 diff --git a/openresty/docker-entrypoint.d/91-update-resolver.sh b/openresty/docker-entrypoint.d/91-update-resolver.sh new file mode 100755 index 00000000..5ddb6b45 --- /dev/null +++ b/openresty/docker-entrypoint.d/91-update-resolver.sh @@ -0,0 +1,12 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +ME=$( basename "$0" ) +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +DNS_SERVER="${DNS_SERVER:-$(grep -i '^nameserver' /etc/resolv.conf | head -n1 | cut -d ' ' -f2)}" + +sed -i.bak -r 's/DNS_SERVER/'"${DNS_SERVER}"'/' /usr/local/openresty/nginx/conf/nginx.conf diff --git a/openresty/docker-entrypoint.d/92-update-real_ip.sh b/openresty/docker-entrypoint.d/92-update-real_ip.sh new file mode 100755 index 00000000..74caf2be --- /dev/null +++ b/openresty/docker-entrypoint.d/92-update-real_ip.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# vim:sw=2:ts=2:sts=2:et + +set -eu + +LC_ALL=C +ME=$( basename "$0" ) +PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin + +# split comma separated IP addresses into multiple `set_real_ip xxx;` lines +SET_REAL_IP_FROM="$(echo "${SET_REAL_IP_FROM}" | awk -F, '{for(i=1; i<=NF; i++) printf "set_real_ip_from "$i";\\n"}')" + +sed -i.bak -r 's#SET_REAL_IP_FROM#'"${SET_REAL_IP_FROM}"'#' /usr/local/openresty/nginx/conf/includes/proxy_backend.conf diff --git a/openresty/docker-entrypoint.sh b/openresty/docker-entrypoint.sh new file mode 100755 index 00000000..cc1335de --- /dev/null +++ b/openresty/docker-entrypoint.sh @@ -0,0 +1,47 @@ +#!/bin/sh +# vim:sw=4:ts=4:et + +set -e + +entrypoint_log() { + if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then + echo "$@" + fi +} + +if [ "$1" = "/usr/local/openresty/bin/openresty" ]; then + if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then + entrypoint_log "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration" + + entrypoint_log "$0: Looking for shell scripts in /docker-entrypoint.d/" + find "/docker-entrypoint.d/" -follow -type f -print | sort -V | while read -r f; do + case "$f" in + *.envsh) + if [ -x "$f" ]; then + entrypoint_log "$0: Sourcing $f"; + . "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *.sh) + if [ -x "$f" ]; then + entrypoint_log "$0: Launching $f"; + "$f" + else + # warn on shell scripts without exec bit + entrypoint_log "$0: Ignoring $f, not executable"; + fi + ;; + *) entrypoint_log "$0: Ignoring $f";; + esac + done + + entrypoint_log "$0: Configuration complete; ready for start up" + else + entrypoint_log "$0: No files found in /docker-entrypoint.d/, skipping configuration" + fi +fi + +exec "$@" diff --git a/openresty/openssl.conf b/openresty/openssl.conf new file mode 100644 index 00000000..560223af --- /dev/null +++ b/openresty/openssl.conf @@ -0,0 +1,15 @@ +[req] +default_bits=4096 +encrypt_key=no +default_md=sha256 +distinguished_name=req_sub +prompt=no + +[req_sub] +commonName="localhost" +emailAddress="none@none.com" +countryName="US" +stateOrProvinceName="NY" +localityName="NY" +organizationName="MyOrg" +organizationalUnitName="MyUnit" diff --git a/openresty/templates/nginx.conf.template b/openresty/templates/nginx.conf.template new file mode 100644 index 00000000..caceef1d --- /dev/null +++ b/openresty/templates/nginx.conf.template @@ -0,0 +1,32 @@ +# nginx.conf -- docker-openresty-modsecurity-crs + +# Enables the use of JIT for regular expressions to speed-up their processing. +pcre_jit on; + +load_module modules/ngx_http_modsecurity_module.so; + +worker_processes auto; +pid /var/run/nginx.pid; + +events { + worker_connections ${WORKER_CONNECTIONS}; +} + +http { + include /usr/local/openresty/nginx/conf/mime.types; + default_type application/octet-stream; + keepalive_timeout ${TIMEOUT}; + sendfile on; + + # Openresty specific paths. + client_body_temp_path /var/run/openresty/nginx-client-body; + proxy_temp_path /var/run/openresty/nginx-proxy; + fastcgi_temp_path /var/run/openresty/nginx-fastcgi; + uwsgi_temp_path /var/run/openresty/nginx-uwsgi; + scgi_temp_path /var/run/openresty/nginx-scgi; + + resolver DNS_SERVER valid=5s; + # Load the specific files from /usr/local/openresty folder instead of /etc/nginx + # Simplifies the usage of envsubst. Otherwise we need to two template output folders. + include /usr/local/openresty/nginx/conf/conf.d/*.conf; +} From 66194d7a281edae118bbaf0a1a09d46a3d219d36 Mon Sep 17 00:00:00 2001 From: Max Leske Date: Sat, 27 Jan 2024 16:02:36 +0100 Subject: [PATCH 4/6] feat: move version information to bake file --- apache/Dockerfile | 26 ++++++++++---------- apache/Dockerfile-alpine | 26 ++++++++++---------- docker-bake.hcl | 48 +++++++++++++++++++++++++++++++++++++ nginx/Dockerfile | 24 +++++++++---------- nginx/Dockerfile-alpine | 20 ++++++++-------- openresty/Dockerfile-alpine | 22 ++++++++--------- 6 files changed, 106 insertions(+), 60 deletions(-) diff --git a/apache/Dockerfile b/apache/Dockerfile index a6658370..fffc66cd 100644 --- a/apache/Dockerfile +++ b/apache/Dockerfile @@ -1,9 +1,9 @@ -ARG APACHE_VERSION=2.4.58 +ARG HTTPD_VERSION="n/a" -FROM httpd:${APACHE_VERSION} as build +FROM httpd:${HTTPD_VERSION} as build -ARG MODSEC_VERSION=2.9.7 \ - LUA_VERSION=5.3 +ARG MODSEC2_VERSION="n/a" +ARG LUA_VERSION="n/a" RUN set -eux; \ echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections; \ @@ -27,16 +27,16 @@ RUN set -eux; \ wget RUN set -eux; \ - wget --quiet https://github.com/SpiderLabs/ModSecurity/archive/refs/tags/v${MODSEC_VERSION}.tar.gz; \ - tar -zxvf v${MODSEC_VERSION}.tar.gz; \ - cd ModSecurity-${MODSEC_VERSION}; \ + wget --quiet https://github.com/SpiderLabs/ModSecurity/archive/refs/tags/v${MODSEC2_VERSION}.tar.gz; \ + tar -zxvf v${MODSEC2_VERSION}.tar.gz; \ + cd ModSecurity-${MODSEC2_VERSION}; \ ./autogen.sh; \ ./configure --with-yajl --with-ssdeep; \ make; \ make install; \ make clean -FROM httpd:${APACHE_VERSION} as crs_release +FROM httpd:${HTTPD_VERSION} as crs_release ARG CRS_RELEASE @@ -56,10 +56,10 @@ RUN set -eux; \ rm -f v${CRS_RELEASE}.tar.gz coreruleset-${CRS_RELEASE}.tar.gz.asc; \ mv -v /opt/owasp-crs/crs-setup.conf.example /opt/owasp-crs/crs-setup.conf -FROM httpd:${APACHE_VERSION} +FROM httpd:${HTTPD_VERSION} -ARG MODSEC_VERSION=2.9.7 \ - LUA_VERSION=5.3 +ARG MODSEC2_VERSION="n/a" +ARG LUA_VERSION="n/a" LABEL maintainer="Felipe Zipitria " @@ -141,8 +141,8 @@ ENV APACHE_ALWAYS_TLS_REDIRECT=off \ BLOCKING_PARANOIA=1 COPY --from=build /usr/local/apache2/modules/mod_security2.so /usr/local/apache2/modules/mod_security2.so -COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC_VERSION}/modsecurity.conf-recommended /etc/modsecurity.d/modsecurity.conf -COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC_VERSION}/unicode.mapping /etc/modsecurity.d/unicode.mapping +COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC2_VERSION}/modsecurity.conf-recommended /etc/modsecurity.d/modsecurity.conf +COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC2_VERSION}/unicode.mapping /etc/modsecurity.d/unicode.mapping COPY --from=crs_release /opt/owasp-crs /opt/owasp-crs COPY src/etc/modsecurity.d/*.conf /etc/modsecurity.d/ COPY src/bin/* /usr/local/bin/ diff --git a/apache/Dockerfile-alpine b/apache/Dockerfile-alpine index 05657fad..c2f629a4 100644 --- a/apache/Dockerfile-alpine +++ b/apache/Dockerfile-alpine @@ -1,9 +1,9 @@ -ARG APACHE_VERSION=2.4.58 +ARG HTTPD_VERSION="n/a" -FROM httpd:${APACHE_VERSION}-alpine as build +FROM httpd:${HTTPD_VERSION}-alpine as build -ARG MODSEC_VERSION=2.9.7 \ - LUA_VERSION=5.3 +ARG MODSEC2_VERSION="n/a" +ARG LUA_VERSION="n/a" # see https://httpd.apache.org/docs/2.4/install.html#requirements RUN set -eux; \ @@ -37,16 +37,16 @@ RUN set -eux; \ zlib-dev RUN set -eux; \ - wget --quiet https://github.com/SpiderLabs/ModSecurity/archive/refs/tags/v${MODSEC_VERSION}.tar.gz; \ - tar -zxvf v${MODSEC_VERSION}.tar.gz; \ - cd ModSecurity-${MODSEC_VERSION}; \ + wget --quiet https://github.com/SpiderLabs/ModSecurity/archive/refs/tags/v${MODSEC2_VERSION}.tar.gz; \ + tar -zxvf v${MODSEC2_VERSION}.tar.gz; \ + cd ModSecurity-${MODSEC2_VERSION}; \ ./autogen.sh; \ ./configure --with-yajl --with-ssdeep --with-lmdb; \ make; \ make install; \ make clean -FROM httpd:${APACHE_VERSION}-alpine as crs_release +FROM httpd:${HTTPD_VERSION}-alpine as crs_release ARG CRS_RELEASE @@ -66,10 +66,10 @@ RUN set -eux; \ rm -f v${CRS_RELEASE}.tar.gz coreruleset-${CRS_RELEASE}.tar.gz.asc; \ mv -v /opt/owasp-crs/crs-setup.conf.example /opt/owasp-crs/crs-setup.conf -FROM httpd:${APACHE_VERSION}-alpine +FROM httpd:${HTTPD_VERSION}-alpine -ARG MODSEC_VERSION=2.9.7 \ - LUA_VERSION=5.3 +ARG MODSEC2_VERSION="n/a" +ARG LUA_VERSION="n/a" LABEL maintainer="Felipe Zipitria " @@ -151,8 +151,8 @@ ENV APACHE_ALWAYS_TLS_REDIRECT=off \ BLOCKING_PARANOIA=1 COPY --from=build /usr/local/apache2/modules/mod_security2.so /usr/local/apache2/modules/mod_security2.so -COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC_VERSION}/modsecurity.conf-recommended /etc/modsecurity.d/modsecurity.conf -COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC_VERSION}/unicode.mapping /etc/modsecurity.d/unicode.mapping +COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC2_VERSION}/modsecurity.conf-recommended /etc/modsecurity.d/modsecurity.conf +COPY --from=build /usr/local/apache2/ModSecurity-${MODSEC2_VERSION}/unicode.mapping /etc/modsecurity.d/unicode.mapping COPY --from=crs_release /opt/owasp-crs /opt/owasp-crs COPY src/etc/modsecurity.d/*.conf /etc/modsecurity.d/ COPY src/bin/* /usr/local/bin/ diff --git a/docker-bake.hcl b/docker-bake.hcl index cf8b54a2..47c62326 100644 --- a/docker-bake.hcl +++ b/docker-bake.hcl @@ -1,8 +1,36 @@ # docker-bake.hcl +variable "modsec3-version" { + default = "3.0.11" +} + +variable "modsec2-version" { + default = "2.9.7" +} + variable "crs-version" { default = "3.3.5" } +variable "nginx-version" { + default = "1.25.3" +} + +variable "httpd-version" { + default = "2.4.58" +} + +variable "openresty-version" { + default = "1.25.3.1" +} + +variable "lua-version" { + default = "5.3" +} + +variable "lmdb-version" { + default = "0.9.29" +} + variable "REPO" { default = "owasp/modsecurity-crs" } @@ -54,12 +82,19 @@ target "platforms-base" { platforms = ["linux/amd64", "linux/arm64/v8", "linux/arm/v7", "linux/i386"] args = { CRS_RELEASE = "${crs-version}" + MODSEC2_VERSION = "${modsec2-version}" + MODSEC3_VERSION = "${modsec3-version}" + LUA_VERSION = "${lua-version}" + LMDB_VERSION = "${lmdb-version}" } } target "apache" { inherits = ["platforms-base"] dockerfile="apache/Dockerfile" + args = { + HTTPD_VERSION = "${httpd-version}" + } tags = concat(tag("apache"), vtag("${crs-version}", "-apache") ) @@ -68,6 +103,9 @@ target "apache" { target "apache-alpine" { inherits = ["platforms-base"] dockerfile="apache/Dockerfile-alpine" + args = { + HTTPD_VERSION = "${httpd-version}" + } tags = concat(tag("apache-alpine"), vtag("${crs-version}", "-apache-alpine") ) @@ -76,6 +114,9 @@ target "apache-alpine" { target "nginx" { inherits = ["platforms-base"] dockerfile="nginx/Dockerfile" + args = { + NGINX_VERSION = "${nginx-version}" + } tags = concat(tag("nginx"), vtag("${crs-version}", "-nginx") ) @@ -84,6 +125,9 @@ target "nginx" { target "nginx-alpine" { inherits = ["platforms-base"] dockerfile="nginx/Dockerfile-alpine" + args = { + NGINX_VERSION = "${nginx-version}" + } tags = concat(tag("nginx-alpine"), vtag("${crs-version}", "-nginx-alpine") ) @@ -93,6 +137,10 @@ target "openresty-alpine-fat" { inherits = ["platforms-base"] platforms = ["linux/amd64", "linux/arm64/v8"] dockerfile="openresty/Dockerfile-alpine" + args = { + OPENRESTY_VERSION = "${openresty-version}" + NGINX_VERSION = "${nginx-version}" + } tags = concat(tag("openresty-alpine-fat"), vtag("${crs-version}", "-openresty-alpine-fat") ) diff --git a/nginx/Dockerfile b/nginx/Dockerfile index 8b21e6c7..6dd44990 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,10 +1,10 @@ -ARG NGINX_VERSION="1.25.3" +ARG NGINX_VERSION="n/a" FROM nginx:${NGINX_VERSION} as build -ARG MODSEC_VERSION=3.0.11 \ - LMDB_VERSION=0.9.29 \ - LUA_VERSION=5.3 +ARG MODSEC3_VERSION="n/a" +ARG LMDB_VERSION="n/a" +ARG LUA_VERSION="n/a" # Note: libpcre3-dev (PCRE 1) is required by the build description, # even though the build will use PCRE2. @@ -42,7 +42,7 @@ RUN set -eux; \ strip /usr/local/lib/liblmdb*.so* RUN set -eux; \ - git clone https://github.com/SpiderLabs/ModSecurity --branch v"${MODSEC_VERSION}" --depth 1 --recursive; \ + git clone https://github.com/SpiderLabs/ModSecurity --branch "v${MODSEC3_VERSION}" --depth 1 --recursive; \ cd ModSecurity; \ ARCH=$(gcc -print-multiarch); \ sed -ie "s/i386-linux-gnu/${ARCH}/g" build/ssdeep.m4; \ @@ -96,9 +96,9 @@ RUN set -eux; \ FROM nginx:${NGINX_VERSION} -ARG MODSEC_VERSION=3.0.11 \ - LMDB_VERSION=0.9.29 \ - LUA_VERSION=5.3 +ARG MODSEC3_VERSION="n/a" +ARG LMDB_VERSION="n/a" +ARG LUA_VERSION="n/a" LABEL maintainer="Felipe Zipitria " @@ -166,7 +166,7 @@ ENV ACCESSLOG=/var/log/nginx/access.log \ ANOMALY_OUTBOUND=4 \ BLOCKING_PARANOIA=1 -COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/ +COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/ COPY --from=build /etc/nginx/modules/ngx_http_modsecurity_module.so /etc/nginx/modules/ngx_http_modsecurity_module.so COPY --from=build /usr/local/lib/liblmdb.so /usr/local/lib/ COPY --from=build /usr/share/TLS/dhparam-* /etc/ssl/certs/ @@ -204,9 +204,9 @@ RUN set -eux; \ chown -R nginx:nginx /tmp/modsecurity; \ # Comment out the SecDisableBackendCompression option since it is not supported in V3 sed -i 's/^\(SecDisableBackendCompression .*\)/# \1/' /etc/nginx/templates/modsecurity.d/modsecurity-override.conf.template; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ chgrp -R 0 /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/; \ chmod -R g=u /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/; \ ln -sv /opt/owasp-crs /etc/modsecurity.d/ diff --git a/nginx/Dockerfile-alpine b/nginx/Dockerfile-alpine index eef38cbf..c388b831 100644 --- a/nginx/Dockerfile-alpine +++ b/nginx/Dockerfile-alpine @@ -1,9 +1,9 @@ -ARG NGINX_VERSION="1.25.3" +ARG NGINX_VERSION="n/a" FROM nginx:${NGINX_VERSION}-alpine as build -ARG MODSEC_VERSION=3.0.11 \ - LUA_VERSION=5.3 +ARG MODSEC3_VERSION="n/a" +ARG LUA_VERSION="n/a" # Note: pcre-dev (PCRE 1) is required by the build description, # even though the build will use PCRE2. @@ -40,7 +40,7 @@ RUN set -eux; \ WORKDIR /sources RUN set -eux; \ - git clone https://github.com/SpiderLabs/ModSecurity --branch v"${MODSEC_VERSION}" --depth 1 --recursive; \ + git clone https://github.com/SpiderLabs/ModSecurity --branch "v${MODSEC3_VERSION}" --depth 1 --recursive; \ cd ModSecurity; \ ARCH=$(gcc -print-multiarch); \ sed -ie "s/i386-linux-gnu/${ARCH}/g" build/ssdeep.m4; \ @@ -92,8 +92,8 @@ RUN set -eux; \ FROM nginx:${NGINX_VERSION}-alpine -ARG MODSEC_VERSION=3.0.11 \ - LUA_VERSION=5.3 +ARG MODSEC3_VERSION +ARG LUA_VERSION LABEL maintainer="Felipe Zipitria " @@ -161,7 +161,7 @@ ENV ACCESSLOG=/var/log/nginx/access.log \ ANOMALY_OUTBOUND=4 \ BLOCKING_PARANOIA=1 -COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/ +COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/ COPY --from=build /etc/nginx/modules/ngx_http_modsecurity_module.so /etc/nginx/modules/ngx_http_modsecurity_module.so COPY --from=build /usr/share/TLS/dhparam-* /etc/ssl/certs/ COPY --from=build /etc/modsecurity.d/unicode.mapping /etc/modsecurity.d/unicode.mapping @@ -202,9 +202,9 @@ RUN set -eux; \ chown -R nginx:nginx /usr/share/nginx /tmp/modsecurity; \ # Comment out the SecDisableBackendCompression option since it is not supported in V3 sed -i 's/^\(SecDisableBackendCompression .*\)/# \1/' /etc/nginx/templates/modsecurity.d/modsecurity-override.conf.template; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ ln -sv /opt/owasp-crs /etc/modsecurity.d/; \ chgrp -R 0 /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/; \ chmod -R g=u /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/ diff --git a/openresty/Dockerfile-alpine b/openresty/Dockerfile-alpine index 9ab3e381..f16c0d4c 100644 --- a/openresty/Dockerfile-alpine +++ b/openresty/Dockerfile-alpine @@ -1,14 +1,12 @@ # Current latest Openresty version is here. # Also specify the nginx core used. (Openresty, adds their own version numbers after the nginx one, so we can't use the same number for both Openresty and nginx) -ARG OPENRESTY_VERSION="1.25.3.1" \ - NGINX_VERSION="1.25.3" \ - MODSEC_VERSION="3.0.11" +ARG OPENRESTY_VERSION="n/a" FROM openresty/openresty:${OPENRESTY_VERSION}-alpine-fat as build -ARG MODSEC_VERSION \ - OPENRESTY_VERSION \ - NGINX_VERSION +ARG OPENRESTY_VERSION +ARG MODSEC3_VERSION="n/a" +ARG NGINX_VERSION="n/a" # Note: pcre-dev (PCRE 1) is required by the build description, # even though the build will use PCRE2. @@ -49,7 +47,7 @@ WORKDIR /sources # Download ModSecurity and compile it. RUN set -eux; \ - git clone https://github.com/SpiderLabs/ModSecurity --branch v"${MODSEC_VERSION}" --depth 1 --recursive; \ + git clone https://github.com/SpiderLabs/ModSecurity --branch "v${MODSEC3_VERSION}" --depth 1 --recursive; \ cd ModSecurity; \ ARCH=$(gcc -print-multiarch); \ sed -ie "s/i386-linux-gnu/${ARCH}/g" build/ssdeep.m4; \ @@ -114,7 +112,7 @@ RUN set -eux; \ FROM openresty/openresty:${OPENRESTY_VERSION}-alpine-fat -ARG MODSEC_VERSION +ARG MODSEC3_VERSION LABEL maintainer="Taavi Ansper " @@ -182,7 +180,7 @@ ENV ACCESSLOG=/var/log/nginx/access.log \ ANOMALY_OUTBOUND=4 \ BLOCKING_PARANOIA=1 -COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/ +COPY --from=build /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/ COPY --from=build /usr/local/openresty/nginx/modules/ngx_http_modsecurity_module.so /usr/local/openresty/nginx/modules/ngx_http_modsecurity_module.so COPY --from=build /usr/share/TLS/server.key /usr/local/openresty/nginx/conf/server.key COPY --from=build /usr/share/TLS/server.crt /usr/local/openresty/nginx/conf/server.crt @@ -233,9 +231,9 @@ RUN set -eux; \ mkdir -p /usr/local/modsecurity; \ # Comment out the SecDisableBackendCompression option since it is not supported in V3 sed -i 's/^\(SecDisableBackendCompression .*\)/# \1/' /usr/local/openresty/nginx/templates/modsecurity.d/modsecurity-override.conf.template; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ - ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ + ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ ln -sv /opt/owasp-crs /etc/modsecurity.d/; \ chmod -R g=u /var/log/ /var/run/ /usr/local/openresty/nginx/ /etc/modsecurity.d/ From bb96afdbffd4f05b023316ad5bf385ed6325ec38 Mon Sep 17 00:00:00 2001 From: Max Leske Date: Sat, 27 Jan 2024 17:17:48 +0100 Subject: [PATCH 5/6] docs: update and improve readmes --- README-containers.md | 58 ++++++++++++++++++++++++++------ README.md | 78 +++++++++++++++++++++++++++++--------------- 2 files changed, 100 insertions(+), 36 deletions(-) diff --git a/README-containers.md b/README-containers.md index 3cbaa853..21ecea3e 100644 --- a/README-containers.md +++ b/README-containers.md @@ -15,23 +15,50 @@ The Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity or compatible web application firewalls. -## Supported tags and respective `Dockerfile` links +## Supported Tags -* `3-nginx-YYYYMMDDHHMM`, `3.3-nginx-YYYYMMDDHHMM`, `3.3.5-nginx-YYYYMMDDHHMM`, `nginx` ([master/nginx/Dockerfile](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile)) – *last stable ModSecurity v3 on Nginx 1.25.3 official stable base image, and latest stable Core Rule Set 3.3.5* -* `3-apache-YYYYMMDDHHMM`, `3.3-apache-YYYYMMDDHHMM`, `3.3.5-apache-YYYYMMDDHHMM`, `apache` ([master/apache/Dockerfile](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile)) –*last stable ModSecurity v2 on Apache 2.4.58 official stable base image, and latest stable Core Rule Set 3.3.5* +### Stable Tags -🆕 We added healthchecks to the images. Containers already return HTTP status code 200 when accessing the `/healthz` URI. When a container has a healthcheck specified, it has a _health status_ in addition to its normal status. This status is initially `starting`. Whenever a health check passes, it becomes `healthy` (whatever state it was previously in). After a certain number of consecutive failures, it becomes `unhealthy`. See for more information. +Stable Tags are composed of: + * CRS version, in the fromat `[.[.-[-]-`. +Examples: + * `3-nginx-202401121309` + * `3.3-apache-alpine-202401121309` + * `3.3.5-openresty-alpine-fat-202401121309` -We also build [alpine linux](https://www.alpinelinux.org/) variants of the base images, using the `-alpine` suffix. Examples: +### Rolling Tags -* `3-nginx-alpine-YYYYMMDDHHMM`, `3.3-nginx-alpine-YYYYMMDDHHMM`, `3.3.5-nginx-alpine-YYYYMMDDHHMM`, `nginx-alpine` ([master/nginx/Dockerfile-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile-alpine) – *last stable ModSecurity v3 on Nginx 1.25.3 official alpine stable base image, and latest stable Core Rule Set 3.3.5* -* `3-apache-alpine-YYYYMMDDHHMM`, `3.3-apache-alpine-YYYYMMDDHHMM`, `3.3.5-apache-alpine-YYYYMMDDHHMM`, `apache-alpine` ([master/apache/Dockerfile-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile-alpine)) – *last stable ModSecurity v2 on Apache 2.4.58 official alpine stable base image, and latest stable Core Rule Set 3.3.5* +Rolling tags are updated whenever a new stable tag release occurs. Rolling tags can be practical but should not be used in production. -## Production usage +Rolling Tags are composed of: + * web server variant + * OS variant (optional) -⚠️ We changed tags to [support production usage](https://github.com/coreruleset/modsecurity-crs-docker/issues/67). Now, if you want to use the "rolling version", use tags `owasp/modsecurity-crs:nginx` or `owasp/modsecurity-crs:apache`, or if you want the alpine variant use `owasp/modsecurity-crs:nginx-alpine` or `owasp/modsecurity-crs:apache-alpine`. If you need a stable long term image, use the one with the full CRS version, the variant used (if any), and the build date in `YYYYMMDDHHMM` format, example `owasp/modsecurity-crs:3.3.5-nginx-202209141209` or `owasp/modsecurity-crs:3.3.5-apache-alpine-202209141209` for example. You have been warned. +The stable tag format is `[-]`. +Examples: + * `nginx` + * `apache-alpine` + * `openresty-alpine-fat` + +## OS Variants + +* nginx – *latest stable ModSecurity v3 on Nginx 1.25.3 official stable base image, and latest stable Core Rule Set 3.3.5* + * [nginx](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile) + * [nginx-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile-alpine) +* Openresty - *last stable ModSecurity v3 on Nginx 1.25.3 official stable base image, and latest stable Core Rule Set 3.3.5* + * [openresty-alpine-fat](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/openresty/Dockerfile-alpine) +* Apache httpd – *last stable ModSecurity v2 on Apache 2.4.58 official stable base image, and latest stable Core Rule Set 3.3.5* + * [apache](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile) + * [apache-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile-alpine) + +### Notes regarding Openresty version of this image + +We currently only provide a version of the Openresty image based on **Alpine Linux**. The Dockerfile for Openresty resides in the [docker-openresty repository](https://github.com/openresty/docker-openresty/blob/master/alpine/Dockerfile.fat). ## Supported architectures @@ -40,6 +67,17 @@ We also build [alpine linux](https://www.alpinelinux.org/) variants of the base * linux/arm64/v8 * linux/i386 +### Notes regarding Openresty version of the image + +Openresty image builds currently support only these architectures: + +* linux/amd64 +* linux/arm64 + +## Container Health Checks + +🆕 We add healthchecks to the images, so that containers return HTTP status code 200 from the `/healthz` endpoint. When a container has a healthcheck specified, it has a _health status_ in addition to its normal status. This status is initially `starting`. Whenever a health check passes, it becomes `healthy` (whatever state it was previously in). After a certain number of consecutive failures, it becomes `unhealthy`. See for more information. + ## Quick reference * **Where to get help**: the [Core Rule Set Slack Channel](https://owasp.org/slack/invite) (#coreruleset on owasp.slack.com), or [Stack Overflow](https://stackoverflow.com/questions/tagged/mod-security) diff --git a/README.md b/README.md index 4cf701f1..98b21ccb 100644 --- a/README.md +++ b/README.md @@ -12,38 +12,63 @@ The Core Rule Set (CRS) is a set of generic attack detection rules for use with ModSecurity or compatible web application firewalls. ModSecurity is an open source, cross platform web application firewall (WAF) engine for Apache, IIS and Nginx. -## Supported tags and respective `Dockerfile` links +## Supported Tags -* `3-nginx-YYYYMMDDHHMM`, `3.3-nginx-YYYYMMDDHHMM`, `3.3.5-nginx-YYYYMMDDHHMM`, `nginx` ([master/nginx/Dockerfile](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile)) – *last stable ModSecurity v3 on Nginx 1.25.3 official stable base image, and latest stable Core Rule Set 3.3.5* -* `3-apache-YYYYMMDDHHMM`, `3.3-apache-YYYYMMDDHHMM`, `3.3.5-apache-YYYYMMDDHHMM`, `apache` ([master/apache/Dockerfile](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile)) –*last stable ModSecurity v2 on Apache 2.4.58 official stable base image, and latest stable Core Rule Set 3.3.5* +### Stable Tags -⚠️ We changed tags to [support production usage](https://github.com/coreruleset/modsecurity-crs-docker/issues/67). Now, if you want to use the "rolling version", use the tag `owasp/modsecurity-crs:nginx` or `owasp/modsecurity-crs:apache`. If you need a stable long term image, use the one with the full CRS version, in addition to the build date in `YYYYMMDDHHMM` format, example `owasp/modsecurity-crs:3.3.5-nginx-202209141209` or `owasp/modsecurity-crs:3.3.5-apache-202209141209` for example. You have been warned. +Stable Tags are composed of: + * CRS version, in the fromat `[.[. for more information. +The stable tag format is `-[-]-`. +Examples: + * `3-nginx-202401121309` + * `3.3-apache-alpine-202401121309` + * `3.3.5-openresty-alpine-fat-202401121309` -## Supported variants +### Rolling Tags -We also build [alpine linux](https://www.alpinelinux.org/) variants of the base images, using the `-alpine` suffix. Examples: +Rolling tags are updated whenever a new stable tag release occurs. Rolling tags can be practical but should not be used in production. -* `3-nginx-alpine-YYYYMMDDHHMM`, `3.3-nginx-alpine-YYYYMMDDHHMM`, `3.3.5-nginx-alpine-YYYYMMDDHHMM`, `nginx-alpine` ([master/nginx/Dockerfile-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile-alpine) – *last stable ModSecurity v3 on Nginx 1.25.3 official alpine stable base image, and latest stable Core Rule Set 3.3.5* -* `3-apache-alpine-YYYYMMDDHHMM`, `3.3-apache-alpine-YYYYMMDDHHMM`, `3.3.5-apache-alpine-YYYYMMDDHHMM`, `apache-alpine` ([master/apache/Dockerfile-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile-alpine)) – *last stable ModSecurity v2 on Apache 2.4.58 official alpine stable base image, and latest stable Core Rule Set 3.3.5* +Rolling Tags are composed of: + * web server variant + * OS variant (optional) -⚠️ We changed tags to [support production usage](https://github.com/coreruleset/modsecurity-crs-docker/issues/67). Now, if you want to use the "rolling version", use the tag `owasp/modsecurity-crs:nginx-alpine` or `owasp/modsecurity-crs:apache-alpine` or `owasp/modsecurity-crs:openresty-alpine-fat`. If you need a stable long term image, use the one with the full CRS version, in addition to the build date in `YYYYMMDDHHMM` format (e.g., `owasp/modsecurity-crs:3.3.5-nginx-alpine-202209141209`). +The stable tag format is `[-]`. +Examples: + * `nginx` + * `apache-alpine` + * `openresty-alpine-fat` -### Notes regarding Openresty version of this image. +## OS Variants + +* nginx – *latest stable ModSecurity v3 on Nginx 1.25.3 official stable base image, and latest stable Core Rule Set 3.3.5* + * [nginx](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile) + * [nginx-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/nginx/Dockerfile-alpine) +* Openresty - *last stable ModSecurity v3 on Nginx 1.25.3 official stable base image, and latest stable Core Rule Set 3.3.5* + * [openresty-alpine-fat](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/openresty/Dockerfile-alpine) +* Apache httpd – *last stable ModSecurity v2 on Apache 2.4.58 official stable base image, and latest stable Core Rule Set 3.3.5* + * [apache](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile) + * [apache-alpine](https://github.com/coreruleset/modsecurity-crs-docker/blob/master/apache/Dockerfile-alpine) + +### Notes regarding Openresty version of this image We currently only provide a version of the Openresty image based on **Alpine Linux**. The Dockerfile for Openresty resides in the [docker-openresty repository](https://github.com/openresty/docker-openresty/blob/master/alpine/Dockerfile.fat). ## Supported architectures -We added the [docker buildx](https://github.com/docker/buildx) support to our docker builds so additional architectures are supported now. As we create our containers based on the official Apache httpd, nginx and Openresty ones, we can only support the architectures they support. +Our builds are based on the official Apache httpd, nginx and Openresty images, which means we can only support the architectures they support. -There is a new file `docker-bake.hcl` used for this purpose. To build for new platforms, just use this example: +We currently provide images for the following architectures: -```bash -docker buildx create --use --platform linux/amd64,linux/i386,linux/arm64,linux/arm/v7 -docker buildx bake -f docker-bake.hcl -``` +* linux/amd64 +* linux/arm/v7 +* linux/arm64/v8 +* linux/i386 + +### Building We require a version of `buildx` >= v0.9.1. [Visit the official documentation](https://docs.docker.com/build/architecture/#install-buildx) for instructions on installing and upgrading `buildx`. You can check which version you have using: @@ -58,15 +83,12 @@ If you want to see the targets of the build, use: docker buildx bake -f ./docker-bake.hcl --print ``` -We are building now for these architectures: +To build for any platforms of your choosing, just use this example: -* linux/amd64 -* linux/arm/v7 -* linux/arm64/v8 -* linux/i386 - -You can find additional examples on how to use `buildx` in this repository's GitHub act -We added the [docker buildx](https://github.com/docker/buildx) support to our docker builds so additional architectures are supported now. As we create our containers based on the official apache and nginx ones, we can only support the architectures they support. +```bash +docker buildx create --use --platform linux/amd64,linux/i386,linux/arm64,linux/arm/v7 +docker buildx bake -f docker-bake.hcl +``` To build a specific target for a single platform only (replace target and platform strings in the example with the your choices): @@ -74,13 +96,17 @@ To build a specific target for a single platform only (replace target and platfo docker buildx bake -f docker-bake.hcl --set "*.platform=linux/amd64" nginx-alpine ``` -### Notes regarding Openresty version of the image. +### Notes regarding Openresty version of the image Openresty image builds currently support only these architectures: * linux/amd64 * linux/arm64 +## Container Health Checks + +🆕 We add healthchecks to the images, so that containers return HTTP status code 200 from the `/healthz` endpoint. When a container has a healthcheck specified, it has a _health status_ in addition to its normal status. This status is initially `starting`. Whenever a health check passes, it becomes `healthy` (whatever state it was previously in). After a certain number of consecutive failures, it becomes `unhealthy`. See for more information. + ## CRS Versions > Hey, I used some specific git version with the containers? What happened? From 5dc9598484059491c18fa61c9659c1d5850e0b61 Mon Sep 17 00:00:00 2001 From: Max Leske Date: Sun, 28 Jan 2024 12:12:34 +0100 Subject: [PATCH 6/6] feat: use nginx-unprivileged images Use unprivileged images and always run images as non-root. Fixes #55 --- apache/Dockerfile | 4 +-- apache/Dockerfile-alpine | 4 +-- nginx/Dockerfile | 42 ++++++++++++++++++----------- nginx/Dockerfile-alpine | 40 +++++++++++++++++---------- nginx/templates/nginx.conf.template | 2 +- 5 files changed, 58 insertions(+), 34 deletions(-) diff --git a/apache/Dockerfile b/apache/Dockerfile index fffc66cd..1aa1d9eb 100644 --- a/apache/Dockerfile +++ b/apache/Dockerfile @@ -58,8 +58,8 @@ RUN set -eux; \ FROM httpd:${HTTPD_VERSION} -ARG MODSEC2_VERSION="n/a" -ARG LUA_VERSION="n/a" +ARG MODSEC2_VERSION +ARG LUA_VERSION LABEL maintainer="Felipe Zipitria " diff --git a/apache/Dockerfile-alpine b/apache/Dockerfile-alpine index c2f629a4..d5628211 100644 --- a/apache/Dockerfile-alpine +++ b/apache/Dockerfile-alpine @@ -68,8 +68,8 @@ RUN set -eux; \ FROM httpd:${HTTPD_VERSION}-alpine -ARG MODSEC2_VERSION="n/a" -ARG LUA_VERSION="n/a" +ARG MODSEC2_VERSION +ARG LUA_VERSION LABEL maintainer="Felipe Zipitria " diff --git a/nginx/Dockerfile b/nginx/Dockerfile index 6dd44990..117ceeb3 100644 --- a/nginx/Dockerfile +++ b/nginx/Dockerfile @@ -1,11 +1,13 @@ ARG NGINX_VERSION="n/a" -FROM nginx:${NGINX_VERSION} as build +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} as build ARG MODSEC3_VERSION="n/a" ARG LMDB_VERSION="n/a" ARG LUA_VERSION="n/a" +USER root + # Note: libpcre3-dev (PCRE 1) is required by the build description, # even though the build will use PCRE2. RUN set -eux; \ @@ -74,10 +76,12 @@ RUN set -eux; \ curl -sSL https://ssl-config.mozilla.org/ffdhe2048.txt -o /usr/share/TLS/dhparam-2048.pem; \ curl -sSL https://ssl-config.mozilla.org/ffdhe4096.txt -o /usr/share/TLS/dhparam-4096.pem -FROM nginx:${NGINX_VERSION} as crs_release +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} as crs_release ARG CRS_RELEASE +USER root + # hadolint ignore=DL3008,SC2016 RUN set -eux; \ apt-get update; \ @@ -86,7 +90,13 @@ RUN set -eux; \ curl \ gnupg; \ mkdir /opt/owasp-crs; \ - curl -SL https://github.com/coreruleset/coreruleset/archive/v${CRS_RELEASE}.tar.gz -o v${CRS_RELEASE}.tar.gz; \ + chown nginx:nginx /opt/owasp-crs + +USER nginx + +WORKDIR /sources + +RUN curl -SL https://github.com/coreruleset/coreruleset/archive/v${CRS_RELEASE}.tar.gz -o v${CRS_RELEASE}.tar.gz; \ curl -SL https://github.com/coreruleset/coreruleset/releases/download/v${CRS_RELEASE}/coreruleset-${CRS_RELEASE}.tar.gz.asc -o coreruleset-${CRS_RELEASE}.tar.gz.asc; \ gpg --fetch-key https://coreruleset.org/security.asc; \ gpg --verify coreruleset-${CRS_RELEASE}.tar.gz.asc v${CRS_RELEASE}.tar.gz; \ @@ -94,11 +104,11 @@ RUN set -eux; \ rm -f v${CRS_RELEASE}.tar.gz coreruleset-${CRS_RELEASE}.tar.gz.asc; \ mv -v /opt/owasp-crs/crs-setup.conf.example /opt/owasp-crs/crs-setup.conf -FROM nginx:${NGINX_VERSION} +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION} -ARG MODSEC3_VERSION="n/a" -ARG LMDB_VERSION="n/a" -ARG LUA_VERSION="n/a" +ARG MODSEC3_VERSION +ARG LMDB_VERSION +ARG LUA_VERSION LABEL maintainer="Felipe Zipitria " @@ -182,6 +192,8 @@ COPY src/opt/modsecurity/activate-rules.sh /docker-entrypoint.d/95-activate-rule COPY nginx/templates /etc/nginx/templates/ COPY src/bin/* /usr/local/bin/ +USER root + RUN set -eux; \ echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections; \ apt-get update -qq; \ @@ -197,18 +209,18 @@ RUN set -eux; \ rm -rf /var/lib/apt/lists/*; \ apt-get clean; \ mkdir /etc/nginx/ssl; \ - mkdir -p /tmp/modsecurity/data; \ - mkdir -p /tmp/modsecurity/upload; \ - mkdir -p /tmp/modsecurity/tmp; \ - mkdir -p /usr/local/modsecurity; \ - chown -R nginx:nginx /tmp/modsecurity; \ # Comment out the SecDisableBackendCompression option since it is not supported in V3 sed -i 's/^\(SecDisableBackendCompression .*\)/# \1/' /etc/nginx/templates/modsecurity.d/modsecurity-override.conf.template; \ ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ - chgrp -R 0 /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/; \ - chmod -R g=u /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/; \ - ln -sv /opt/owasp-crs /etc/modsecurity.d/ + ln -sv /opt/owasp-crs /etc/modsecurity.d/; \ + chown nginx:nginx /opt/owasp-crs /etc/modsecurity.d + +USER nginx + +RUN mkdir -p /tmp/modsecurity/data; \ + mkdir -p /tmp/modsecurity/upload; \ + mkdir -p /tmp/modsecurity/tmp HEALTHCHECK CMD /usr/local/bin/healthcheck diff --git a/nginx/Dockerfile-alpine b/nginx/Dockerfile-alpine index c388b831..9bd6dc94 100644 --- a/nginx/Dockerfile-alpine +++ b/nginx/Dockerfile-alpine @@ -1,10 +1,12 @@ ARG NGINX_VERSION="n/a" -FROM nginx:${NGINX_VERSION}-alpine as build +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION}-alpine as build ARG MODSEC3_VERSION="n/a" ARG LUA_VERSION="n/a" +USER root + # Note: pcre-dev (PCRE 1) is required by the build description, # even though the build will use PCRE2. RUN set -eux; \ @@ -71,10 +73,12 @@ RUN set -eux; \ curl -sSL https://ssl-config.mozilla.org/ffdhe2048.txt -o /usr/share/TLS/dhparam-2048.pem; \ curl -sSL https://ssl-config.mozilla.org/ffdhe4096.txt -o /usr/share/TLS/dhparam-4096.pem -FROM nginx:${NGINX_VERSION}-alpine as crs_release +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION}-alpine as crs_release ARG CRS_RELEASE +USER root + # hadolint ignore=DL3008,SC2016 RUN set -eux; \ apk add --no-cache \ @@ -82,7 +86,13 @@ RUN set -eux; \ curl \ gnupg; \ mkdir /opt/owasp-crs; \ - curl -SL https://github.com/coreruleset/coreruleset/archive/v${CRS_RELEASE}.tar.gz -o v${CRS_RELEASE}.tar.gz; \ + chown nginx:nginx /opt/owasp-crs + +USER nginx + +WORKDIR /sources + +RUN curl -SL https://github.com/coreruleset/coreruleset/archive/v${CRS_RELEASE}.tar.gz -o v${CRS_RELEASE}.tar.gz; \ curl -SL https://github.com/coreruleset/coreruleset/releases/download/v${CRS_RELEASE}/coreruleset-${CRS_RELEASE}.tar.gz.asc -o coreruleset-${CRS_RELEASE}.tar.gz.asc; \ gpg --fetch-key https://coreruleset.org/security.asc; \ gpg --verify coreruleset-${CRS_RELEASE}.tar.gz.asc v${CRS_RELEASE}.tar.gz; \ @@ -90,7 +100,7 @@ RUN set -eux; \ rm -f v${CRS_RELEASE}.tar.gz coreruleset-${CRS_RELEASE}.tar.gz.asc; \ mv -v /opt/owasp-crs/crs-setup.conf.example /opt/owasp-crs/crs-setup.conf -FROM nginx:${NGINX_VERSION}-alpine +FROM nginxinc/nginx-unprivileged:${NGINX_VERSION}-alpine ARG MODSEC3_VERSION ARG LUA_VERSION @@ -167,15 +177,16 @@ COPY --from=build /usr/share/TLS/dhparam-* /etc/ssl/certs/ COPY --from=build /etc/modsecurity.d/unicode.mapping /etc/modsecurity.d/unicode.mapping COPY --from=build /etc/modsecurity.d/modsecurity.conf /etc/modsecurity.d/modsecurity.conf COPY --from=crs_release /opt/owasp-crs /opt/owasp-crs -# We use the templating mechanism from the nginx image here. -COPY nginx/templates /etc/nginx/templates/ COPY src/etc/modsecurity.d/modsecurity-override.conf /etc/nginx/templates/modsecurity.d/modsecurity-override.conf.template COPY src/etc/modsecurity.d/setup.conf /etc/nginx/templates/modsecurity.d/setup.conf.template -COPY src/bin/* /usr/local/bin/ COPY nginx/docker-entrypoint.d/*.sh /docker-entrypoint.d/ COPY src/opt/modsecurity/activate-plugins.sh /docker-entrypoint.d/94-activate-plugins.sh COPY src/opt/modsecurity/activate-rules.sh /docker-entrypoint.d/95-activate-rules.sh +# We use the templating mechanism from the nginx image here. +COPY nginx/templates /etc/nginx/templates/ +COPY src/bin/* /usr/local/bin/ +USER root RUN set -eux; \ apk add --no-cache \ @@ -195,19 +206,20 @@ RUN set -eux; \ # Alpine needs GNU 'sed' because the 'sed' program shipped with busybox does not support 'z' parameter for separating lines with a 'NUL' character. sed \ yajl; \ - mkdir /etc/nginx/ssl/; \ - mkdir -p /tmp/modsecurity/data; \ - mkdir -p /tmp/modsecurity/upload; \ - mkdir -p /tmp/modsecurity/tmp; \ - chown -R nginx:nginx /usr/share/nginx /tmp/modsecurity; \ + mkdir /etc/nginx/ssl; \ # Comment out the SecDisableBackendCompression option since it is not supported in V3 sed -i 's/^\(SecDisableBackendCompression .*\)/# \1/' /etc/nginx/templates/modsecurity.d/modsecurity-override.conf.template; \ ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3.0; \ ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so.3; \ ln -s /usr/local/modsecurity/lib/libmodsecurity.so.${MODSEC3_VERSION} /usr/local/modsecurity/lib/libmodsecurity.so; \ ln -sv /opt/owasp-crs /etc/modsecurity.d/; \ - chgrp -R 0 /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/; \ - chmod -R g=u /var/cache/nginx/ /var/log/ /var/run/ /usr/share/nginx/ /etc/nginx/ /etc/modsecurity.d/ + chown nginx:nginx /opt/owasp-crs /etc/modsecurity.d + +USER nginx + +RUN mkdir -p /tmp/modsecurity/data; \ + mkdir -p /tmp/modsecurity/upload; \ + mkdir -p /tmp/modsecurity/tmp WORKDIR /usr/share/nginx/html diff --git a/nginx/templates/nginx.conf.template b/nginx/templates/nginx.conf.template index 08acd62a..07266bdf 100644 --- a/nginx/templates/nginx.conf.template +++ b/nginx/templates/nginx.conf.template @@ -1,7 +1,7 @@ load_module modules/ngx_http_modsecurity_module.so; worker_processes auto; -pid /var/run/nginx.pid; +pid /tmp/nginx.pid; events { worker_connections ${WORKER_CONNECTIONS};