Problema

En entornos auto‑hosted es habitual exponer un reverse proxy (Nginx, Caddy, HAProxy, etc.) que recibe tráfico de todo internet. Los crawlers de IA, los bots de búsqueda y los rangos de IP de los proveedores cloud aparecen constantemente en los logs y pueden consumir recursos o generar falsos positivos en WAFs. Mantener listas manuales de “no permitir” o “permitir” es una tarea que se vuelve insostenible: los proveedores añaden o retiran bloques cada pocos días, y los CI/CD de terceros (CircleCI, TeamCity…) también usan rangos dinámicos. El síntoma típico es un aumento inesperado de errores 403/404, saturación de logs y, a veces, bloqueos de servicios legítimos porque la lista está desactualizada.

Causa

  1. Actualizaciones frecuentes de rangos IP – AWS, GCP, Azure, DigitalOcean, Cloudflare y otros publican sus CIDR cada 24‑48 h. Los scripts caseros que descargan un archivo estático quedan obsoletos rápidamente.
  2. Falta de normalización – Cada proveedor entrega los datos en formatos diferentes (JSON, CSV, texto plano). Unirlos manualmente genera errores de sintaxis y duplicados.
  3. Integración manual en firewalls – Copiar y pegar listas en archivos de configuración de Nginx o iptables implica reinicios innecesarios y riesgo de errores de orden.
  4. Ausencia de fallback offline – Cuando la red falla, los sistemas que dependen de una consulta HTTP a la lista remota dejan de bloquear correctamente.
  5. Escalabilidad de lookups – Consultas por cada IP del log usando grep o awk son lentas; los firewalls modernos (iptables/ipset, nftables) pueden manejar millones de entradas, pero requieren una carga previa eficiente.

Solución

Una arquitectura reutilizable se basa en tres capas:

  1. Fuente de datos automatizada – Un repositorio que, mediante GitHub Actions, descarga los rangos de cada proveedor, los convierte a un formato unificado (plain‑text v4/v6, JSON, CSV) y genera archivos de configuración listos para Nginx, iptables/ipset, nftables, HAProxy, Caddy y UFW.
  2. Librerías de lookup – Un módulo Go y otro JavaScript/TypeScript que cargan los CIDR en estructuras radix‑tree. Permiten consultas sub‑microsegundo, funcionan offline y pueden usarse dentro de scripts de auditoría o de generación de reglas dinámicas.
  3. Generador de reglas – Un script que, a partir de los archivos de la fuente, crea los conjuntos (ipset o nft set) y los incluye en la configuración del firewall o del proxy sin necesidad de reiniciar todo el servicio. El proceso se puede programar con cron o con el mismo workflow de CI.

Paso a paso práctico

  1. Clonar el repositorio – El proyecto mantiene una rama main con los archivos actualizados.
  2. Seleccionar el bundle – Los bundles predefinidos (all-clouds, all-ai-crawlers, all-ci) ya vienen mergeados y deduplicados.
  3. Generar ipset – El script generate_ipset.sh crea un conjunto llamado cloud_ips y lo rellena con los CIDR del bundle elegido.
  4. Incluir en Nginx – En la sección http se añade include /etc/nginx/conf.d/deny_clouds.conf; donde el archivo contiene deny por cada rango.
  5. Actualizar automáticamente – Un cron que ejecuta git pull && ./generate_ipset.sh && systemctl reload nginx garantiza que la lista nunca quede obsoleta.
  6. Uso de la librería Go – En aplicaciones que necesiten decidir en tiempo real si una IP pertenece a un cloud, basta con importar github.com/rezmoss/cloudipdb y llamar a Lookup(ip).
  7. Uso de la librería JS – En entornos Node o navegadores, import { lookup } from "cloudipdb" permite validar IPs sin depender de la red.

Cuándo aplicar esta solución

  • Entornos con tráfico mixto (público + interno) donde los bots representan más del 5 % del total de peticiones.
  • Servicios críticos detrás de un reverse proxy que no pueden permitirse downtime por listas de bloqueo desactualizadas.
  • Equipos que gestionan varios proveedores cloud y necesitan una única fuente de verdad para reglas de firewall.
  • CI/CD que requieren salida a internet y deben ser whitelistados sin abrir todo el rango 0.0.0.0/0.

No es necesario cuando:

  • El número de IPs a bloquear es estático y bajo (menos de 100 rangos).
  • Se usa un WAF SaaS que ya provee actualizaciones automáticas de listas de bots.

Código

# Clonar el repositorio oficial
git clone https://github.com/rezmoss/cloud-provider-ip-addresses.git
cd cloud-provider-ip-addresses

# Elegir el bundle que se va a usar (ejemplo: all-ai-crawlers)
BUNDLE=all-ai-crawlers

# Generar ipset llamado cloud_ips
./generate_ipset.sh $BUNDLE cloud_ips

# Verificar que el set contiene los CIDR esperados
ipset list cloud_ips | wc -l

# Recargar nginx (o cualquier otro servicio) sin reiniciar
systemctl reload nginx

Verificación

  1. Comprobar la existencia del setipset list cloud_ips debe mostrar cientos de CIDR sin errores de sintaxis.
  2. Test de bloqueo – Desde una máquina con una IP que pertenezca al bundle, intentar acceder al endpoint protegido; debería recibir 403 Forbidden.
  3. Log de Nginx – Buscar la cadena 403 y confirmar que la razón es deny por una IP del set.
  4. Actualización automática – Simular una nueva ejecución del workflow (por ejemplo, modificando un archivo en el repo) y observar que git pull trae cambios y que systemctl reload nginx se ejecuta sin interrupciones.

Notas adicionales

  • Persistencia de ipset – En distribuciones que no guardan los sets al reboot, añadir ipset save > /etc/ipset.conf y cargarlo en rc.local o mediante un servicio systemd.
  • Rendimiento – Un set de 2 M+ IPs consume ~150 MiB RAM; asegúrese de que el host tenga suficiente memoria antes de cargar todos los rangos simultáneamente.
  • Fallback offline – Las librerías Go/JS incluyen un archivo fallback.dat con los CIDR más comunes; es útil cuando la red está caída pero se necesita seguir bloqueando.
  • Extensión a IPv6 – El mismo proceso funciona para IPv6, solo hay que usar generate_ipset.sh $BUNDLE cloud_ips_v6 y habilitar ip6tables o nft con la familia inet.
  • Auditoría periódica – Ejecutar radix_lookup.py access.log permite identificar rápidamente qué rangos aparecen con mayor frecuencia y ajustar los bundles (por ejemplo, crear un custom-blocklist).

Con esta arquitectura se elimina la carga manual de listas, se garantiza que los firewalls y reverse proxies siempre trabajen con datos frescos y se consigue una solución que se adapta tanto a entornos Linux tradicionales como a pipelines de CI que requieren salida a la nube.