viernes, 3 de enero de 2025

Nginx (II) Autenticación LDAP(I). Sustituir NGINX por openresty. Luaroks y Lua script

1. Introducción

Openresty es un nginx que lleva incorporado Lua, que es un lenguaje de script para Nginx creado por la Universidad Católica Pontificia de Rio de Janeiro en Brasil que es rápido y utiliza pocos recursos.

2. Instalación de openresty

Veamos los pasos a realizar según Cloudspinx:

#1. Bloquear nginx
sudo systemctl disable nginx
sudo systemctl stop nginx

#2. Instalar prerequisitos
sudo apt-get -y install --no-install-recommends wget gnupg ca-certificates lsb-release

#3. Importar la clave GPG de descarga (para Ubuntu 22 +)
wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty.gpg

#4. Añadir el repositorio en sistemas x86_64 or amd64 para Ubuntu 22 +
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/openresty.gpg] http://openresty.org/package/ubuntu $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/openresty.list > /dev/null

#5. Actualizar el índice APT
sudo apt-get update

#6. Instalar el paquete
sudo apt-get -y install openresty

#6.1. Aquí da un error de que el puerto 80 está ocupado
#     Por tanto hay que entrar en /usr/local/openresty/nginx/conf/nginx.conf
#     y cambiar "listen       80;" 
#           por "listen       8080;" u otro puerto que no esté pillado
#     y volver a ejecutar :
#     sudo apt-get -y install openresty


#7. Verificar la instalación que debe devolver: nginx version: openresty/X.Y.Z
openresty -v

#8. Arrancar/rearrancar/ para rel servicio
sudo systemctl start openresty
sudo systemctl restart openresty
sudo systemctl stop openresty

#9. Permitir el servicio al arrancar (boot)
sudo systemctl enable openresty

#10. Ver el estado del servicio
sudo systemctl status openresty


Ojo, ahora el fichero de configuración esta en una de estas 2 carpetas:
  • /etc/openresty
  • /usr/local/openresty

Y los logs están en:

  • /usr/local/openresty/nginx/logs/error.log


4. Instalación de luarocks 

Luarocks es un paquete de instación de módulos Lua para openresty

Para instalarlo hacemos:

# 1.Prerequisitos
sudo apt install build-essential libreadline-dev unzip

# 2. Descargar
wget https://luarocks.org/releases/luarocks-3.11.1.tar.gz

# 3. Descomprimir
tar zxpf luarocks-3.11.1.tar.gz

# 4. Compilar e instalar 
cd luarocks-3.11.1
sudo ./configure && make && sudo make install
sudo luarocks install luasocket
lua

# Debe de aparecer
Lua 5.4.7  Copyright (C) 1994-2024 Lua.org, PUC-Rio

Veamos algunos usos de luarocks

# 1.Instalar paquetes.
# En este caso instala el paquete lua-python para poder ejecutar modulos python
sudo luarocks install lua-resty-http

sudo luarocks install lua-resty-openssl

sudo luarocks install lua-resty-iputils

# 2. Ver los módulos instalados
luarocks list

# Devuelve
Rocks installed for Lua 5.1
---------------------------
lua-resty-http
   0.17.2-0 (installed) - /usr/local/lib/luarocks/rocks-5.1
lua-resty-iputils
   0.3.0-2 (installed) - /usr/local/lib/luarocks/rocks-5.1
lua-resty-lrucache
   0.09-2 (installed) - /usr/local/lib/luarocks/rocks-5.1
lua-resty-maxminddb
   1.3.4-1 (installed) - /usr/local/lib/luarocks/rocks-5.1
lua-resty-openssl
   1.5.2-1 (installed) - /usr/local/lib/luarocks/rocks-5.1
luasocket
   3.1.0-1 (installed) - /usr/local/lib/luarocks/rocks-5.1

5. Lua script


Con Lua se pueden generar scripts de :
  • Autenticación con JWT, LDAP o OAuth2
  • Enrutamiento (Routing) dinámico basado en headers, cookies o contenido del body del request
  • Caching Personalizado
  • Rate limiting. Contruir lógica rate-limiting basada en IP, user agent (navegador), etc
  • Transformación del contenido para generar respuestas dinámicas (compresión, conversión, etc)
  • API Gateways como validación de request, filtrado de respuestas i logging (bitácora)
OJO: Los comentarios en lua se encabezan con "--" y no con "#" (como nginx)

En Lua hay varios módulos que podemos instalar (y algunos ya vienen instalados)

  • ngx_lua: Core module for embedding Lua in OpenResty.
  • lua-resty-core: Standard Lua library optimized for OpenResty.
  • lua-resty-http: Make HTTP requests from within OpenResty.
  • lua-resty-jwt: Validate and decode JSON Web Tokens (JWT).
  • lua-resty-redis: Connect to Redis for caching or session management.

Veamos algunos ejemplos de Lua como contenido dinámico y enrutado dinámico

server {
    listen 8080;

    #1. Creación de contenido.
    #   Cuando se accede a http://localhost:8080/hello:
    #   devuelve "Hello Word"
    location /hello {
        content_by_lua_block {
            ngx.say("Hello, World!")
        }
    }
    
    #2. Redirección dinámica en base al navegador (si es "curl" u otro)
    #   Cuando se accede a http://localhost:8080/route:
    #   te envía a http://localhost:8080/for-curl si operas en "curl"
    #   y sinó te envia a http://localhost:8080/for-browser 
    
    location /route {
        content_by_lua_block {
            local user_agent = ngx.var.http_user_agent
            if user_agent and user_agent:find("curl") then
                ngx.redirect("/for-curl", 302)
            else
                ngx.redirect("/for-browser", 302)
            end
        }
    }
}

Veamos un caso concreto que opera con autenticación JWT.  Aquí cabe destacar la clave secreta "your_jwt_secret", el control de las cabeceras o header

server {
    listen 8080;

    location /protected {
        access_by_lua_block {
            -- Importamos el módulo lua-resty-jwt que debe estar previamente instalado
            local jwt = require "resty.jwt"
            local auth_header = ngx.var.http_Authorization

            if not auth_header or not auth_header:find("Bearer ") then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say("Missing or invalid Authorization header")
                return ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end

            local token = auth_header:sub(8)  -- Remove "Bearer "
            --- "your_jwt_secret" es la clave secreta para verificar la firma del token
            local jwt_obj = jwt:verify("your_jwt_secret", token)

            if not jwt_obj.verified then
                ngx.status = ngx.HTTP_UNAUTHORIZED
                ngx.say("Unauthorized: " .. (jwt_obj.reason or "unknown reason"))
                return ngx.exit(ngx.HTTP_UNAUTHORIZED)
            end
        }

     content_by_lua_block {
            ngx.say("Access Granted!")
        }
    }
}

Para llamar con curl usando JWT se puede hacer con curl y dando un Bearer con el  token JWT:

curl http://localhost:8080/protected -H "Authorization: Bearer <your-jwt-token>"


Vewamos 

1. Introducción

 Se puede utilizar el módulo adicional ngx_http_auth_request_module, pero se necesita una versión de nginx precompilada con este módulo adicional. Para Ubuntu se podría instalar nginx-extras. Pero da muchos problemas. Para ello se ha optado por configurar nginx para que uilizando fastCGI consulte un script python para autenticar usuarios sobre LDAP. 

Supongamos que ya tenemos instalado python y un entorno virtual. Instalaremos pues nginx y fcgiwrap

# 1. Instalar paquetes requeridos
sudo apt update
sudo apt install nginx fcgiwrap

# 2. Verificar la versión de nginx instalada (en este caso 1.24.0 (Ubuntu) 
nginx -v

# 3. Como curisidad si queremos mostra los módulos instalados en nginx
nginx -V 2>&1|xargs -n1|grep module

2. Configurar fcgiwrap

Ejecutar

# 1. Arrancar el sercicio
sudo systemctl enable fcgiwrap
sudo systemctl start fcgiwrap

# 2. Verificar el servicio
systemctl status fcgiwrap


3. Crear el script python de un fake autenticathor

Veamos este código propuesto por ChatGPT. 
Observar que la primera línea es el "shebang" que indica el intérprete que va utilizar para ejecutarlo. En este caso, utilizamos el python3 que se encuenttra en el entorno virtual creado
Si le pasamos admin + secret nos deja pasar

#!/home/edu/MyPython/05.fasthtml/env05/bin/python3
import os
import cgi

print("Content-Type: text/plain\n")

# Simulated authentication logic
form = cgi.FieldStorage()
username = form.getvalue("username")
password = form.getvalue("password")

if username == "admin" and password == "secret":
    print("Authentication successful")
else:
    print("Authentication failed")

Hay que dar permiso de ejecución a todo el mundo

sudo chmod +x /home/edu/MyPython/05.fasthtml/basicutils/xmlogin.py


2. Configurar nginx

Según CHATGPT esto sirve: para el fichero /etc/nginx/nginx.conf 

http {
    
    server {
        listen 8001;
        server_name localhost;

        location /auth {
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME /home/edu/MyPython/05.fasthtml/basicutils/xmlogin.py;
    fastcgi_pass unix:/var/run/fcgiwrap.socket;
} } }

Y aclara:

Explicación de la configuración:

  • ldap_server my_ldap_server:

    • Define un servidor LDAP con el nombre my_ldap_server.
    • url: Especifica la URL del servidor LDAP. En este caso,                               ldap://municipio-dc-03.edificio.municipio:389.
      • dc=edificio,dc=municipio: Indica la base de búsqueda en el árbol LDAP.
      • ?uid: Especifica el atributo de búsqueda del usuario (generalmente uid o cn).
      • ?sub: Define el alcance de la búsqueda (sub para buscar recursivamente en subárboles).
      • (objectClass=person): Filtro para encontrar objetos LDAP que representan usuarios.
  • binddn y binddn_passwd:

    • Credenciales usadas por Nginx para consultar el servidor LDAP.
  • auth_ldap y auth_ldap_servers:

    • Habilita la autenticación LDAP en el bloque de ubicación.

3. Proteger rutas específicas

En este ejemplo, solo las solicitudes al directorio /protected requieren autenticación LDAP. Si la autenticación es exitosa, el usuario puede acceder; de lo contrario, se muestra un desafío de autenticación.


Pruebas y solución de problemas

  1. Revisar los logs:

    • Logs de acceso: /var/log/nginx/access.log
    • Logs de error: /var/log/nginx/error.log
  2. Asegurar conectividad con el servidor LDAP:

    • Probar la conexión desde el servidor donde está Nginx (escribiendo en una sola línea):
ldapsearch -H 
   ldap://municipio-dc-03.edificio.municipio 
   -D "cn=Ximo Dante,ou=SISTEMAS,ou=USUARIOS IMPORTANTES,dc=edificio,dc=municipio" 
   -w "mi_contraseña" 
   -b "dc=edificio,dc=municipio"

Supongamos que 

  1. Depurar errores comunes:

    • Credenciales incorrectas
      • Revisar binddn sobre todo no dejarse ningún OU ni DC ni por supuesto el CN. Para ello hemos ejecutado en Windows :  dsquery user -name "Ximo Dante"
      • Revisar binddn_passwd.
    • URL LDAP incorrecta: Verificar que el servidor LDAP y la base DN sean correctos.

Conclusión

Usar LDAP con Nginx es posible con el módulo adecuado, como ngx_http_auth_ldap_module o la solución comercial de Nginx Plus. Este enfoque permite autenticar usuarios centralmente mediante un servidor LDAP, lo cual es útil en entornos empresariales.





 

----------------------------------------------------------------------------------------

1. Introducción

Se puede utilizar el módulo adicional ngx_http_auth_request_module, pero se necesita una versión de nginx precompilada con este módulo adicional. Para Ubuntu se podría instalar nginx-extras pero da problemas. Para ello utilizamos una ruta alternativa, compilando el módulo

sudo apt install nginx-extras #DA PROBLEMAS PUES NO RECONOCE EL SERVICIO LDAP

sudo apt update
sudo apt upgrade 

# Install requiered packages
sudo apt install build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev git

# Download nginx versison 1.27.3
wget http://nginx.org/download/nginx-1.27.3.tar.gz
tar -xzvf nginx-1.27.3.tar.gz
cd nginx-1.27.3

# Clone LDAP Module
git clone https://github.com/kvspb/nginx-auth-ldap.git

# Configure Nginx with the LDAP Module
./configure --add-module=./nginx-auth-ldap --with-http_ssl_module --with-http_v2_module

# Compile and Install Nginx:
make
sudo make install

# Verify Installation: Check the installed Nginx binary for the LDAP module:
/usr/local/nginx/sbin/nginx -V





No hay comentarios :

Publicar un comentario