我成功地在多次运行 launcher rebuild app 后持久化了 nginx ModSecurity 的配置更改,具体步骤如下:
首先,更新从 discourse_docker 仓库 获取并克隆到 /var/discourse/ 的本地 install-nginx 副本。
cd /var/discourse/image/base
cp install-nginx install-nginx.`date "+%Y%m%d_%H%M%S"`.orig
# 在下载 nginx 源代码之前,添加一个块来检出 modsecurity 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
# 更新 configure 行以包含上面检出的 ModSecurity 模块
sed -i '/ModSecurity/! s%^[^#]*./configure \(.*nginx.*\)%#./configure \1\n./configure \1 --add-module=/tmp/ModSecurity-nginx%' install-nginx
# 在清理部分添加一行
grep 'rm -fr /tmp/ModSecurity-nginx' install-nginx || sed -i 's%\(rm -fr.*/tmp/nginx.*\)%rm -fr /tmp/ModSecurity-nginx\n\1%' install-nginx
请注意,负责执行 install-nginx 脚本的 Dockerfile 是在构建镜像时执行的。而该镜像仅由 Discourse 团队在上传到 Docker Hub 之前构建。当运行 Discourse 的 ./launcher rebuild app 命令时,它会触发(如果有可用更新)一个 docker pull,从 Docker Hub 获取最新的 Discourse Docker 镜像。同样,这不会重新构建镜像、执行 Dockerfile 或执行上面修改的 install-nginx 脚本。
据我所知,触发更新后的 install-nginx Bash 脚本运行(该脚本由 Dockerfile 执行)的唯一方法是让 Docker 构建一个新镜像。例如,这会触发 Docker 构建一个名为 discourse_modsecurity 的新镜像——该镜像将使用本地修改后的 install-nginx 脚本进行构建:
docker build --tag 'discourse_modsecurity' /var/discourse/image/base/
不幸的是,我找不到一种方法让 launcher 使用自定义镜像(指定 run-image 会直接使用指定的镜像,而不会对其执行模板——而这是实际配置(而不仅仅是安装)nginx 所必需的)。因此,我们替换 launcher 脚本中定义的 image 变量,以使用我们新的本地 Docker 镜像 discourse_modsecurity。
# 将行 "image="discourse/base:<version>" 替换为 '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
现在,我们添加一个新的模板文件,以设置我们的 nginx 配置,使其包含必要的 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: |
################################################################################
# File: modsecurity.include
# Version: 0.1
# Purpose: Defines mod_security rules for the discourse vhost
# This should be included in the server{} blocks nginx vhosts.
# Author: Michael Altfield <michael@opensourceecology.org>
# Created: 2019-11-12
# Updated: 2019-11-12
################################################################################
Include "/etc/modsecurity/modsecurity.conf"
# OWASP Core Rule Set, installed from the 'modsecurity-crs' package in 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
并将此模板(templates/web.modsecurity.template.yml)添加到我们应用的 yaml 配置文件的 templates 块中,使其看起来类似于以下内容:
[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]#
现在,当您重新构建 Discourse Docker 应用时,它将使用您新的 discourse_modsecurity Docker 镜像(该镜像使用带有 ModSecurity 的 nginx),并将配置 nginx 以使用 OWASP CRS。
/var/discourse/launcher rebuild app