Hola Visitante

Autor Tema: Shaping con Iptables: Limitando CPS  (Leído 73 veces)

Berni69

  • Administrator
  • *****
  • Mensajes: 33
    • Ver Perfil
Shaping con Iptables: Limitando CPS
« en: Septiembre 07, 2018, 10:33:16 pm »

Buenas noches, después de mucho tiempo sin pasarme por aquí, esta noche os traigo una pequeña entrada para ver como se puede configurar un rate limiting (shaping) en función de las conexiones por segundo en lugar del por ancho de banda (bandwidth).


Durante el transcurso de esta semana, me han consultado si se podría limitar el consumo de una API REST de un proveedor externo a priori no debería ser mucho problema, cuando te piden esto lo primero que piensas es en limitar el ancho de banda consumido en un packetshaper/firewall aplicando políticas de QoS. Pero esta vez, se solicitó que se limitara por transacciones por segundo permitidas. Tras revisarlo con los compañeros nunca habíamos montado nada así por lo que me he dispuesto a investigar un poco más y he llegado la solución que os contaré en este post.


En la siguiente imagen se describe la arquitectura inicial, en el recuadro rojo se muestra que existen N instancias de una aplicación que competirán por 10 conexiones por segundo contra la API externa (verde).





Por definición las aplicaciones intentan usar todos los recursos que pueden para llevar a cabo su cometido lo más rápido posible.


La arquitectura propuesta para poder limitar realizar el rate-limiting de salida contra la API externa, pasa por montar un proxy HTTP (en este caso squid pero valdría cualquier proxy http/https) que tenga visibilidad sobre todas las conexiones que se realizan a la API y en él crear una política de de connection_tracking con Iptables. De este modo la arquitectura quedaría de la siguiente forma:



Para hacer la prueba de concepto he montado 3 máquinas linux con Centos 7 (1GB de RAM cada una y dos núcleos deberían sobrar para la prueba). A partir de ahora las máquinas recibirán el nombre:

























Nombre del ServidorIPDescripción
shaper0110.112.112.101Squid + Iptables
webserver0110.112.112.102Servidor web con nginx
server0110.112.112.106Envío de tráfico

Para simplificar configuraciones, y la lectura de los scripts se han hecho 2 suposiciones.



  1. Tenemos acceso privilegiado a la máquina (sudo -i) o similar.

  2. En el archivo de hosts (/etc/hosts) de cada máquina se ha añadido lo siguiente:
    10.112.112.101 shaper01
    10.112.112.102 webserver01
    10.112.112.106 server01



En el servidor webserver01, he instalado un nginx de prueba para que nos sirva contenido estático y poder ver sus logs:


yum install epel-release
yum install nginx
systemctl enable nginx
systemctl start nginx

En el servidor shaper01 he instalado squid y iptables:



yum install epel-release -y
yum install iptables-services -y
yum -y install squid
echo "cache deny all" >> /etc/squid/squid.conf
systemctl restart iptables squid
systemctl enable iptables squid

En este punto Iptables estan bloqueando todo el tráfico por defecto por que en los siguientes comandos, voy a resetear estos parámetros (no lo hagáis así si ya está instalado y tiene reglas por configuradas):



iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
iptables -t nat -F
iptables -t mangle -F
iptables -F
iptables -X

El siguiente paso es configurar las reglas para limitar el número de conexiones por segundo:



iptables --new-chain RATE-LIMIT
iptables --append INPUT  --match conntrack --ctstate NEW --jump RATE-LIMIT
iptables --append RATE-LIMIT \
    --match hashlimit \
    --hashlimit-mode dstip \
    --hashlimit-upto 10/sec \
    --hashlimit-burst 9 \
    --hashlimit-name conn_rate_limit \
    --jump ACCEPT
iptables --append RATE-LIMIT --jump REJECT

Con este comando creamos una nueva “cadena” en iptables que se ejecutará cuando haya una nueva conexión y no haya hecho match con ninguna regla existente.

Explicación del comando:



  1. match hashlimit: Tipo de plugin de iptables que se aplicará en este caso hashlimit (variación avanzada del módulo de limits)

  2. hashlimit-mode dstip: Permite agrupar los (CPS) por ip de destino, origen,..  

  3. hashlimit-upto 10/sec: Número de conexiones máximas por unidad de tiempo

  4. hashlimit-burst 9: Ráfaga máxima soportada

  5. hashlimit-name conn_rate_limit: Nombre con el que guardara la información internamente

  6. jump REJECT: Acción por omisión permite hacer ACCEPT/DROP/REJECT. Se ha creado con reject porque avisa al origen de que no es posible establecer la conexión. Si se hiciera con DROP la aplicación quedaría esperando hasta obtener un TimeOut ralentizando mucho el proceso de captura de errores y reintentos.


En el servidor server01, se ha configurado el un curl para que use nginx y vaya haciendo peticiones:



export http_proxy="http://shaper01:3128"
export https_proxy="http://shaper01:3128"
while [ 1 ]; do curl webserver01 -s > /dev/null; done

Si todo ha ido bien en el nginx deberíamos ver logs como el siguiente:



10.112.112.101 - - [07/Sep/2018:19:49:58 +0000] "GET / HTTP/1.1" 200 3700 "-" "curl/7.29.0" "10.112.112.106"

Para comprobar que está funcionando correctamente, he lanzado el while con el curl en el server01 sin haber activado las iptables y tras un tiempo he ejecutado los comandos para hacer el rate-limiting. Tras esto he analizado el fichero de log de nginx con algo de ayuda de bash y excel:



cat access.log  | cut -d " " -f 4 | uniq -c
      3 [07/Sep/2018:21:03:12
     74 [07/Sep/2018:21:03:13
     74 [07/Sep/2018:21:03:14
     74 [07/Sep/2018:21:03:15
     75 [07/Sep/2018:21:03:16
     75 [07/Sep/2018:21:03:17
     75 [07/Sep/2018:21:03:18
     74 [07/Sep/2018:21:03:19
     74 [07/Sep/2018:21:03:20
     74 [07/Sep/2018:21:03:21
     74 [07/Sep/2018:21:03:22
     75 [07/Sep/2018:21:03:23
     74 [07/Sep/2018:21:03:24
     75 [07/Sep/2018:21:03:25
     74 [07/Sep/2018:21:03:26
     75 [07/Sep/2018:21:03:27
     75 [07/Sep/2018:21:03:28
      9 [07/Sep/2018:21:03:29
     11 [07/Sep/2018:21:03:46
     10 [07/Sep/2018:21:03:47
     10 [07/Sep/2018:21:03:48
     10 [07/Sep/2018:21:03:49
     10 [07/Sep/2018:21:03:50
     10 [07/Sep/2018:21:03:51
      8 [07/Sep/2018:21:03:52
      8 [07/Sep/2018:21:03:53
     10 [07/Sep/2018:21:03:54
     10 [07/Sep/2018:21:03:55
     10 [07/Sep/2018:21:03:56
     10 [07/Sep/2018:21:03:57
     10 [07/Sep/2018:21:03:58

Si graficamos la información, se observa claramente el momento dónde he activado el rate-limiting:


Espero que os resulte de utilidad o almenos entretenida la lectura.