From b10178f0f7adc5dc5df083ca757f5aa212ffb1ff Mon Sep 17 00:00:00 2001 From: Manuel Caballero Date: Tue, 25 Oct 2022 13:48:10 +0200 Subject: [PATCH] Initial config modsecurity --- dd-ctl | 2 + dd-sso/docker-compose-parts/haproxy.yml | 14 +- .../auto-generate-certs.sh | 0 dd-sso/docker/certbot/docker-entrypoint.sh | 45 +++++ .../letsencrypt-hook-deploy-concatenante.sh | 0 .../letsencrypt-renew-cron.sh | 0 .../{haproxy => certbot}/letsencrypt.sh | 0 dd-sso/docker/haproxy/Dockerfile | 8 +- dd-sso/docker/haproxy/docker-entrypoint.sh | 6 - dd-sso/docker/haproxy/haproxy.conf | 2 +- .../haproxy/haproxy.proxy-protocol.conf | 2 +- dd-waf/docker-compose-parts/haproxy.yml | 34 ++++ dd-waf/docker-compose-parts/modsecurity.yml | 13 ++ dd-waf/docker/haproxy/Dockerfile | 37 ++++ dd-waf/docker/haproxy/auto-generate-certs.sh | 50 +++++ dd-waf/docker/haproxy/docker-entrypoint.sh | 45 +++++ dd-waf/docker/haproxy/haproxy.conf | 83 ++++++++ .../haproxy/haproxy.proxy-protocol.conf | 182 ++++++++++++++++++ .../letsencrypt-hook-deploy-concatenante.sh | 23 +++ .../docker/haproxy/letsencrypt-renew-cron.sh | 21 ++ dd-waf/docker/haproxy/letsencrypt.sh | 50 +++++ dd-waf/docker/modsecurity/000-default.conf | 14 ++ dd-waf/docker/modsecurity/Dockerfile | 59 ++++++ .../letsencrypt-hook-deploy-concatenante.sh | 23 +++ .../modsecurity/letsencrypt-renew-cron.sh | 21 ++ dd-waf/docker/modsecurity/letsencrypt.sh | 50 +++++ dd-waf/docker/modsecurity/modsec_rules.conf | 3 + 27 files changed, 766 insertions(+), 21 deletions(-) rename dd-sso/docker/{haproxy => certbot}/auto-generate-certs.sh (100%) create mode 100644 dd-sso/docker/certbot/docker-entrypoint.sh rename dd-sso/docker/{haproxy => certbot}/letsencrypt-hook-deploy-concatenante.sh (100%) rename dd-sso/docker/{haproxy => certbot}/letsencrypt-renew-cron.sh (100%) rename dd-sso/docker/{haproxy => certbot}/letsencrypt.sh (100%) create mode 100644 dd-waf/docker-compose-parts/haproxy.yml create mode 100644 dd-waf/docker-compose-parts/modsecurity.yml create mode 100644 dd-waf/docker/haproxy/Dockerfile create mode 100755 dd-waf/docker/haproxy/auto-generate-certs.sh create mode 100644 dd-waf/docker/haproxy/docker-entrypoint.sh create mode 100644 dd-waf/docker/haproxy/haproxy.conf create mode 100644 dd-waf/docker/haproxy/haproxy.proxy-protocol.conf create mode 100755 dd-waf/docker/haproxy/letsencrypt-hook-deploy-concatenante.sh create mode 100755 dd-waf/docker/haproxy/letsencrypt-renew-cron.sh create mode 100755 dd-waf/docker/haproxy/letsencrypt.sh create mode 100644 dd-waf/docker/modsecurity/000-default.conf create mode 100644 dd-waf/docker/modsecurity/Dockerfile create mode 100755 dd-waf/docker/modsecurity/letsencrypt-hook-deploy-concatenante.sh create mode 100755 dd-waf/docker/modsecurity/letsencrypt-renew-cron.sh create mode 100755 dd-waf/docker/modsecurity/letsencrypt.sh create mode 100644 dd-waf/docker/modsecurity/modsec_rules.conf diff --git a/dd-ctl b/dd-ctl index 8244ffb..f392ccc 100755 --- a/dd-ctl +++ b/dd-ctl @@ -207,6 +207,8 @@ build_compose(){ # Build compose ymls docker-compose -f dd-sso/docker-compose-parts/$BEHIND \ + -f dd-waf/docker-compose-parts/haproxy.yml \ + -f dd-waf/docker-compose-parts/modsecurity.yml \ -f dd-sso/docker-compose-parts/api.yml \ -f dd-sso/docker-compose-parts/keycloak.yml \ -f dd-sso/docker-compose-parts/avatars.yml \ diff --git a/dd-sso/docker-compose-parts/haproxy.yml b/dd-sso/docker-compose-parts/haproxy.yml index 24452b5..d33d204 100644 --- a/dd-sso/docker-compose-parts/haproxy.yml +++ b/dd-sso/docker-compose-parts/haproxy.yml @@ -20,6 +20,8 @@ version: '3.7' services: dd-sso-haproxy: + depends_on: + - dd-waf-haproxy build: args: HAPROXY_IMG: ${HAPROXY_IMG-haproxy:2.4.12-alpine3.15} @@ -35,15 +37,15 @@ services: networks: - dd_net ports: - - published: 80 + - published: 8088 target: 80 - - published: 443 + - published: 8443 target: 443 # These are for cases when operators want to use PROXY protocol in front - - published: 8888 - target: 8888 - - published: 591 - target: 591 +# - published: 8888 +# target: 8888 +# - published: 591 +# target: 591 env_file: - .env logging: diff --git a/dd-sso/docker/haproxy/auto-generate-certs.sh b/dd-sso/docker/certbot/auto-generate-certs.sh similarity index 100% rename from dd-sso/docker/haproxy/auto-generate-certs.sh rename to dd-sso/docker/certbot/auto-generate-certs.sh diff --git a/dd-sso/docker/certbot/docker-entrypoint.sh b/dd-sso/docker/certbot/docker-entrypoint.sh new file mode 100644 index 0000000..ade9bce --- /dev/null +++ b/dd-sso/docker/certbot/docker-entrypoint.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# Copyright © 2022 Evilham +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +set -e + +ln -sf /usr/local/etc/haproxy/${HAPROXY_CFG:-haproxy.normal.cfg} /usr/local/etc/haproxy/haproxy.cfg + +LETSENCRYPT_DOMAIN="$DOMAIN" letsencrypt.sh + +if [ ! -e "/certs/chain.pem" ]; then + auto-generate-certs.sh +fi + +# first arg is `-f` or `--some-option` +if [ "${1#-}" != "$1" ]; then + set -- haproxy "$@" +fi + +if [ "$1" = 'haproxy' ]; then + shift # "haproxy" + # if the user wants "haproxy", let's add a couple useful flags + # -W -- "master-worker mode" (similar to the old "haproxy-systemd-wrapper"; allows for reload via "SIGUSR2") + # -db -- disables background mode + set -- haproxy -W -db "$@" +fi + +exec "$@" diff --git a/dd-sso/docker/haproxy/letsencrypt-hook-deploy-concatenante.sh b/dd-sso/docker/certbot/letsencrypt-hook-deploy-concatenante.sh similarity index 100% rename from dd-sso/docker/haproxy/letsencrypt-hook-deploy-concatenante.sh rename to dd-sso/docker/certbot/letsencrypt-hook-deploy-concatenante.sh diff --git a/dd-sso/docker/haproxy/letsencrypt-renew-cron.sh b/dd-sso/docker/certbot/letsencrypt-renew-cron.sh similarity index 100% rename from dd-sso/docker/haproxy/letsencrypt-renew-cron.sh rename to dd-sso/docker/certbot/letsencrypt-renew-cron.sh diff --git a/dd-sso/docker/haproxy/letsencrypt.sh b/dd-sso/docker/certbot/letsencrypt.sh similarity index 100% rename from dd-sso/docker/haproxy/letsencrypt.sh rename to dd-sso/docker/certbot/letsencrypt.sh diff --git a/dd-sso/docker/haproxy/Dockerfile b/dd-sso/docker/haproxy/Dockerfile index e8fdf86..0f852f1 100644 --- a/dd-sso/docker/haproxy/Dockerfile +++ b/dd-sso/docker/haproxy/Dockerfile @@ -21,13 +21,7 @@ ARG HAPROXY_IMG FROM $HAPROXY_IMG as production USER root -RUN apk add openssl certbot py-pip -RUN pip install certbot-plugin-gandi - -COPY letsencrypt-hook-deploy-concatenante.sh /usr/local/sbin/ -COPY letsencrypt.sh /usr/local/sbin/ -COPY letsencrypt-renew-cron.sh /etc/periodic/daily/letsencrypt-renew -COPY auto-generate-certs.sh /usr/local/sbin/ +RUN apk add openssl py-pip COPY docker-entrypoint.sh /usr/local/bin/ RUN ln -s /usr/local/bin/docker-entrypoint.sh / diff --git a/dd-sso/docker/haproxy/docker-entrypoint.sh b/dd-sso/docker/haproxy/docker-entrypoint.sh index ade9bce..2a83c0d 100644 --- a/dd-sso/docker/haproxy/docker-entrypoint.sh +++ b/dd-sso/docker/haproxy/docker-entrypoint.sh @@ -23,12 +23,6 @@ set -e ln -sf /usr/local/etc/haproxy/${HAPROXY_CFG:-haproxy.normal.cfg} /usr/local/etc/haproxy/haproxy.cfg -LETSENCRYPT_DOMAIN="$DOMAIN" letsencrypt.sh - -if [ ! -e "/certs/chain.pem" ]; then - auto-generate-certs.sh -fi - # first arg is `-f` or `--some-option` if [ "${1#-}" != "$1" ]; then set -- haproxy "$@" diff --git a/dd-sso/docker/haproxy/haproxy.conf b/dd-sso/docker/haproxy/haproxy.conf index 4f11c19..42446c2 100644 --- a/dd-sso/docker/haproxy/haproxy.conf +++ b/dd-sso/docker/haproxy/haproxy.conf @@ -48,7 +48,7 @@ global frontend website mode http bind :80 - redirect scheme https if !{ env(BEHIND_PROXY) -m str true } !{ ssl_fc } + #redirect scheme https if !{ env(BEHIND_PROXY) -m str true } !{ ssl_fc } http-request del-header ssl_client_cert unless { ssl_fc_has_crt } http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\ if { ssl_fc_has_crt } bind :443 ssl crt /certs/chain.pem diff --git a/dd-sso/docker/haproxy/haproxy.proxy-protocol.conf b/dd-sso/docker/haproxy/haproxy.proxy-protocol.conf index e433219..7892b79 100644 --- a/dd-sso/docker/haproxy/haproxy.proxy-protocol.conf +++ b/dd-sso/docker/haproxy/haproxy.proxy-protocol.conf @@ -50,7 +50,7 @@ frontend website mode http bind :80 bind :8888 accept-proxy - redirect scheme https if !{ env(BEHIND_PROXY) -m str true } !{ ssl_fc } + #redirect scheme https if !{ env(BEHIND_PROXY) -m str true } !{ ssl_fc } http-request del-header ssl_client_cert unless { ssl_fc_has_crt } http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\ if { ssl_fc_has_crt } bind :443 ssl crt /certs/chain.pem diff --git a/dd-waf/docker-compose-parts/haproxy.yml b/dd-waf/docker-compose-parts/haproxy.yml new file mode 100644 index 0000000..7b3fa2f --- /dev/null +++ b/dd-waf/docker-compose-parts/haproxy.yml @@ -0,0 +1,34 @@ +version: '3.7' +services: + dd-waf-haproxy: + build: + args: + HAPROXY_IMG: ${HAPROXY_IMG-haproxy:2.4.12-alpine3.15} + context: ${BUILD_SSO_ROOT_PATH}/docker/haproxy-waf + dockerfile: Dockerfile + target: production + container_name: dd-waf-haproxy + restart: unless-stopped + volumes: + - /etc/localtime:/etc/localtime:ro + - ${SRC_FOLDER}/haproxy/letsencrypt:/etc/letsencrypt:rw + - ${SRC_FOLDER}/haproxy/certs:/certs:rw + networks: + - dd_net + ports: + - published: 80 + target: 80 + - published: 443 + target: 443 + # These are for cases when operators want to use PROXY protocol in front + - published: 8888 + target: 8888 + - published: 591 + target: 591 + env_file: + - .env + logging: + driver: "json-file" + options: + max-size: "5m" + max-file: "10" \ No newline at end of file diff --git a/dd-waf/docker-compose-parts/modsecurity.yml b/dd-waf/docker-compose-parts/modsecurity.yml new file mode 100644 index 0000000..1b9da12 --- /dev/null +++ b/dd-waf/docker-compose-parts/modsecurity.yml @@ -0,0 +1,13 @@ +version: '3.7' +services: + dd-waf-apache: + build: + context: ${BUILD_SSO_ROOT_PATH}/docker/modsecurity + dockerfile: Dockerfile + target: production + container_name: dd-waf-apache + restart: unless-stopped + volumes: + - /etc/localtime:/etc/localtime:ro + networks: + - dd_net \ No newline at end of file diff --git a/dd-waf/docker/haproxy/Dockerfile b/dd-waf/docker/haproxy/Dockerfile new file mode 100644 index 0000000..e8fdf86 --- /dev/null +++ b/dd-waf/docker/haproxy/Dockerfile @@ -0,0 +1,37 @@ +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +ARG HAPROXY_IMG +FROM $HAPROXY_IMG as production + +USER root +RUN apk add openssl certbot py-pip +RUN pip install certbot-plugin-gandi + +COPY letsencrypt-hook-deploy-concatenante.sh /usr/local/sbin/ +COPY letsencrypt.sh /usr/local/sbin/ +COPY letsencrypt-renew-cron.sh /etc/periodic/daily/letsencrypt-renew +COPY auto-generate-certs.sh /usr/local/sbin/ + +COPY docker-entrypoint.sh /usr/local/bin/ +RUN ln -s /usr/local/bin/docker-entrypoint.sh / +RUN chmod 775 docker-entrypoint.sh + +ADD haproxy.conf /usr/local/etc/haproxy/haproxy.normal.cfg +ADD haproxy.proxy-protocol.conf /usr/local/etc/haproxy/haproxy.proxy-protocol.cfg diff --git a/dd-waf/docker/haproxy/auto-generate-certs.sh b/dd-waf/docker/haproxy/auto-generate-certs.sh new file mode 100755 index 0000000..5d9a10a --- /dev/null +++ b/dd-waf/docker/haproxy/auto-generate-certs.sh @@ -0,0 +1,50 @@ +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +cd /certs + +# Self signed cert generic data +C=CA +L=Barcelona +O=localdomain +CN_CA=$O +CN_HOST=*.$O +OU=$O + +echo '#### Creating 2048-bit RSA key:' +openssl genrsa -out ca-key.pem 2048 + +echo '#### Using the key to create a self-signed certificate to your CA:' +openssl req -new -x509 -days 9999 -key ca-key.pem -out ca-cert.pem -sha256 \ + -subj "/C=$C/L=$L/O=$O/CN=$CN_CA" + +echo '#### Creating server certificate:' +openssl genrsa -out server-key.pem 2048 + +echo '#### Creating a certificate signing request for the server:' +openssl req -new -key server-key.pem -sha256 -out server-key.csr \ + -subj "/CN=$CN_HOST" + +echo '#### Creating server certificate:' +RND=$(( ( RANDOM % 1000 ) + 1 )) +openssl x509 -req -days 9999 -in server-key.csr -CA ca-cert.pem -CAkey ca-key.pem \ + -set_serial $RND -sha256 -out server-cert.pem + +echo '#### Concatenate certs for haprox' +cat server-cert.pem server-key.pem > chain.pem diff --git a/dd-waf/docker/haproxy/docker-entrypoint.sh b/dd-waf/docker/haproxy/docker-entrypoint.sh new file mode 100644 index 0000000..ade9bce --- /dev/null +++ b/dd-waf/docker/haproxy/docker-entrypoint.sh @@ -0,0 +1,45 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# Copyright © 2022 Evilham +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +set -e + +ln -sf /usr/local/etc/haproxy/${HAPROXY_CFG:-haproxy.normal.cfg} /usr/local/etc/haproxy/haproxy.cfg + +LETSENCRYPT_DOMAIN="$DOMAIN" letsencrypt.sh + +if [ ! -e "/certs/chain.pem" ]; then + auto-generate-certs.sh +fi + +# first arg is `-f` or `--some-option` +if [ "${1#-}" != "$1" ]; then + set -- haproxy "$@" +fi + +if [ "$1" = 'haproxy' ]; then + shift # "haproxy" + # if the user wants "haproxy", let's add a couple useful flags + # -W -- "master-worker mode" (similar to the old "haproxy-systemd-wrapper"; allows for reload via "SIGUSR2") + # -db -- disables background mode + set -- haproxy -W -db "$@" +fi + +exec "$@" diff --git a/dd-waf/docker/haproxy/haproxy.conf b/dd-waf/docker/haproxy/haproxy.conf new file mode 100644 index 0000000..73bfde7 --- /dev/null +++ b/dd-waf/docker/haproxy/haproxy.conf @@ -0,0 +1,83 @@ +resolvers mydns + nameserver dns1 127.0.0.11:53 + +global + daemon + log 127.0.0.1 local0 + tune.ssl.default-dh-param 2048 + h1-case-adjust content-type Content-Type + h1-case-adjust content-encoding Content-Encoding + h1-case-adjust transfer-encoding Transfer-Encoding + +defaults + mode http + option http-server-close + option dontlognull + option redispatch + option contstats + retries 3 + timeout connect 5s + timeout http-keep-alive 1s + # Slowloris protection + timeout http-request 15s + timeout queue 30s + timeout tarpit 1m # tarpit hold tim + backlog 10000 + + +frontend tf_waf + mode http + bind :80 + # redirect scheme https if !{ env(BEHIND_PROXY) -m str true } !{ ssl_fc } + http-request del-header ssl_client_cert unless { ssl_fc_has_crt } + http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\ if { ssl_fc_has_crt } + bind :443 ssl crt /certs/chain.pem + + + # New line to test URI to see if its a letsencrypt request + acl letsencrypt-acl path_beg /.well-known/acme-challenge/ + use_backend letsencrypt if letsencrypt-acl + + default_backend bk_waf + +# Traffic secured by the WAF arrives here +frontend ft_web + bind :81 name http + mode http + log global + option httplog + timeout client 25s + maxconn 1000 + default_backend bk_web + +backend letsencrypt + server letsencrypt 127.0.0.1:8080 + +# WAF farm where users' traffic is routed first +backend bk_waf + mode http + server modsecurity dd-waf-apache:80 check port 80 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +# application server farm +backend bk_web + mode http + server sso dd-sso-haproxy:80 check port 80 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +listen stats + bind 0.0.0.0:9999 + mode http + stats enable + option httplog + stats show-legends + stats uri /haproxy + stats realm Haproxy\ Statistics + stats refresh 5s + #stats auth staging:mypassword + #acl authorized http_auth(AuthUsers) + #stats http-request auth unless authorized + timeout connect 5000ms + timeout client 50000ms + timeout server 50000ms + +userlist AuthUsers + user admin password $6$grgQMVfwI0XSGAQl$2usaQC9LVXXXYHtSkGUf74CIGsiH8fi/K.V6DuKSq0twPkmFGP2vL/b//Ulp2I4xBEZ3eYDhUbwBPK8jpmsbo. diff --git a/dd-waf/docker/haproxy/haproxy.proxy-protocol.conf b/dd-waf/docker/haproxy/haproxy.proxy-protocol.conf new file mode 100644 index 0000000..e433219 --- /dev/null +++ b/dd-waf/docker/haproxy/haproxy.proxy-protocol.conf @@ -0,0 +1,182 @@ +# +# Copyright © 2021,2022 IsardVDI S.L. +# Copyright © 2022 Evilham +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +resolvers mydns + nameserver dns1 127.0.0.11:53 + +global +# debug + daemon + log 127.0.0.1 local0 + tune.ssl.default-dh-param 2048 + h1-case-adjust content-type Content-Type + h1-case-adjust content-encoding Content-Encoding + h1-case-adjust transfer-encoding Transfer-Encoding + + defaults + mode http + timeout connect 120s + timeout client 120s + timeout client-fin 120s + timeout server 120s + timeout tunnel 7200s + option http-server-close + option httpclose + log global + option httplog + backlog 4096 + maxconn 2000 + option tcpka + option h1-case-adjust-bogus-client + +frontend website + mode http + bind :80 + bind :8888 accept-proxy + redirect scheme https if !{ env(BEHIND_PROXY) -m str true } !{ ssl_fc } + http-request del-header ssl_client_cert unless { ssl_fc_has_crt } + http-request set-header ssl_client_cert -----BEGIN\ CERTIFICATE-----\ %[ssl_c_der,base64]\ -----END\ CERTIFICATE-----\ if { ssl_fc_has_crt } + bind :443 ssl crt /certs/chain.pem + bind :591 accept-proxy ssl crt /certs/chain.pem + + acl is_upgrade hdr(Connection) -i upgrade + acl is_websocket hdr(Upgrade) -i websocket + + acl is_nextcloud hdr_beg(host) nextcloud. + acl is_moodle hdr_beg(host) moodle. !path_beg -i /local/tresipuntimportgc/ + acl is_moodle_long hdr_beg(host) moodle. path_beg -i /local/tresipuntimportgc/ + acl is_oof hdr_beg(host) oof. + acl is_wp hdr_sub(host) .wp. + acl is_wp hdr_beg(host) wp. + acl is_pad hdr_beg(host) pad. + acl is_sso hdr_beg(host) sso. + acl is_api hdr_beg(host) api. + acl is_admin hdr_beg(host) admin. + + acl is_root path -i / + http-request deny if is_pad is_root + + use_backend be_api if { path_end -i favicon.ico } or { path_end -i favicon } or { path_beg -i /apps/theming/favicon/ } + + use_backend letsencrypt if { path_beg /.well-known/acme-challenge/ } + use_backend be_api if is_nextcloud { path_beg /avatar/ } + use_backend be_nextcloud if is_nextcloud + use_backend be_moodle_long if is_moodle_long + use_backend be_moodle if is_moodle + use_backend be_oof if is_oof + use_backend be_wp if is_wp + use_backend be_etherpad if is_pad + use_backend be_admin if is_sso { path_beg /socket.io } + use_backend be_admin if is_admin + use_backend be_sso if is_sso + use_backend be_api if is_api + + http-request redirect code 301 location https://moodle."${DOMAIN}" if { hdr(host) -i "${DOMAIN}" } +# default_backend be_sso + +backend letsencrypt + server letsencrypt 127.0.0.1:8080 + +backend be_api + mode http + http-request set-path /img/favicon.ico if { path_end -i favicon.ico } or { path_end -i favicon } or { path_beg -i /apps/theming/favicon/ } + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + # Nextcloud use /avatar/username/32 /avatar/username/64 and /avatar/username/128 + http-request set-path %[path,regsub(\"^(/avatar/[^/]+).*\",\"\1\")] + server api dd-sso-api:80 check port 80 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_sso + mode http + option httpclose + option forwardfor + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + http-response replace-header Set-Cookie (KEYCLOAK_LOCALE=[^;]*);(.*) \1;Domain="${DOMAIN}";Version=1;Path=/;Secure; + server keycloak dd-sso-keycloak:8080 check port 8080 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_admin + mode http + option forwardfor + timeout queue 600s + timeout server 600s + timeout connect 600s + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + server dd-sso-admin dd-sso-admin:9000 check port 9000 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +## APPS +backend be_moodle + mode http + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + server moodle dd-apps-moodle:8080 check port 8080 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_moodle_long + mode http + timeout server 900s + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + server moodle dd-apps-moodle:8080 check port 8080 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_nextcloud + mode http + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + server nextcloud dd-apps-nextcloud-nginx:80 check port 80 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_etherpad + mode http + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + server etherpad dd-apps-etherpad:9001 check port 9001 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_oof + mode http + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + server onlyoffice dd-apps-onlyoffice:80 check port 80 inter 5s rise 2 fall 10 resolvers mydns init-addr none + +backend be_wp + mode http + acl existing-x-forwarded-host req.hdr(X-Forwarded-Host) -m found + acl existing-x-forwarded-proto req.hdr(X-Forwarded-Proto) -m found + http-request add-header X-Forwarded-Host %[req.hdr(Host)] unless existing-x-forwarded-host + http-request add-header X-Forwarded-Proto https unless existing-x-forwarded-proto + + http-request set-header X-SSL %[ssl_fc] + http-request set-header X-Forwarded-Proto https + server wp dd-apps-wordpress:80 check port 80 inter 5s rise 2 fall 10 resolvers mydns init-addr none diff --git a/dd-waf/docker/haproxy/letsencrypt-hook-deploy-concatenante.sh b/dd-waf/docker/haproxy/letsencrypt-hook-deploy-concatenante.sh new file mode 100755 index 0000000..3b3fc34 --- /dev/null +++ b/dd-waf/docker/haproxy/letsencrypt-hook-deploy-concatenante.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +cat $RENEWED_LINEAGE/fullchain.pem $RENEWED_LINEAGE/privkey.pem > /certs/chain.pem + +kill -SIGUSR2 1 diff --git a/dd-waf/docker/haproxy/letsencrypt-renew-cron.sh b/dd-waf/docker/haproxy/letsencrypt-renew-cron.sh new file mode 100755 index 0000000..486d64a --- /dev/null +++ b/dd-waf/docker/haproxy/letsencrypt-renew-cron.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +certbot renew --http-01-port 8080 --cert-name sso.$LETSENCRYPT_DOMAIN diff --git a/dd-waf/docker/haproxy/letsencrypt.sh b/dd-waf/docker/haproxy/letsencrypt.sh new file mode 100755 index 0000000..a571eff --- /dev/null +++ b/dd-waf/docker/haproxy/letsencrypt.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +if [ ! -L /etc/letsencrypt/renewal-hooks/deploy/letsencrypt-hook-deploy-concatenante.sh ] +then + mkdir -p /etc/letsencrypt/renewal-hooks/deploy/ + ln -s /usr/local/sbin/letsencrypt-hook-deploy-concatenante.sh /etc/letsencrypt/renewal-hooks/deploy/ +fi + +if [ -n "$LETSENCRYPT_DOMAIN" -a -n "$LETSENCRYPT_EMAIL" ] +then + LETSENCRYPT_DOMAIN="$LETSENCRYPT_DOMAIN" crond + if [ "$LETSENCRYPT_DOMAIN_ROOT" == "true" ] + then + option_root_domain="-d $LETSENCRYPT_DOMAIN" + fi + if [ ! -f /certs/chain.pem ] + then + if certbot certonly --standalone -m "$LETSENCRYPT_EMAIL" -n --agree-tos \ + -d "sso.$LETSENCRYPT_DOMAIN" \ + -d "api.$LETSENCRYPT_DOMAIN" \ + -d "admin.$LETSENCRYPT_DOMAIN" \ + -d "moodle.$LETSENCRYPT_DOMAIN" \ + -d "nextcloud.$LETSENCRYPT_DOMAIN" \ + -d "wp.$LETSENCRYPT_DOMAIN" \ + -d "oof.$LETSENCRYPT_DOMAIN" \ + -d "pad.$LETSENCRYPT_DOMAIN" \ + $option_root_domain + then + RENEWED_LINEAGE="/etc/letsencrypt/live/sso.$LETSENCRYPT_DOMAIN" /etc/letsencrypt/renewal-hooks/deploy/letsencrypt-hook-deploy-concatenante.sh + fi + fi +fi diff --git a/dd-waf/docker/modsecurity/000-default.conf b/dd-waf/docker/modsecurity/000-default.conf new file mode 100644 index 0000000..32f9c26 --- /dev/null +++ b/dd-waf/docker/modsecurity/000-default.conf @@ -0,0 +1,14 @@ + + modsecurity on + modsecurity_rules_file /etc/apache2/modsecurity.d/modsec_rules.conf + ServerAdmin webmaster@localhost + DocumentRoot /var/www/html + ErrorLog ${APACHE_LOG_DIR}/error.log + CustomLog ${APACHE_LOG_DIR}/access.log combined7 + + ProxyPreserveHost On + ProxyRequests off + ProxyVia Off + ProxyPass "/" "http://dd-waf-haproxy:81/" + ProxyPassReverse "/" "http://dd-waf-haproxy:81/" + diff --git a/dd-waf/docker/modsecurity/Dockerfile b/dd-waf/docker/modsecurity/Dockerfile new file mode 100644 index 0000000..0276f51 --- /dev/null +++ b/dd-waf/docker/modsecurity/Dockerfile @@ -0,0 +1,59 @@ +# Install Modsecurity in a Docker container; +FROM ubuntu:20.04 as production +ARG DEBIAN_FRONTEND=noninteractive +# update/upgrade your system +RUN apt-get update -y + +# Install Required Dependencies +RUN apt-get install -y g++ flex bison curl apache2-dev \ + doxygen libyajl-dev ssdeep liblua5.2-dev \ + libgeoip-dev libtool dh-autoreconf \ + libcurl4-gnutls-dev libxml2 libpcre++-dev \ + libxml2-dev git wget tar apache2 \ + certbot python3-certbot-apache + +# Download LibModsecurity +RUN wget https://github.com/SpiderLabs/ModSecurity/releases/download/v3.0.8/modsecurity-v3.0.8.tar.gz + +# Extract the Downloaded File +RUN tar xzf modsecurity-v3.0.8.tar.gz && rm -rf modsecurity-v3.0.8.tar.gz + +# Compile and Install LibModsecurity +RUN cd modsecurity-v3.0.8 && \ + ./build.sh && ./configure && \ + make && make install + +# Install ModSecurity-Apache Connector +RUN cd ~ && git clone https://github.com/SpiderLabs/ModSecurity-apache + +RUN cd ~/ModSecurity-apache && \ + ./autogen.sh && \ + ./configure --with-libmodsecurity=/usr/local/modsecurity/ && \ + make && \ + make install + +# Load the Apache ModSecurity Connector Module +RUN echo "LoadModule security3_module /usr/lib/apache2/modules/mod_security3.so" >> /etc/apache2/apache2.conf + +# Configure ModSecurity +RUN mkdir /etc/apache2/modsecurity.d && \ + cp modsecurity-v3.0.8/modsecurity.conf-recommended /etc/apache2/modsecurity.d/modsecurity.conf && \ + cp modsecurity-v3.0.8/unicode.mapping /etc/apache2/modsecurity.d/ && \ + sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/apache2/modsecurity.d/modsecurity.conf +ADD modsec_rules.conf /etc/apache2/modsecurity.d/ + +# Install OWASP ModSecurity Core Rule Set (CRS) on Ubuntu +RUN git clone https://github.com/SpiderLabs/owasp-modsecurity-crs.git /etc/apache2/modsecurity.d/owasp-crs && \ + cp /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf.example /etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf + +# Activate ModSecurity +RUN mv /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/000-default.conf.old +ADD 000-default.conf /etc/apache2/sites-available/ + +RUN a2enmod proxy_http + +EXPOSE 80 +CMD apachectl -D FOREGROUND + +# Testing ModSecurity +#curl http:///index.php?exec=/bin/bash \ No newline at end of file diff --git a/dd-waf/docker/modsecurity/letsencrypt-hook-deploy-concatenante.sh b/dd-waf/docker/modsecurity/letsencrypt-hook-deploy-concatenante.sh new file mode 100755 index 0000000..3b3fc34 --- /dev/null +++ b/dd-waf/docker/modsecurity/letsencrypt-hook-deploy-concatenante.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +cat $RENEWED_LINEAGE/fullchain.pem $RENEWED_LINEAGE/privkey.pem > /certs/chain.pem + +kill -SIGUSR2 1 diff --git a/dd-waf/docker/modsecurity/letsencrypt-renew-cron.sh b/dd-waf/docker/modsecurity/letsencrypt-renew-cron.sh new file mode 100755 index 0000000..486d64a --- /dev/null +++ b/dd-waf/docker/modsecurity/letsencrypt-renew-cron.sh @@ -0,0 +1,21 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +certbot renew --http-01-port 8080 --cert-name sso.$LETSENCRYPT_DOMAIN diff --git a/dd-waf/docker/modsecurity/letsencrypt.sh b/dd-waf/docker/modsecurity/letsencrypt.sh new file mode 100755 index 0000000..5a524cb --- /dev/null +++ b/dd-waf/docker/modsecurity/letsencrypt.sh @@ -0,0 +1,50 @@ +#!/bin/sh +# +# Copyright © 2021,2022 IsardVDI S.L. +# +# This file is part of DD +# +# DD is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# DD is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License +# along with DD. If not, see . +# +# SPDX-License-Identifier: AGPL-3.0-or-later +if [ ! -L /etc/letsencrypt/renewal-hooks/deploy/letsencrypt-hook-deploy-concatenante.sh ] +then + mkdir -p /etc/letsencrypt/renewal-hooks/deploy/ + ln -s /usr/local/sbin/letsencrypt-hook-deploy-concatenante.sh /etc/letsencrypt/renewal-hooks/deploy/ +fi + +if [ -n "$LETSENCRYPT_DOMAIN" -a -n "$LETSENCRYPT_EMAIL" ] +then + LETSENCRYPT_DOMAIN="$LETSENCRYPT_DOMAIN" crond + if [ "$LETSENCRYPT_DOMAIN_ROOT" == "true" ] + then + option_root_domain="-d $LETSENCRYPT_DOMAIN" + fi + if [ ! -f /certs/chain.pem ] + then + if certbot certonly --standalone -m "$LETSENCRYPT_EMAIL" -n --agree-tos --apache --redirect --uir --hsts --staple-ocsp --must-staple\ + -d "sso.$LETSENCRYPT_DOMAIN" \ + -d "api.$LETSENCRYPT_DOMAIN" \ + -d "admin.$LETSENCRYPT_DOMAIN" \ + -d "moodle.$LETSENCRYPT_DOMAIN" \ + -d "nextcloud.$LETSENCRYPT_DOMAIN" \ + -d "wp.$LETSENCRYPT_DOMAIN" \ + -d "oof.$LETSENCRYPT_DOMAIN" \ + -d "pad.$LETSENCRYPT_DOMAIN" \ + $option_root_domain + then + RENEWED_LINEAGE="/etc/letsencrypt/live/sso.$LETSENCRYPT_DOMAIN" /etc/letsencrypt/renewal-hooks/deploy/letsencrypt-hook-deploy-concatenante.sh + fi + fi +fi \ No newline at end of file diff --git a/dd-waf/docker/modsecurity/modsec_rules.conf b/dd-waf/docker/modsecurity/modsec_rules.conf new file mode 100644 index 0000000..51d7cf6 --- /dev/null +++ b/dd-waf/docker/modsecurity/modsec_rules.conf @@ -0,0 +1,3 @@ +Include "/etc/apache2/modsecurity.d/modsecurity.conf" +Include "/etc/apache2/modsecurity.d/owasp-crs/crs-setup.conf" +Include "/etc/apache2/modsecurity.d/owasp-crs/rules/*.conf"