Featured image of post Configuración de servidor proxy reverso en DMZ usando nginx

Configuración de servidor proxy reverso en DMZ usando nginx

NGINX es un servidor web usado en varios escenarios, uno de los cuales es el de aprox reverso (reverse proxy). La principal funcionalidad de un proxy reverso es recibir las solicitudes web (u otros protocolos) de clientes desde una zona en red no segura (DMZ u otras) y reenviar las solicitudes a un servidor ubicado en una ubicación segura y con controles (Intranet).

Con nginx como proxy reverso se pueden mitigar riesgos de seguridad, implementar controles de seguridad y limitar el tipo/numero de conexiones en caso de ataques DoS o DDoS.

Prerequisitos:

  • Servidor web en una red interna (IIS, Apache, nginx, etc)
  • Servidor con acceso a la red DMZ y a la red interna
  • Instalación de Ubuntu 16.04 en la máquina virtual (recomendable con servidor SSH para realizar gestión remota)
  1. Instalación de servidor nginx

    Para instalar nginx en Ubuntu se usa el siguiente comando:

    1
    
    sudo apt install nginx
    

    Una vez instalado se procede a realizar la configuración del servicio de proxy reverso.

  2. Configuración de nginx

    La configuración de sitios nginx se realiza principalmente con los archivos que se encuentran en las carpetas /etc/nginx/sites-available/ y /etc/nginx/sites-enabled/

    En la carpeta /etc/nginx/sites-available/ se crean los archivos con los sitios que se encuentran disponibles, y en la carpeta /etc/nginx/sites-enabled/ normalmente se crean enlaces simbólicos que apuntan a los sitios que queremos habilitar de la carpeta /etc/nginx/sites-available/

    Para configurar un sitio web ejemplo.com que sea proxy reverso hacia un servidor interno con ip ip_srv_interna (10.0.0.2) se realiza la creación de archivo ejemplo.com:

    1
    2
    3
    4
    5
    6
    7
    
    server {
    listen 80; #Puerto de escucha
    server_name ejemplo.com; #Nombre o IP de servidor
        location / {
        proxy_pass http://10.0.0.2:80;
    }
    }
    

    Podemos verificar que el archivo de configuración sea correcto con el comando:

    1
    2
    3
    
    sudo nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    

    Si aparece un mensaje como el siguiente:

    1
    2
    
    nginx: [emerg] invalid parameter "server_name" in /etc/nginx/sites-enabled/ejemplo.com:6
    nginx: configuration file /etc/nginx/nginx.conf test failed
    

    Debemos verificar que el archivo en la linea 6 o cercanas a esta tenga las configuraciones correctas.

    Una vez tenemos listo el archivo de configuración del sitio, se crea el enlace simbólico en la carpeta de sitios habilitados

    1
    
    sudo ln -s /etc/nginx/sites-available/ejemplo.com /etc/nginx/sites-enabled/ejemplo.com
    

    Con esto ya podemos realizar una recarga del servicio y comprobar que funcione nuestro proxy reverso:

    1
    
    sudo systemctl reload nginx
    
  3. Habilitar firewall

    Dado que el servidor estará expuesto hacia Internet, es recomendable realizar la activación el Firewall. Si bien existen distintos métodos en Linux, últimamente las principales distribuciones se han decantado en usar herramientas para gestionar Firewall, firewalld en distribuciones basadas en Red Hat y ufw en distribuciones basadas en Ubuntu.

    Para instalar la herramienta de gestión del Firewall en Ubuntu se usa el siguiente comando:

    1
    
    sudo apt install ufw
    

    Una vez instalada se usa el siguiente comando para habilitarlo:

    1
    
    sudo ufw enable
    

    Se puede verificar el estado del Firewall las reglas con el siguiente comando:

    1
    
    sudo ufw status verbose
    

    Para habilitar el servicio web (http y https):

    1
    
    sudo ufw allow http
    

    Como tenemos habilitado el servicio SSH, es recomendable limitar el acceso desde una sub red o una tarjeta de red específica, en este caso se limitará el acceso para equipos en la sub red 10.0.0.0/8 normalmente usada para redes internas y restringirá el acceso desde otras redes, como Internet.

    1
    2
    
    sudo ufw allow from 10.0.0.0/8 to any port 22
    sudo ufw deny ssh
    

    Luego, configuramos las acciones por defecto de las conexiones, bloqueando todas las entrantes y habilitando las salientes con excepción de las reglas antes creadas:

    1
    2
    3
    4
    5
    6
    7
    
    sudo ufw default allow outgoing
    Default outgoing policy changed to 'allow'
    (be sure to update your rules accordingly)
    
    sudo ufw default deny incoming
    Default incoming policy changed to 'deny'
    (be sure to update your rules accordingly)
    

    Verificamos el estado de las reglas de nuevo:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    sudo ufw status verbose
    
    Status: active
    Logging: on (low)
    Default: deny (incoming), allow (outgoing), disabled (routed)
    New profiles: skip
    
    To Action From
    -- ------ ----
    22 ALLOW IN 10.0.0.0/8
    80 ALLOW IN Anywhere
    22 DENY IN Anywhere
    80 (v6) ALLOW IN Anywhere (v6)
    22 (v6) DENY IN Anywhere (v6)
    
  4. Realizar configuraciones reforzamiento de seguridad y otras a nginx

    Si bien el proxy reverso ya es funcional, es posible realizar configuraciones adicionales para mitigar ataques de diverso tipo, enviar información del cliente hacia el servidor web interno para que sea más transparente el funcionamiento y ubicar los logs del sitio en una ruta específica.

    Teniendo en cuenta esto, se modificará el archivo ejemplo.com con las configuraciones deseadas.

    En los archivos de configuración de nginx se realizan comentarios usando el símbolo numeral (o como se ha nombrado tanto en estos días, hastag) #.

    A continuación se muestra el archivo ejemplo.com con distintas configuraciones y su descripción:

    1
    
    sudo nano /etc/nginx/sites-enabled/ejemplo.com
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
    limit_conn_zone $binary_remote_addr zone=addr:10m; #Espacio en memoria reservado para la zona
    
    server {
    listen 80; #Puerto de escucha
    server_name ejemplo.com; #Nombre de servidor
    client_body_timeout 15s; #Timeout de maximo de conexiones a body 15 segundos para luego cerrar sesion para evitar ataques Slowloris
    client_header_timeout 15s; #Timeout de maximo de conexiones a header 15 segundos para luego cerrar sesion para evitar ataques Slowloris
    
    access_log /var/log/nginx/ejemplo.access.log; #Log de accesos a servidor
    location / {
        limit_conn addr 25; #Limitar el numero de conexiones simultaneas desde una IP a 25 evitando ataques DoS
        proxy_pass http://10.0.0.2:80;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        #deny 8.8.8.8 #Denegar acceso de IPs que puedan estar realizando ataques de DDoS
        }
    }
    

    Una vez se tengan todos los cambios deseados, se realiza de nuevo la recarga del servicio de nginx.

    1
    
    sudo systemctl reload nginx
    

    Para realizar la prueba se puede ingresar desde un navegador a la IP pública o el dominio http://ejemplo.com, se mostrará la respuesta web del servidor interno proporcionada a través de nginx.

    También se puede comprobar la respuesta de header del servidor usando el comando curl, donde se evidencia que el servidor que esta entregando las respuestas es el servidor de proxy reverso nginx:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    curl -I -k http://ejemplo.com/
    HTTP/1.1 200 OK
    Server: nginx/1.10.0 (Ubuntu)
    Date: Fri, 17 Mar 2017 14:47:55 GMT
    Content-Type: text/html
    Content-Length: 701
    Connection: keep-alive
    Last-Modified: Fri, 10 Mar 2017 20:58:39 GMT
    Accept-Ranges: bytes
    ETag: "326cc417e198d21:0"
    
  5. Habilitar el Control de Acceso Obligatorio Mandatory Access Control (MAC), AppArmor

    Es posible asegurar aun más nuestro proxy reverso usando AppArmor, el cual restringe el acceso de archivos a los servicios evitando casos en los que se reciban ataques a nginx usando vulnerabilidades y que las mismas no incidan en otros servicios del sistema salvo por nginx. En distribuciones basadas en Red Hat se encuentra una plataforma similar para asegurar procesos llamada SELinux, aunque con objetivos similares su configuración es completamente distinto.

    Ubuntu viene con AppArmor instalado y habilitado por defecto. Sin embargo se requieren algunas herramientas y perfiles de ejemplo para crear un perfil de aseguramiento para nginx, las mismas se instalan de la siguiente manera:

    1
    
    sudo apt-get install apparmor-utils
    

    Se crea un perfil de AppArmor para nginx con los siguientes comandos

    1
    2
    
    cd /etc/apparmor.d/
    sudo aa-autodep nginx
    

    Habilitar perfil en modo de registro, esto para que se generen registros de los archivos que ha requerido nginx para su funcionamiento

    1
    
    sudo aa-complain nginx
    

    Realizar reinicio del servicio de nginx y hacer uso del servicio ingresando a http://ejemplo.com desde un navegador, para que el registro de AppArmor detecte los archivos que usa el servicio cuando esta en ejecución.

    1
    
    sudo systemctl restart nginx
    
  6. Ingresar desde un navegador a ejemplo.com

    Luego de que se AppArmor ha tomado registro de los archivos que se han requerido, se usa el siguiente comando para que el sistema modifique el perfil autorizando el acceso a los hallazgos, esto se realiza con la tecla A en cada una de las preguntas de solicitud de permisos.

    1
    
    sudo aa-logprof
    

    Esto se puede hacer debido a que el servicio esta en funcionamiento normal y no recibe ataques, de lo contrario es recomendable realizar revisión de cada uno de los permisos que se solicitan. Este es un ejemplo de archivo de perfil generado

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    # Last Modified: Fri Mar 17 12:28:11 2017
    #include <tunables/global>
    
    /usr/sbin/nginx flags=(complain) {
    #include <abstractions/base>
    #include <abstractions/lxc/container-base>
    /etc/group r,
    /etc/nginx/conf.d/ r,
    /etc/nginx/mime.types r,
    /etc/nginx/nginx.conf r,
    /etc/nginx/sites-enabled/ r,
    /etc/nsswitch.conf r,
    /etc/passwd r,
    /etc/ssl/openssl.cnf r,
    /usr/sbin/nginx mr,
    /var/log/nginx/error.log w,
    }
    

    Si se requiere se puede editar el perfil de forma manual con el comando:

    1
    
    sudo nano /etc/apparmor.d/usr.sbin.nginx
    

    Se realiza la recarga del servicio AppArmor y se reinicia nginx, con esto se tendrá el servicio asegurado por AppArmor.

    1
    2
    
    sudo /etc/init.d/apparmor reload
    sudo systemctl restart nginx
    

    Se puede comprobar su funcionamiento verificando que nginx esta siendo controlado con el siguiente comando:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    
    sudo apparmor_status
    
    apparmor module is loaded.
    13 profiles are loaded.
    12 profiles are in enforce mode.
    /sbin/dhclient
    /usr/bin/lxc-start
    /usr/lib/NetworkManager/nm-dhcp-client.action
    /usr/lib/NetworkManager/nm-dhcp-helper
    /usr/lib/connman/scripts/dhclient-script
    /usr/lib/lxd/lxd-bridge-proxy
    /usr/lib/snapd/snap-confine
    /usr/lib/snapd/snap-confine//mount-namespace-capture-helper
    lxc-container-default
    lxc-container-default-cgns
    lxc-container-default-with-mounting
    lxc-container-default-with-nesting
    1 profiles are in complain mode.
    /usr/sbin/nginx
    3 processes have profiles defined.
    0 processes are in enforce mode.
    3 processes are in complain mode.
    /usr/sbin/nginx (2369)
    /usr/sbin/nginx (2370)
    /usr/sbin/nginx (2371)
    0 processes are unconfined but have a profile defined.
    

El alcance de esta guía es para un servicio web que no usa TLS (SSL), por lo que se requieren pasos adicionales para realizar el montaje de un proxy reverso seguro usando certificados.

Si tienen dudas, o si tienen sugerencias para mejorar algún aspecto de seguridad no duden en comentar!

Fuentes:

Built with Hugo
Theme Stack designed by Jimmy