Мне не разрешено публиковать сообщения в разделе «Как сделать», поэтому я размещу это здесь ![]()
Обзор
Цель — добавить WAF к существующим ресурсам, сохраняя производительность на небольшой установке. В этом примере мы будем использовать один экземпляр EC2. Поскольку Discourse работает в Docker, мы можем установить NGINX на хосте и использовать прокси-перенаправление (proxy_pass) для передачи трафика в наш контейнер Docker. Мы также используем RDS для PostgreSQL.
Настройка Discourse
Первым шагом является настройка файла app.yml для индивидуальной установки Discourse. В этом примере мы будем запускать роли web и redis. Роль DB и роль SSL использоваться не будут.
Также мы хотим убедиться, что порты web не открыты в контейнере Docker. Причина в том, что мы будем открывать доступ к web через прокси NGINX на хосте.
Пример файла app.yml
## это шаблон автономного контейнера Docker Discourse «все в одном»
##
## После внесения изменений в этот файл вы ОБЯЗАНЫ выполнить пересборку
## /var/discourse/launcher rebuild app
##
## БУДЬТЕ *ОЧЕНЬ* ОСТОРОЖНЫ ПРИ РЕДАКТИРОВАНИИ!
## YAML-ФАЙЛЫ ЧРЕЗВЫЧАЙНО ЧУВСТВИТЕЛЬНЫ К ОШИБКАМ В ПРОБЕЛАХ ИЛИ ВЫРАВНИВАНИИ!
## для проверки файла посещайте http://www.yamllint.com/ по мере необходимости
templates:
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
- "templates/web.socketed.template.yml"
## Раскомментируйте эти две строки, если хотите добавить Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
## какие TCP/IP-порты должен открывать этот контейнер?
## Если вы хотите, чтобы Discourse использовал порт совместно с другим веб-сервером, например Apache или nginx,
## см. https://meta.discourse.org/t/17247 для деталей
expose:
# - "80:80" # http
# - "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
## Установите db_shared_buffers максимум на 25% от общего объема памяти.
## будет установлено автоматически при загрузке в зависимости от обнаруженной оперативной памяти, или вы можете переопределить
db_shared_buffers: "768MB"
## может улучшить производительность сортировки, но увеличивает использование памяти на подключение
#db_work_mem: "40MB"
## Какую ревизию Git должен использовать этот контейнер? (по умолчанию: tests-passed)
#version: tests-passed
env:
LANG: en_US.UTF-8
# DISCOURSE_DEFAULT_LOCALE: en
## Сколько одновременных веб-запросов поддерживается? Зависит от памяти и ядер CPU.
## будет установлено автоматически при загрузке в зависимости от обнаруженных процессоров, или вы можете переопределить
UNICORN_WORKERS: 2
## TODO: Доменное имя, на которое будет реагировать этот экземпляр Discourse
## Обязательно. Discourse не будет работать с чистым IP-адресом.
DISCOURSE_HOSTNAME: cloudforums.net
## Раскомментируйте, если хотите, чтобы контейнер запускался с тем же
## именем хоста (-h option), что указано выше (по умолчанию "$hostname-$config")
#DOCKER_USE_HOSTNAME: true
## TODO: Список email-адресов через запятую, которые станут администраторами и разработчиками
## при первой регистрации, например 'user1@example.com,user2@example.com'
DISCOURSE_DEVELOPER_EMAILS: 'youremail@domain.com'
## TODO: SMTP-сервер, используемый для проверки новых учетных записей и отправки уведомлений
## Адрес SMTP, имя пользователя и пароль обязательны
## ВНИМАНИЕ: символ '#' в пароле SMTP может вызвать проблемы!
DISCOURSE_SMTP_ADDRESS: YOUR_SMTP
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: YOUR_SMTP_USERNAME
DISCOURSE_SMTP_PASSWORD: YOUR_SMTP_PASSWORD
#DISCOURSE_SMTP_ENABLE_START_TLS: true # (опционально, по умолчанию true)
## Если вы добавили шаблон Lets Encrypt, раскомментируйте ниже, чтобы получить бесплатный SSL-сертификат
#LETSENCRYPT_ACCOUNT_EMAIL: me@example.com
DISCOURSE_DB_SOCKET: ''
DISCOURSE_DB_USERNAME: YOUR_USERNAME
DISCOURSE_DB_PASSWORD: YOUR_PASSWORD
DISCOURSE_DB_HOST: YOUR_HOST
## HTTP или HTTPS-адрес CDN для этого экземпляра Discourse (настроен на загрузку)
## см. https://meta.discourse.org/t/14857 для деталей
#DISCOURSE_CDN_URL: https://discourse-cdn.example.com
## Контейнер Docker не имеет состояния; все данные хранятся в /shared
volumes:
- volume:
host: /var/discourse/shared/standalone
guest: /shared
- volume:
host: /var/discourse/shared/standalone/log/var-log
guest: /var/log
## Плагины размещаются здесь
## см. https://meta.discourse.org/t/19157 для деталей
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/docker_manager.git
## Любые пользовательские команды для выполнения после сборки
run:
- exec: echo "Начало пользовательских команд"
## Если вы хотите установить адрес email «От» для вашей первой регистрации, раскомментируйте и измените:
## После получения первого email регистрации закомментируйте строку снова. Выполнять нужно только один раз.
- exec: rails c "SiteSetting.enable_badge_sql = true"
- exec: echo "Конец пользовательских команд"
Начало установки Discourse
Клонирование репозитория Discourse
sudo -u root git clone https://github.com/discourse/discourse_docker.git /var/discours
Копирование пользовательского app.yml для установки
Вы можете выполнить команду ниже, чтобы сделать это за вас. Просто замените тестовую строку «PASTE YOUR FULL APP.YML HERE» на ваш полный файл app.yml.
sudo -u root cat > /var/discourse/containers/app.yml <<\EOF
PASTE YOUR FULL APP.YML HERE
EOF
Запуск настройки Discourse
Запустите настройку Discourse без запросов с помощью команды ниже.
sudo -u yes "" | /var/discourse/./discourse-setup
Установка Discourse должна занять 10–15 минут.
Установка NGINX, WAF и GEOIP
Выполните обновление и установите предварительные требования
apt update -y
apt upgrade -y
apt -y install libpcre3-dev libssl-dev unzip build-essential daemon libxml2-dev libxslt1-dev libgd-dev libgeoip-dev zlib1g-dev libpcre3
Установите базу данных MaxMind, чтобы вы могли применять правила GEO IP в зависимости от местоположения. Вы можете использовать эту базу данных для маршрутизации или блокировки трафика в зависимости от местоположения. Теперь в логах NGINX будет отображаться страна пользователя, даже если вы не включите гео-блокировку. I
sudo add-apt-repository -y ppa:maxmind/ppa
apt update -y
apt install -y libmaxminddb0 libmaxminddb-dev mmdb-bin
Загрузка и извлечение NGINX и WAF NAXSI
Примечание: замените NGINX на последнюю версию
mkdir ~/nginx-waf
wget https://nginx.org/download/nginx-1.16.1.tar.gz -O ~/nginx-waf/nginx.tar.gz
tar xzf ~/nginx-waf/nginx.tar.gz -C ~/nginx-waf
wget https://github.com/nbs-system/naxsi/archive/master.zip -O ~/nginx-waf/waf.zip
unzip ~/nginx-waf/waf.zip -d ~/nginx-waf/
Клонирование модуля GEO IP2 для NGINX через Git
apt install -y git
git clone https://github.com/leev/ngx_http_geoip2_module.git /etc/ngx_http_geoip2_module
Компиляция NGINX
Мы создадим скрипт для выполнения этого за нас и запустим его ниже
cat > ~/nginx-waf/nginx-1.16.1/install.sh <<\EOF
cd ~/nginx-waf/nginx-1.16.1/
./configure --conf-path=/etc/nginx/nginx.conf --add-module=../naxsi-master/naxsi_src/ --error-log-path=/var/log/nginx/error.log --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-log-path=/var/log/nginx/access.log --http-proxy-temp-path=/var/lib/nginx/proxy --lock-path=/var/lock/nginx.lock --pid-path=/var/run/nginx.pid --user=www-data --group=www-data --with-http_ssl_module --without-mail_pop3_module --without-mail_smtp_module --without-mail_imap_module --without-http_uwsgi_module --add-dynamic-module=/etc/ngx_http_geoip2_module --without-http_scgi_module --prefix=/usr
make
make install
EOF
sh ~/nginx-waf/nginx-1.16.1/install.sh
Создание правил брандмауэра
Нижеприведенные правила по умолчанию включат WAF и заблокируют вредоносные запросы. Если вы хотите запустить WAF в режиме обучения, вы можете сделать это, добавив Learning Mode в файл правил ниже.
cp ~/nginx-waf/naxsi-master/naxsi_config/naxsi_core.rules /etc/nginx/
cat > /etc/nginx/naxsi.rules <<\EOF
SecRulesEnabled;
DeniedUrl "/RequestDenied";
## Проверка правил Naxsi
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
EOF
Создание файла конфигурации NGINX
По умолчанию в этом файле конфигурации гео-блокировка закомментирована, но вы можете раскомментировать и включить её, если хотите.
Примечание: сначала мы должны запустить NGINX БЕЗ SSL. Потому что нам нужно, чтобы certbot увидел живой домен. Мы получим SSL на следующем шаге и фактически скопируем новый файл конфигурации NGINX, чтобы заменить этот.
Примечание: замените cloudforums.net на ваш домен
cat > /etc/nginx/nginx.conf <<\EOF
#user nobody;
worker_processes 1;
load_module modules/ngx_http_geoip2_module.so;
events {
worker_connections 1024;
}
http {
include mime.types;
include /etc/nginx/naxsi_core.rules;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
geoip2 /etc/geo_ip/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_country_name source=$remote_addr country names en;
}
log_format main_geo '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$geoip2_data_country_code $geoip2_data_country_name';
access_log /var/log/nginx/access.log main_geo;
default_type application/octet-stream;
error_log /var/log/nginx/error.log;
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name cloudforums.net;
root /;
location /.well-known/acme-challenge/ {
root /var/www;
}
location / {
return 301 https://$host$request_uri;
include /etc/nginx/naxsi.rules;
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
EOF
Создание скрипта upstart для NGINX
Нам нужно создать скрипт для запуска службы NGINX.
cat > /etc/init.d/nginx <<\EOF
#! /bin/sh PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/sbin/nginx
NAME=nginx
DESC=nginx
test -x $DAEMON || exit 0
# Включите настройки nginx по умолчанию, если они доступны
if [ -f /etc/nginx ] ; then
. /etc/nginx
fi
set -e
case "$1" in
start)
echo -n "Запуск $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/nginx.pid \
--exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Остановка $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/nginx.pid \
--exec $DAEMON
echo "$NAME."
;;
restart|force-reload)
echo -n "Перезапуск $DESC: "
start-stop-daemon --stop --quiet --pidfile \
/var/run/nginx.pid --exec $DAEMON
sleep 1 start-stop-daemon --start --quiet --pidfile \
/var/run/nginx.pid --exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
reload)
echo -n "Перезагрузка конфигурации $DESC: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/nginx.pid \
--exec $DAEMON
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Использование: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
EOF
systemctl daemon-reload
Создание файла службы NGINX
cat > /lib/systemd/system/nginx.service <<\EOF
[Unit]
Description=Высокопроизводительный веб-сервер и сервер обратного прокси
Documentation=man:nginx(8)
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
Загрузка базы данных стран Geo IP
mkdir /etc/geo_ip
wget http://geolite.maxmind.com/download/geoip/database/GeoLite2-Country.mmdb.gz
gzip -d GeoLite2-Country.mmdb.gz
mv GeoLite2-Country.mmdb /etc/geo_ip/
Включение и запуск NGINX
systemctl stop apache2
systemctl daemon-reload
systemctl enable nginx
systemctl start nginx
Добавление SSL-сертификата для вашего домена
Не забудьте заменить cloudforums.net на ваш домен.com
mkdir /var/www
apt-get -y update
apt-get -y install letsencrypt
yes "n" | letsencrypt certonly --webroot --agree-tos -w /var/www -d cloudforums.net -m youremail@domain.com
Создание нового файла NGINX с правилами SSL
Создайте новый файл NGINX с вашим только что загруженным SSL-сертификатом.
Примечание: измените cloudforums.net на ваш домен
cat > /etc/nginx/nginx.conf <<\EOF
#user nobody;
worker_processes 1;
load_module modules/ngx_http_geoip2_module.so;
events {
worker_connections 1024;
}
http {
include mime.types;
include /etc/nginx/naxsi_core.rules;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
geoip2 /etc/geo_ip/GeoLite2-Country.mmdb {
$geoip2_data_country_code source=$remote_addr country iso_code;
$geoip2_data_country_name source=$remote_addr country names en;
}
log_format main_geo '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" '
'$geoip2_data_country_code $geoip2_data_country_name';
#***********************************************************
#Раскомментируйте для гео-блокировки. По умолчанию в настройках ниже только US
#***********************************************************
#map $geoip2_data_country_code $allowed_country {
# default no;
# US yes;
# }
access_log /var/log/nginx/access.log main_geo;
default_type application/octet-stream;
error_log /var/log/nginx/error.log;
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name cloudforums.net;
root /;
location /.well-known/acme-challenge/ {
root /var/www;
}
location / {
return 301 https://$server_name$request_uri;
include /etc/nginx/naxsi.rules;
root html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
server {
listen 443 ssl; listen [::]:443 ssl;
server_name cloudforums.net;
ssl on;
ssl_certificate /etc/letsencrypt/live/cloudforums.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/cloudforums.net/privkey.pem;
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
add_header Strict-Transport-Security "max-age=63072000;";
ssl_stapling on;
ssl_stapling_verify on;
client_max_body_size 0;
location / {
proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
proxy_set_header Host $http_host;
proxy_http_version 1.1;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Real-IP $remote_addr;
}
}
# HTTPS сервер
#
#server {
# listen 443 ssl;
# server_name localhost;
# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;
# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;
# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;
# location / {
# root html;
# index index.html index.htm;
# }
#}
}
EOF
Перезапуск NGINX
systemctl restart nginx
Теперь у вас есть потрясающий WAF с открытым исходным кодом!! ![]()
Бесстыдная реклама
Не забудьте присоединиться к нам на cloudforums.net, если вам понравилась эта инструкция. Мы очень рады видеть вас у нас. Мы ничего не продаем и не размещаем рекламу. Ищем только хороших участников IT-обсуждений ![]()
