Logré persistir con éxito mis cambios de configuración de nginx ModSecurity a través de las ejecuciones de launcher rebuild app de la siguiente manera:
Primero, actualizamos la copia local de install-nginx que proviene del repositorio discourse_docker y que se clona en /var/discourse/.
cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig
# agregar un bloque para extraer el módulo nginx de modsecurity justo antes de descargar el código fuente de nginx
grep 'ModSecurity' install-nginx || sed -i 's%\(curl.*nginx\.org/download.*\)%# mod_security\napt-get install -y libmodsecurity-dev modsecurity-crs\ncd /tmp\ngit clone --depth 1 https://github.com/SpiderLabs/ModSecurity-nginx.git\n\n\1%' install-nginx
# actualizar la línea de configuración para incluir el módulo ModSecurity extraído anteriormente
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx
# agregar una línea a la sección de limpieza
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx
Tenga en cuenta que el Dockerfile responsable de ejecutar el script install-nginx se ejecuta cuando se construye la imagen. Y la imagen solo es construida por el equipo de Discourse antes de ser subida a docker hub. Cuando se ejecuta el comando ./launcher rebuild app de Discourse, se activa (si hay actualizaciones disponibles) un docker pull, que obtiene la última imagen de Docker de Discourse desde docker hub. Nuevamente, esto no reconstruye la imagen, no ejecuta el Dockerfile ni ejecuta el script install-nginx modificado anteriormente.
La única forma (que yo sepa) de activar la ejecución del script bash actualizado install-nginx (que es ejecutado por el Dockerfile) es que Docker construya una nueva imagen. Por ejemplo, esto activa a Docker para construir una nueva imagen llamada discourse_modsecurity, la cual se construirá utilizando el script install-nginx modificado localmente:
docker build --tag 'discourse_modsecurity' /var/discourse/image/base/
Desafortunadamente, no pude encontrar una manera de decirle a launcher que use una imagen personalizada (especificar un run-image utiliza la imagen especificada directamente, sin ejecutar las plantillas sobre ella, como se necesita para configurar [en lugar de solo instalar] nginx). Por lo tanto, reemplazamos la variable image definida en el script launcher para usar nuestra nueva imagen de Docker local llamada discourse_modsecurity.
# reemplazar la línea "image="discourse/base:<version>" con 'image="discourse_modsecurity"'
grep 'discourse_modsecurity' launcher || sed --in-place=.`date "+%Y%m%d_%H%M%S"` '/base_image/! s%^\(\s*\)image=\(.*\)$%#\1image=\2\n\1image="discourse_modsecurity"%' /var/discourse/launcher
Ahora agregamos un nuevo archivo de plantilla para configurar nuestras configuraciones de nginx e incluir los archivos/bloques necesarios de modsecurity.
cat << EOF > /var/discourse/templates/web.modsecurity.template.yml
run:
- exec:
cmd:
- sudo apt-get install -y modsecurity-crs
- cp /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf
- sed -i 's/SecRuleEngine DetectionOnly/SecRuleEngine On/' /etc/modsecurity/modsecurity.conf
- sed -i 's^\(\s*\)[^#]*SecRequestBodyInMemoryLimit\(.*\)^\1#SecRequestBodyInMemoryLimit\2^' /etc/modsecurity/modsecurity.conf
- sed -i '/nginx/! s%^\(\s*\)[^#]*SecAuditLog \(.*\)%#\1SecAuditLog \2\n\1SecAuditLog /var/log/nginx/modsec_audit.log%' /etc/modsecurity/modsecurity.conf
- file:
path: /etc/nginx/conf.d/modsecurity.include
contents: |
################################################################################
# Archivo: modsecurity.include
# Versión: 0.1
# Propósito: Define reglas de mod_security para el vhost de discourse
# Esto debe incluirse en los bloques server{} de los vhosts de nginx.
# Autor: Michael Altfield <michael@opensourceecology.org>
# Creado: 2019-11-12
# Actualizado: 2019-11-12
################################################################################
Include "/etc/modsecurity/modsecurity.conf"
# OWASP Core Rule Set, instalado desde el paquete 'modsecurity-crs' en debian
Include /etc/modsecurity/crs/crs-setup.conf
Include /usr/share/modsecurity-crs/rules/*.conf
- replace:
filename: "/etc/nginx/conf.d/discourse.conf"
from: /server.+{/
to: |
server {
modsecurity on;
modsecurity_rules_file /etc/nginx/conf.d/modsecurity.include;
EOF
Y agregamos esta plantilla (templates/web.modsecurity.template.yml) al bloque de plantillas del archivo de configuración yaml de nuestra aplicación, para que se vea algo así:
[root@osestaging1 discourse]# vim /var/discourse/containers/app.yml
...
[root@osestaging1 discourse]# grep -A 6 'templates:' /var/discourse/containers/app.yml
templates:
- "templates/postgres.template.yml"
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
- "templates/web.socketed.template.yml"
- "templates/web.modsecurity.template.yml"
[root@osestaging1 discourse]#
Ahora, cuando reconstruyas la aplicación de Docker de Discourse, usará tu nueva imagen de Docker discourse_modsecurity con nginx y modsecurity, y configurará nginx para utilizar el OWASP CRS.
/var/discourse/launcher rebuild app