Não tenho permissão para postar em ‘How-Tos’, então vou postar isso aqui ![]()
Visão Geral
O objetivo é adicionar um WAF (Web Application Firewall) aos recursos existentes, mantendo o desempenho em uma instalação pequena. Neste exemplo, usaremos uma única instância EC2. Como o Discourse é executado em Docker, podemos instalar o NGINX no host e usar o proxy pass para direcionar o tráfego para nosso contêiner Docker. Também estamos usando o RDS para o PostgreSQL.
Configuração do Discourse
Nosso primeiro passo é configurar o arquivo app.yml para uma instalação personalizada do Discourse. Neste exemplo, executaremos os roles web e redis. Não usaremos o role DB nem os roles SSL.
Também queremos garantir que não exponhamos as portas web no contêiner Docker. O motivo é que vamos expor nossa web através do proxy NGINX no host.
Exemplo de arquivo app.yml
## este é o modelo de contêiner Docker Discourse all-in-one, standalone
##
## Após fazer alterações neste arquivo, você DEVE reconstruir
## /var/discourse/launcher rebuild app
##
## TENHA *MUITO* CUIDADO AO EDITAR!
## ARQUIVOS YAML SÃO SUPER SUPER SENSÍVEIS A ERROS DE ESPAÇAMENTO OU ALINHAMENTO!
## visite http://www.yamllint.com/ para validar este arquivo conforme necessário
templates:
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
- "templates/web.socketed.template.yml"
## Descomente estas duas linhas se desejar adicionar o Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
## quais portas TCP/IP este contêiner deve expor?
## Se você deseja que o Discourse compartilhe uma porta com outro servidor web como Apache ou nginx,
## consulte https://meta.discourse.org/t/17247 para detalhes
expose:
# - "80:80" # http
# - "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
## Defina db_shared_buffers para no máximo 25% da memória total.
## será definido automaticamente pelo bootstrap com base na RAM detectada, ou você pode substituir
db_shared_buffers: "768MB"
## pode melhorar o desempenho de ordenação, mas aumenta o uso de memória por conexão
#db_work_mem: "40MB"
## Qual revisão do Git este contêiner deve usar? (padrão: tests-passed)
#version: tests-passed
env:
LANG: en_US.UTF-8
# DISCOURSE_DEFAULT_LOCALE: en
## Quantas solicitações web concorrentes são suportadas? Depende da memória e dos núcleos da CPU.
## será definido automaticamente pelo bootstrap com base nas CPUs detectadas, ou você pode substituir
UNICORN_WORKERS: 2
## TODO: O nome de domínio ao qual esta instância do Discourse responderá
## Obrigatório. O Discourse não funcionará com um número IP puro.
DISCOURSE_HOSTNAME: cloudforums.net
## Descomente se quiser que o contêiner seja iniciado com o mesmo
## nome de host (opção -h) especificado acima (padrão "$hostname-$config")
#DOCKER_USE_HOSTNAME: true
## TODO: Lista de e-mails delimitados por vírgula que serão feitos administradores e desenvolvedores
## no cadastro inicial, exemplo 'user1@example.com,user2@example.com'
DISCOURSE_DEVELOPER_EMAILS: 'youremail@domain.com'
## TODO: O servidor de e-mail SMTP usado para validar novas contas e enviar notificações
## ENDEREÇO SMTP, nome de usuário e senha são obrigatórios
## AVISO: o caractere '#' na senha SMTP pode causar problemas!
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 # (opcional, padrão true)
## Se você adicionou o modelo Lets Encrypt, descomente abaixo para obter um certificado SSL gratuito
#LETSENCRYPT_ACCOUNT_EMAIL: me@example.com
DISCOURSE_DB_SOCKET: ''
DISCOURSE_DB_USERNAME: YOUR_USERNAME
DISCOURSE_DB_PASSWORD: YOUR_PASSWORD
DISCOURSE_DB_HOST: YOUR_HOST
## O endereço HTTP ou HTTPS do CDN para esta instância do Discourse (configurado para buscar)
## consulte https://meta.discourse.org/t/14857 para detalhes
#DISCOURSE_CDN_URL: https://discourse-cdn.example.com
## O contêiner Docker é sem estado; todos os dados são armazenados em /shared
volumes:
- volume:
host: /var/discourse/shared/standalone
guest: /shared
- volume:
host: /var/discourse/shared/standalone/log/var-log
guest: /var/log
## Plugins vão aqui
## consulte https://meta.discourse.org/t/19157 para detalhes
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/docker_manager.git
## Quaisquer comandos personalizados para executar após a construção
run:
- exec: echo "Início dos comandos personalizados"
## Se você quiser definir o endereço de e-mail 'De' para seu primeiro cadastro, descomente e altere:
## Após receber o primeiro e-mail de cadastro, comente novamente a linha. Só precisa ser executado uma vez.
- exec: rails c "SiteSetting.enable_badge_sql = true"
- exec: echo "Fim dos comandos personalizados"
Iniciar Instalação do Discourse
Clonar Repositório do Discourse
sudo -u root git clone https://github.com/discourse/discourse_docker.git /var/discours
Copiar app.yml personalizado para a Instalação
Você pode executar o comando abaixo para fazer isso por você. Basta substituir o texto “PASTE YOUR FULL APP.YML HERE” pelo seu app.yml completo.
sudo -u root cat > /var/discourse/containers/app.yml <<\EOF
PASTE YOUR FULL APP.YML HERE
EOF
Executar Configuração do Discourse
Inicie a configuração do Discourse sem prompts usando o comando abaixo.
sudo -u yes "" | /var/discourse/./discourse-setup
O Discourse deve levar de 10 a 15 minutos para instalar.
Instalação do NGINX, WAF e GEOIP
Execute atualizações e instale pré-requisitos
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
Instale o banco de dados MaxMind para que você possa executar regras GEO IP com base na localização. Você pode usar este banco de dados para rotear ou bloquear tráfego com base na localização. Nossos logs do NGINX agora mostrarão o país do usuário, mesmo que você não ative o bloqueio geográfico.
sudo add-apt-repository -y ppa:maxmind/ppa
apt update -y
apt install -y libmaxminddb0 libmaxminddb-dev mmdb-bin
Baixar e extrair NGINX e WAF NAXSI
Nota: Substitua NGINX pela versão mais recente
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/
Clone o módulo GEO IP2 para o NGINX via Git
apt install -y git
git clone https://github.com/leev/ngx_http_geoip2_module.git /etc/ngx_http_geoip2_module
Compilar NGINX
Vamos criar um script para fazer isso por nós e executá-lo abaixo
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
Criar Regras de Firewall
O padrão abaixo ativará o WAF e bloqueará solicitações maliciosas. Se você quiser executar o WAF no modo de aprendizado, pode fazer isso adicionando Learning Mode ao arquivo de regras abaixo.
cp ~/nginx-waf/naxsi-master/naxsi_config/naxsi_core.rules /etc/nginx/
cat > /etc/nginx/naxsi.rules <<\EOF
SecRulesEnabled;
DeniedUrl "/RequestDenied";
## Verificar regras do Naxsi
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
EOF
Criar arquivo de configuração do NGINX
Por padrão, neste arquivo de configuração, o bloqueio geográfico está comentado, mas você pode descomentar e ativar se desejar.
Nota: Devemos executar o NGINX SEM SSL inicialmente. Porque precisamos que o certbot veja um domínio ativo. Obteremos o SSL em uma etapa posterior e, na verdade, copiaremos um novo arquivo de configuração do NGINX para substituir este.
Nota: Substitua cloudforums.net pelo seu nome de domínio
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
Criar script upstart para o NGINX
Precisamos criar um script para que o serviço NGINX seja iniciado.
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
# Incluir padrões do nginx se disponíveis
if [ -f /etc/nginx ] ; then
. /etc/nginx
fi
set -e
case "$1" in
start)
echo -n "Iniciando $DESC: "
start-stop-daemon --start --quiet --pidfile /var/run/nginx.pid \
--exec $DAEMON -- $DAEMON_OPTS
echo "$NAME."
;;
stop)
echo -n "Parando $DESC: "
start-stop-daemon --stop --quiet --pidfile /var/run/nginx.pid \
--exec $DAEMON
echo "$NAME."
;;
restart|force-reload)
echo -n "Reiniciando $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 "Recarregando configuração $DESC: "
start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/nginx.pid \
--exec $DAEMON
echo "$NAME."
;;
*)
N=/etc/init.d/$NAME
echo "Uso: $N {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
EOF
systemctl daemon-reload
Criar arquivo de serviço do NGINX
cat > /lib/systemd/system/nginx.service <<\EOF
[Unit]
Description=Um servidor web de alto desempenho e um servidor proxy reverso
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
Baixar Banco de Dados Geo IP Country
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/
Ativar e Iniciar NGINX
systemctl stop apache2
systemctl daemon-reload
systemctl enable nginx
systemctl start nginx
Adicionar certificado SSL para seu domínio
Não se esqueça de substituir cloudforums.net pelo seu domínio.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
Criar novo arquivo NGINX com regras SSL
Crie um novo arquivo NGINX com o certificado SSL que você acabou de baixar.
Nota: altere cloudforums.net para o seu domínio
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';
#***********************************************************
#Descomente para fazer o bloqueio geográfico. O padrão é apenas EUA nas configurações abaixo
#***********************************************************
#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;
}
}
# Servidor 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
Reiniciar NGINX
systemctl restart nginx
Agora você tem um WAF de código aberto incrível!! ![]()
Propaganda Desavergonhada
Certifique-se de se juntar a nós em cloudforums.net se você gostou deste guia. Adoraríamos ter você aqui. Não vendemos nada nem temos anúncios. Apenas procuramos boas postagens de TI ![]()
