No tengo permiso para publicar en la sección de Cómo hacer, así que lo publicaré aquí ![]()
Resumen
El objetivo es agregar un WAF a los recursos existentes manteniendo el rendimiento en una instalación pequeña. En este ejemplo, utilizaremos una única instancia de EC2. Dado que Discourse se ejecuta en Docker, podemos instalar NGINX en el host y usar proxy_pass para redirigir el tráfico hacia nuestro contenedor Docker. También estamos utilizando RDS para PostgreSQL.
Configuración de Discourse
Nuestro primer paso es configurar nuestro archivo app.yml para una instalación personalizada de Discourse. En este ejemplo, ejecutaremos los roles web y redis. No utilizaremos el rol de base de datos ni el de SSL.
También queremos asegurarnos de no exponer los puertos web en el contenedor Docker. La razón es que expondremos nuestra web a través del proxy NGINX en el host.
Ejemplo de archivo app.yml
## este es la plantilla del contenedor Docker Discourse todo en uno, independiente
##
## Después de realizar cambios en este archivo, DEBES reconstruir
## /var/discourse/launcher rebuild app
##
## TEN *MUCHO* CUIDADO AL EDITAR!
## ¡LOS ARCHIVOS YAML SON SUPER SUPER SENSIBLES A ERRORES EN LOS ESPACIOS EN BLANCO O EN LA ALINEACIÓN!
## visita http://www.yamllint.com/ para validar este archivo según sea necesario
templates:
- "templates/redis.template.yml"
- "templates/web.template.yml"
- "templates/web.ratelimited.template.yml"
- "templates/web.socketed.template.yml"
## Descomenta estas dos líneas si deseas agregar Lets Encrypt (https)
#- "templates/web.ssl.template.yml"
#- "templates/web.letsencrypt.ssl.template.yml"
## ¿qué puertos TCP/IP debe exponer este contenedor?
## Si deseas que Discourse comparta un puerto con otro servidor web como Apache o nginx,
## consulta https://meta.discourse.org/t/17247 para obtener detalles
expose:
# - "80:80" # http
# - "443:443" # https
params:
db_default_text_search_config: "pg_catalog.english"
## Establece db_shared_buffers a un máximo del 25% de la memoria total.
## se establecerá automáticamente por bootstrap según la RAM detectada, o puedes sobrescribirlo
db_shared_buffers: "768MB"
## puede mejorar el rendimiento de ordenación, pero añade uso de memoria por conexión
#db_work_mem: "40MB"
## ¿Qué revisión de Git debe usar este contenedor? (por defecto: tests-passed)
#version: tests-passed
env:
LANG: en_US.UTF-8
# DISCOURSE_DEFAULT_LOCALE: en
## ¿Cuántas solicitudes web concurrentes se admiten? Depende de la memoria y los núcleos de CPU.
## se establecerá automáticamente por bootstrap según los CPUs detectados, o puedes sobrescribirlo
UNICORN_WORKERS: 2
## TODO: El nombre de dominio al que responderá esta instancia de Discourse
## Requerido. Discourse no funcionará con una dirección IP desnuda.
DISCOURSE_HOSTNAME: cloudforums.net
## Descomenta si deseas que el contenedor se inicie con el mismo
## nombre de host (opción -h) que se especificó anteriormente (por defecto "$hostname-$config")
#DOCKER_USE_HOSTNAME: true
## TODO: Lista de correos electrónicos separados por comas que serán administradores y desarrolladores
## en el registro inicial, ejemplo 'usuario1@dominio.com,usuario2@dominio.com'
DISCOURSE_DEVELOPER_EMAILS: 'tuemail@dominio.com'
## TODO: El servidor de correo SMTP utilizado para validar nuevas cuentas y enviar notificaciones
## Se requieren dirección SMTP, nombre de usuario y contraseña
## ¡ADVERTENCIA: el carácter '#' en la contraseña SMTP puede causar problemas!
DISCOURSE_SMTP_ADDRESS: TU_SMTP
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: TU_USUARIO_SMTP
DISCOURSE_SMTP_PASSWORD: TU_CONTRASEÑA_SMTP
#DISCOURSE_SMTP_ENABLE_START_TLS: true # (opcional, por defecto true)
## Si agregaste la plantilla de Lets Encrypt, descomenta a continuación para obtener un certificado SSL gratuito
#LETSENCRYPT_ACCOUNT_EMAIL: me@ejemplo.com
DISCOURSE_DB_SOCKET: ''
DISCOURSE_DB_USERNAME: TU_USUARIO
DISCOURSE_DB_PASSWORD: TU_CONTRASEÑA
DISCOURSE_DB_HOST: TU_HOST
## La dirección CDN http o https para esta instancia de Discourse (configurada para extraer)
## consulta https://meta.discourse.org/t/14857 para obtener detalles
#DISCOURSE_CDN_URL: https://discourse-cdn.ejemplo.com
## El contenedor Docker es sin estado; todos los datos se almacenan en /shared
volumes:
- volume:
host: /var/discourse/shared/standalone
guest: /shared
- volume:
host: /var/discourse/shared/standalone/log/var-log
guest: /var/log
## Los plugins van aquí
## consulta https://meta.discourse.org/t/19157 para obtener detalles
hooks:
after_code:
- exec:
cd: $home/plugins
cmd:
- git clone https://github.com/discourse/docker_manager.git
## Cualquier comando personalizado para ejecutar después de la compilación
run:
- exec: echo "Inicio de comandos personalizados"
## Si deseas establecer la dirección de correo electrónico 'De' para tu primer registro, descomenta y cambia:
## Después de recibir el primer correo de registro, vuelve a comentar la línea. Solo necesita ejecutarse una vez.
- exec: rails c "SiteSetting.enable_badge_sql = true"
- exec: echo "Fin de comandos personalizados"
Comenzar la instalación de Discourse
Clonar el repositorio de Discourse
sudo -u root git clone https://github.com/discourse/discourse_docker.git /var/discours
Copiar app.yml personalizado para la instalación
Puedes ejecutar el siguiente comando para hacerlo por ti. Solo reemplaza el texto “PEGA AQUÍ TU app.yml COMPLETO” con tu archivo app.yml completo.
sudo -u root cat > /var/discourse/containers/app.yml <<\EOF
PEGA AQUÍ TU app.yml COMPLETO
EOF
Ejecutar la configuración de Discourse
Inicia la configuración de Discourse sin preguntas utilizando el siguiente comando.
sudo -u yes "" | /var/discourse/./discourse-setup
Discourse debería tardar de 10 a 15 minutos en instalarse.
Instalación de NGINX, WAF y GEOIP
Ejecuta las actualizaciones e instala los prerequisitos
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
Instala la base de datos MaxMind DB para poder ejecutar reglas GEO IP basadas en la ubicación. Puedes usar esta base de datos para enrutar o bloquear el tráfico según la ubicación. Nuestros registros de NGINX ahora mostrarán el país del usuario, incluso si no activas el bloqueo geográfico. I
sudo add-apt-repository -y ppa:maxmind/ppa
apt update -y
apt install -y libmaxminddb0 libmaxminddb-dev mmdb-bin
Descargar y extraer NGINX y NAXSI WAF
Nota: Reemplaza NGINX con la versión más reciente
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/
Clonar el módulo GEO IP2 para NGINX
apt install -y git
git clone https://github.com/leev/ngx_http_geoip2_module.git /etc/ngx_http_geoip2_module
Compilar NGINX
Crearemos un script para hacer esto por nosotros y lo ejecutaremos a continuación.
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
Crear reglas del firewall
La configuración predeterminada a continuación activará el WAF y bloqueará las solicitudes maliciosas. Si deseas ejecutar el WAF en modo de aprendizaje, puedes hacerlo agregando Modo de aprendizaje al archivo de reglas a continuación.
cp ~/nginx-waf/naxsi-master/naxsi_config/naxsi_core.rules /etc/nginx/
cat > /etc/nginx/naxsi.rules <<\EOF
SecRulesEnabled;
DeniedUrl "/RequestDenied";
## Verificar reglas de Naxsi
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
EOF
Crear archivo de configuración de NGINX
Por defecto, en este archivo de configuración, el bloqueo geográfico está comentado, pero puedes descomentar y activarlo si lo deseas.
Nota: Debemos ejecutar NGINX SIN SSL al principio. Porque necesitamos que certbot vea un dominio activo. Obtendremos SSL en un paso posterior y en realidad copiaremos un nuevo archivo de configuración de NGINX para reemplazar este uno
Nota: Reemplaza cloudforums.net con tu nombre de dominio
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
Crear script upstart para NGINX
Necesitamos crear un script para que el servicio NGINX se inicie.
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 valores predeterminados de nginx si están disponibles
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 "Deteniendo $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 "Recargando la configuración de $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
Crear archivo de servicio NGINX
cat > /lib/systemd/system/nginx.service <<\EOF
[Unit]
Description=Un servidor web de alto rendimiento y un servidor proxy inverso
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
Descargar base de datos de países 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/
Habilitar e iniciar NGINX
systemctl stop apache2
systemctl daemon-reload
systemctl enable nginx
systemctl start nginx
Agregar certificado SSL para tu dominio
No olvides reemplazar cloudforums.net con tu dominio.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 tuemail@dominio.com
Crear nuevo archivo NGINX con reglas SSL
Crea un nuevo archivo NGINX con tu certificado SSL que acabas de descargar.
Nota: cambia cloudforums.net por tu dominio
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';
#***********************************************************
#Descomenta para hacer bloqueo geográfico. Por defecto solo está configurado para EE. UU. en la configuración a continuación
#***********************************************************
#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
¡Ahora tienes un WAF de código abierto increíble!! ![]()
Publicidad descarada
Asegúrate de unirte a nosotros en cloudforums.net si disfrutaste esta guía. Realmente nos encantaría tenerte aquí. No vendemos nada ni tenemos anuncios. Solo buscamos buenas publicaciones de TI ![]()
