[WAF] Consolidate proxies and documentation

The environment / dd.conf variables: PROXY_PROTOCOL and DISABLE_WAF
determine how DD and HAProxy will behave.

- PROXY_PROTOCOL: whether or not the PROXY protocol will be accepted
- DISABLE_WAF: whether or not WAF will be enabled

This simplifies maintenance, as well as the overall architecture and operation.

While at it, we now publish images for DD's HAProxy as well.
merge-requests/44/head
Evilham 2022-11-23 20:10:13 +01:00
parent e6325c9618
commit 09fec74915
No known key found for this signature in database
GPG Key ID: AE3EE30D970886BF
40 changed files with 418 additions and 938 deletions

40
dd-ctl
View File

@ -182,7 +182,31 @@ build_compose(){
setconf CUSTOM_PATH "$CUSTOM_PATH" .env
setconf BUILD_APPS_ROOT_PATH "$CUSTOM_PATH/dd-apps" .env
setconf BUILD_SSO_ROOT_PATH "$CUSTOM_PATH/dd-sso" .env
setconf BUILD_WAF_ROOT_PATH "$CUSTOM_PATH/dd-waf" .env
# Choose HAProxy configuration flavour
if [ "${PROXY_PROTOCOL:-false}" = "true" ]; then
HAPROXY_YML="haproxy.proxy.yml"
HAPROXY_PROXY="proxy"
else
# Default
HAPROXY_YML="haproxy.yml"
HAPROXY_PROXY="no-proxy"
fi
# Enable or disable WAF
if [ "${DISABLE_WAF:-true}" = "true" ]; then
# Current default (might change)
WAF_YML="waf-modsecurity.disabled.yml"
HAPROXY_WAF="no-waf"
else
WAF_YML="waf-modsecurity.yml"
HAPROXY_WAF="waf"
fi
# Persist resulting HAProxy config
export HAPROXY_CFG="haproxy.${HAPROXY_WAF}.${HAPROXY_PROXY}.cfg"
setconf HAPROXY_CFG "${HAPROXY_CFG}"
setconf HAPROXY_CFG "${HAPROXY_CFG}" .env
## Prepare apps environment
ln -sf "${CUSTOM_PATH}/.env" dd-apps/.env
ln -sf "${CUSTOM_PATH}/.env" dd-apps/docker/postgresql && \
@ -204,20 +228,10 @@ build_compose(){
rm -rf custom/system/keycloak-themes
rmdir custom/system 2>/dev/null || true
if [ "$BEHIND_PROXY" = "true" ]; then
BEHIND="haproxy-behind.yml"
MODSECURITY="-f dd-waf/docker-compose-parts/modsecurity.yml"
HAPROXY_WAF="-f dd-waf/docker-compose-parts/haproxy.yml"
else
BEHIND="haproxy.yml"
fi
# Build compose ymls
# shellcheck disable=SC2086
docker-compose \
$MODSECURITY $HAPROXY_WAF \
\
-f dd-sso/docker-compose-parts/$BEHIND \
-f "dd-sso/docker-compose-parts/$WAF_YML" \
-f "dd-sso/docker-compose-parts/$HAPROXY_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 \

View File

@ -20,6 +20,7 @@
version: '3.7'
services:
dd-sso-haproxy:
image: registry.dd-work.space/dd/haproxy:${DD_BUILD:-latest}
build:
args:
HAPROXY_IMG: ${HAPROXY_IMG-haproxy:2.4.12-alpine3.15}

View File

@ -0,0 +1,54 @@
#
# 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 <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
version: '3.7'
services:
dd-sso-haproxy:
image: registry.dd-work.space/dd/haproxy:${DD_BUILD:-latest}
build:
args:
HAPROXY_IMG: ${HAPROXY_IMG-haproxy:2.4.12-alpine3.15}
context: ${BUILD_SSO_ROOT_PATH}/docker/haproxy
dockerfile: Dockerfile
target: production
container_name: dd-sso-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"

View File

@ -20,6 +20,7 @@
version: '3.7'
services:
dd-sso-haproxy:
image: registry.dd-work.space/dd/haproxy:${DD_BUILD:-latest}
build:
args:
HAPROXY_IMG: ${HAPROXY_IMG-haproxy:2.4.12-alpine3.15}
@ -39,11 +40,6 @@ services:
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:

View File

@ -0,0 +1,2 @@
# Dummy file for a disabled WAF
version: '3.7'

View File

@ -3,7 +3,7 @@ services:
dd-waf-apache:
image: registry.dd-work.space/dd/waf-apache:${DD_BUILD:-latest}
build:
context: ${BUILD_WAF_ROOT_PATH}/docker/modsecurity
context: ${BUILD_SSO_ROOT_PATH}/docker/waf-modsecurity
dockerfile: Dockerfile
target: production
container_name: dd-waf-apache

View File

@ -31,7 +31,13 @@ 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
RUN chmod 555 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
COPY haproxy.cnf.parts /haproxy.cnf.parts
ADD gen-haproxy-conf.sh /gen-haproxy-conf.sh
RUN chmod 555 gen-haproxy-conf.sh
# Generate all flavours of configuration
RUN /gen-haproxy-conf.sh waf no-proxy > /usr/local/etc/haproxy/haproxy.waf.no-proxy.cfg
RUN /gen-haproxy-conf.sh waf proxy > /usr/local/etc/haproxy/haproxy.waf.proxy.cfg
RUN /gen-haproxy-conf.sh no-waf no-proxy > /usr/local/etc/haproxy/haproxy.no-waf.no-proxy.cfg
RUN /gen-haproxy-conf.sh no-waf proxy > /usr/local/etc/haproxy/haproxy.no-waf.proxy.cfg

View File

@ -21,7 +21,7 @@
# 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
ln -sf /usr/local/etc/haproxy/${HAPROXY_CFG:-haproxy.no-waf.no-proxy.cfg} /usr/local/etc/haproxy/haproxy.cfg
LETSENCRYPT_DOMAIN="$DOMAIN" letsencrypt.sh

View File

@ -0,0 +1,73 @@
#!/bin/sh -eu
_help(){
cat <<EOF
USAGE: gen-haproxy-conf.sh waf|no-waf proxy|no-proxy
Generate a DD-compatible HAProxy configuration to stdout.
- The first argument indicates whether or not WAF will be enabled.
waf: enable WAF
no-waf: do not use WAF
- The second argument indicates whether or not the PROXY protocol will
be enabled on ports 8888 (HTTP) and 561 (HTTPS) for the outer layer
(either with WAF or without).
EOF
}
case "${1:-}" in
[wW][aA][fF])
USE_WAF="YES"
;;
[nN][oO]-[wW][aA][fF])
;;
*)
_help >> /dev/stderr
exit 1
;;
esac
case "${2:-}" in
[pP][rR][oO][xX][yY])
USE_PROXY="YES"
;;
[nN][oO]-[pP][rR][oO][xX][yY])
;;
*)
_help >> /dev/stderr
exit 1
;;
esac
PARTS_DIR="haproxy.cnf.parts"
_binds(){
cat "${PARTS_DIR}/bind-direct.cnf"
if [ -n "${USE_PROXY:-}" ]; then
cat "${PARTS_DIR}/bind-proxy.cnf"
fi
}
# Beginning
cat "${PARTS_DIR}/head.cnf"
if [ -n "${USE_WAF:-}" ]; then
# WAF bits
cat "${PARTS_DIR}/defaults-waf.cnf"
cat "${PARTS_DIR}/head-waf.cnf"
_binds
cat "${PARTS_DIR}/tail-waf.cnf"
cat "${PARTS_DIR}/web-head.cnf"
else
# Non-WAF bits
cat "${PARTS_DIR}/defaults-non-waf.cnf"
cat "${PARTS_DIR}/tail-non-waf.cnf"
cat "${PARTS_DIR}/web-head.cnf"
_binds
fi
# bk_web ending
cat "${PARTS_DIR}/web-tail.cnf"
# Application backends
cat "${PARTS_DIR}/backends.cnf"

View File

@ -1,96 +1,6 @@
#
# Copyright © 2021,2022 IsardVDI S.L.
# Copyright © 2022 Evilham <contact@evilham.com>
# BEGIN: backends.cnf
#
# 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 <https://www.gnu.org/licenses/>.
#
# 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
@ -180,3 +90,6 @@ backend be_wp
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
#
# END: backends.cnf
#

View File

@ -0,0 +1,16 @@
#
# BEGIN: bind-direct.cnf
#
bind :80
http-request redirect scheme https code 301 unless { 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
#
# END: bind-direct.cnf
#

View File

@ -0,0 +1,8 @@
#
# BEGIN: bind-proxy.cnf
#
bind :8888 accept-proxy
bind :591 accept-proxy ssl crt /certs/chain.pem
#
# END: bind-proxy.cnf
#

View File

@ -0,0 +1,21 @@
#
# BEGIN: defaults-non-waf.cnf
#
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
#
# END: defaults-non-waf.cnf
#

View File

@ -0,0 +1,27 @@
#
# BEGIN: defaults-waf.cnf
#
defaults
mode http
option http-server-close
option dontlognull
option redispatch
# Since ulimit -n (-H) is patched in container
# HAProxy is supposed to adjust this value accordingly
# maxconn 2000
option tcpka # For the backends
option h1-case-adjust-bogus-client
timeout connect 5s # non-waf has 120s
# Slowloris protection
timeout http-request 15s
# By setting timeout http-request these values are shadowed?
# timeout client 120s
# timeout client-fin 120s
# timeout server 120s
# timeout tunnel 2h
timeout queue 30s
timeout tarpit 1m # tarpit hold time
backlog 8192 # Less or equal power of 2 is used
#
# END: defaults-waf.cnf
#

View File

@ -0,0 +1,7 @@
#
# BEGIN: waf-head.cnf
#
frontend tf_waf
#
# END: waf-head.cnf
#

View File

@ -1,6 +1,7 @@
#!/bin/sh
#
# Copyright © 2021,2022 IsardVDI S.L.
# Copyright © 2022 Evilham <contact@evilham.com>
# Copyright © 2022 Teradisk <info@teradisk.com>
#
# This file is part of DD
#
@ -18,6 +19,21 @@
# along with DD. If not, see <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
cat $RENEWED_LINEAGE/fullchain.pem $RENEWED_LINEAGE/privkey.pem > /certs/chain.pem
kill -SIGUSR2 1
#
# BEGIN: head.cnf
#
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
#
# END: head.cnf
#

View File

@ -0,0 +1,7 @@
#
# BEGIN: tail-non-waf.cnf
#
frontend ft_web
#
# END: tail-non-waf.cnf
#

View File

@ -0,0 +1,28 @@
#
# BEGIN: waf-tail.cnf
#
# Internal traffic
use_backend bk_web if { src 172.16.0.0/12 }
default_backend bk_waf
# 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
# Internal traffic passes through this backend
backend bk_web
mode http
server bk_web dd-sso-haproxy:81 resolvers mydns init-addr 127.0.0.1
# Traffic secured by the WAF arrives here
frontend ft_web
bind :81 name http
log global
option httplog
timeout client 25s
maxconn 1000
#
# END: waf-tail.cnf
#

View File

@ -0,0 +1,31 @@
#
# BEGIN: web-head.cnf
#
mode http
# http-request directives must happen here
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 }
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
http-request redirect code 301 location https://moodle."${DOMAIN}" if { hdr(host) -i "${DOMAIN}" }
#
# END: web-head.cnf
#

View File

@ -0,0 +1,21 @@
#
# BEGIN: web-tail.cnf
#
use_backend be_api if { path_end -i favicon.ico } or { path_end -i favicon } or { path_beg -i /apps/theming/favicon/ }
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
# default_backend be_sso
#
# END: web-tail.cnf
#

View File

@ -1,236 +0,0 @@
#
# 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 <https://www.gnu.org/licenses/>.
#
# 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
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
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_jitsi hdr_beg(host) jitsi.
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_ipa hdr_beg(host) ipa.
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_jitsi if is_jitsi
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_adminer if is_sso { path_beg /dd-sso-adminer }
use_backend be_admin if is_admin
use_backend be_sso if is_sso
use_backend be_ipa if is_ipa
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_ipa
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 freeipa dd-sso-freeipa:443 check port 443 ssl verify none inter 5s rise 2 fall 10 resolvers mydns init-addr none
backend be_sso
mode http
option httpclose
#option http-server-close
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 authorized http_auth(AuthUsers)
# http-request auth realm AuthUsers unless authorized
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
backend be_adminer
mode http
# acl authorized http_auth(AuthUsers)
# http-request auth realm AuthUsers unless authorized
http-request redirect scheme http drop-query append-slash if { path -m str /dd-sso-adminer }
http-request replace-path /dd-sso-adminer/(.*) /\1
# http-request del-header Authorization
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-adminer dd-sso-adminer:8080 check port 8080 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_jitsi
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 jitsi dd-apps-jitsi:80 check port 80 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
listen stats
bind 0.0.0.0:8888
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.

View File

@ -1,182 +0,0 @@
#
# Copyright © 2021,2022 IsardVDI S.L.
# Copyright © 2022 Evilham <contact@evilham.com>
#
# 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 <https://www.gnu.org/licenses/>.
#
# 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

View File

@ -9,6 +9,6 @@
ProxyPreserveHost On
ProxyRequests off
ProxyVia Off
ProxyPass "/" "http://dd-waf-haproxy:81/"
ProxyPassReverse "/" "http://dd-waf-haproxy:81/"
ProxyPass "/" "http://dd-sso-haproxy:81/"
ProxyPassReverse "/" "http://dd-sso-haproxy:81/"
</VirtualHost>

View File

@ -1,7 +1,7 @@
#!/bin/bash -e
set -e
if [ "$DISABLE_WAF" == "true" ]; then
if [ "${DISABLE_WAF:-true}" == "true" ]; then
sed -i.orig -e "s/modsecurity On/modsecurity Off/" /etc/apache2/sites-available/000-default.conf
else
sed -i.orig -e "s/modsecurity Off/modsecurity On/" /etc/apache2/sites-available/000-default.conf

View File

@ -1,77 +0,0 @@
# DD - Apache2 ModSecurity + HAProxy
Instalación de los servicios Apache2 ModSecurity y HAProxy.
* En el servicio de Apache2 con ModSecurity V3 se incluyen las reglas OWASP
* En servicio HAProxy actua de frontend de la aplicación, gestiona y negocia el certificado del dominio a través de letsencrypt.
* En la instalación el ModSecurity se encuentra deshabilitado para no interferir en el proceso de setup inicial del DD.
* La instalación se puede realizar con o sin la parte WAF.
* Si tenemos instalado el WAF podemos tenerlo activo o en modo bypass
## HAProxy
Podemos encontrar la configuración del servicio en [dd-waf/haproxy](dd-waf/harpoxy)
La versión por defecto que se usara en HAProxy es `haproxy:2.4.12-alpine3.15` pero podemos definir usar otra versión
definiendo el valor de la variable `HAPROXY_IMG` en nuestro fichero dd.conf
La configuración del servicio se encuentra en fichero haproxy.cfg. Todo el tráfico que pasa por el haproxy se enruta al Apache2-ModSecurity.
El servicio de HAProxy se encarga de negociar y configurar el certicado del dominio de instalación
La comunicación desde fuera del stack de la aplicación es cifrada pero internamente la comunción usa el protocolo http
## Apache - ModSecurity
Podemos encontrar la configuración del servicio en [dd-waf/haproxy](dd-waf/harpoxy)
Tenemos diferentes ficheros para configurar este servicio
* En el fichero 000-default.conf tendremos la configuración del servidor web Apache2.
* En el fichero crs-setup.conf configuramos OWASP ModSecurity Core Rule Set ver.3.2.0
* En el fichero modsec_rules.conf incluimos los ficheros necesarios del owasp servicio de Apache2
* En el fichero rules_apps.conf se configuran los falsos positivos, de las diferentes aplicaciones, que se tienen idenficados hasta el momento.
## Instalación WAF
Podemos hacer la intalación del proyecto con o sin servico waf.
### Instalación
Para la instalación del haproxy + modsecurity debemos definir a `true` la variable `BEHIND_PROXY` en el fichero `dd.conf`
* Instalación del servicio WAF
```
BEHIND_PROXY=true
```
* No se instala el servicio WAF
```
BEHIND_PROXY=true
```
### Enable/Disable
Si tenemos instalado la parte del WAF en nuestro proyecto podemos tenerlo activo o desactivado.
* HAProxy activado
```
DISABLE_WAF=false
```
* HAProxy desactivado
```
DISABLE_WAF=true
```
### Configuración
Ahora tenemos que desplegar el modsecurity + haproxy ejecutando el comando `update` del `dd-ctl`
```
./dd-ctl update
```

View File

@ -1,34 +0,0 @@
version: '3.7'
services:
dd-waf-haproxy:
build:
args:
HAPROXY_IMG: ${HAPROXY_IMG-haproxy:2.4.12-alpine3.15}
context: ${BUILD_WAF_ROOT_PATH}/docker/haproxy
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"

View File

@ -1,35 +0,0 @@
#
# 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 <https://www.gnu.org/licenses/>.
#
# 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.cfg /usr/local/etc/haproxy/haproxy.cfg

View File

@ -1,50 +0,0 @@
#
# 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 <https://www.gnu.org/licenses/>.
#
# 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

View File

@ -1,43 +0,0 @@
#!/bin/sh
#
# Copyright © 2021,2022 IsardVDI S.L.
# Copyright © 2022 Evilham <contact@evilham.com>
#
# 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 <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
set -e
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 "$@"

View File

@ -1,86 +0,0 @@
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
http-request redirect scheme https code 301 unless { 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
# Internal traffic
use_backend bk_web if { src 192.168.0.0/16 }
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.

View File

@ -1,21 +0,0 @@
#!/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 <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: AGPL-3.0-or-later
certbot renew --http-01-port 8080 --cert-name sso.$LETSENCRYPT_DOMAIN

View File

@ -1,50 +0,0 @@
#!/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 <https://www.gnu.org/licenses/>.
#
# 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

View File

@ -146,11 +146,11 @@ MARIADB_PASSWORD=SuperSecret
##=============================================================================
IPA_ADMIN_PWD=freeipafreeipa
## WORKS BEHIND PROXY
BEHIND_PROXY=false
## ACCEPT PROXY PROTOCOL ON 8888 (HTTP) AND 561 (HTTPS)
#PROXY_PROTOCOL=false
## MODSECURITY
DISABLE_WAF=true
## DISABLE WAF/MODSECURITY
#DISABLE_WAF=true
# SOURCES & SYSTEM VARS

View File

@ -30,6 +30,10 @@ Això es fa en l'aplicació admin.
- anar a groups i verificar que apareix
- anar a users i crear l'usuari "docent01" del grup "docents" amb role "teacher"
## Activar WAF
Si així ho volem, podem activar el Web Application Firewall/Modsecurity seguint
[aquestes instruccions](waf-modsecurity.es.md).
## Plantilles Nextcloud (Opcional)

View File

@ -0,0 +1,49 @@
# DD - Apache2 ModSecurity + HAProxy
Instalación de los servicios Apache2 ModSecurity y HAProxy.
* En el servicio de Apache2 con ModSecurity V3 se incluyen las reglas OWASP
* En servicio HAProxy actua de frontend de la aplicación, gestiona y negocia el certificado del dominio a través de letsencrypt.
* En la instalación el ModSecurity se encuentra deshabilitado para no interferir en el proceso de setup inicial del DD.
* La instalación se puede realizar con o sin la parte WAF.
* Si tenemos instalado el WAF podemos tenerlo activo o en modo bypass
## Apache - ModSecurity
Podemos encontrar la definición del servicio en `dd-sso/docker/waf-modsecurity`.
Tenemos diferentes ficheros para configurar este servicio:
* En el fichero `000-default.conf` tendremos la configuración del servidor web Apache2.
* En el fichero `crs-setup.conf` configuramos OWASP ModSecurity Core Rule Set ver.3.2.0
* En el fichero `modsec_rules.conf` incluimos los ficheros necesarios del owasp servicio de Apache2
* En el fichero `rules_apps.conf` se configuran los falsos positivos, de las diferentes aplicaciones, que se tienen idenficados hasta el momento.
### Enable/Disable
DD se puede utilizar con WAF tenerlo activo o desactivado, esto se gestiona
con la variable `DISABLE_WAF` en `dd.conf`.
El valor por defecto actual es `true` (WAF desactivado),
esto cambiará en un futuro.
```
# Ejemplo de dd.conf
# Usar WAF
DISABLE_WAF=false
# No usar WAF
DISABLE_WAF=false
```
### Configuración
Los cambios en `dd.conf` no son inmediatos,
tenemos que re-desplegar los contenedores de DD usando `dd-ctl`:
```sh
./dd-ctl down
./dd-ctl build
./dd-ctl up
```