BLOG | NGINX

Solicitudes de muestreo con registro condicional de NGINX

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Owen Garrett
Owen Garrett
Publicado el 24 de abril de 2019

NGINX puede registrar un registro muy detallado de cada transacción que procesa. Estos registros se conocen como registros de acceso y puede ajustar los detalles que se registran para diferentes servicios o ubicaciones con un formato de archivo de registro personalizable.

De forma predeterminada, NGINX registra cada transacción que procesa. Esto puede ser necesario por motivos de cumplimiento o seguridad, pero para un sitio web con mucha actividad, el volumen de datos generados puede ser abrumador. En este artículo, mostramos cómo registrar transacciones de forma selectiva según diversos criterios y cómo utilizar ese conocimiento para muestrear puntos de datos sobre solicitudes de una manera rápida y sencilla.

Salvo que se indique lo contrario, esta publicación se aplica tanto a NGINX Open Source como a NGINX Plus. Para facilitar la lectura, haremos referencia a NGINX en todo momento.

Antecedentes: descripción general rápida de la configuración del registro de acceso de NGINX

Los registros de acceso de NGINX se definen mediante la directiva log_format . Puede definir varios formatos de registro con nombre diferentes; por ejemplo, un formato de registro completo llamado main y un formato de registro abreviado llamado notes para registrar tres puntos de datos sobre una solicitud:

log_format main '$dirección_remota - $usuario_remoto [$tiempo_local] "$solicitud" '
'$estado $bytes_del_cuerpo_enviados "$referencia_http" '
'"$agente_usuario_http" "$http_x_reenviado_para"';

log_format notes '$dirección_remota "$solicitud" $estado';

El formato de registro puede hacer referencia a variables NGINX y otros valores calculados en el momento del registro.

Luego, utiliza la directiva access_log para indicarle a NGINX que registre una transacción una vez que se complete. Esta directiva especifica la ubicación del archivo de registro y el formato de registro a utilizar:

registro_de_acceso /var/log/nginx/access.log principal;

De forma predeterminada, NGINX registra todas las transacciones utilizando la siguiente configuración:

access_log registros/access.log combinados;

Si define su propio access_log, éste anula (reemplaza) el registro de acceso predeterminado.

Registro condicional

A veces es posible que desees registrar solo ciertas solicitudes. Esto se hace mediante el registro condicional, de la siguiente manera:

servidor {
escuchar 80;

establecer $logme 0;
si ( $uri ~ ^/secure ) {
establecer $logme 1;
}

# Los auditores requieren un registro adicional para las solicitudes a /secure
access_log /var/log/nginx/secure.log notas if=$logme;

# Si tenemos un registro de acceso global, debemos volver a declararlo aquí
access_log /var/log/nginx/access.log main;

ubicación / {
# ...
}
}

Los registros de acceso no se heredan

Las configuraciones del registro de acceso no se acumulan ni heredan; una directiva access_log en un contexto anula (reemplaza) los registros de acceso declarados en los contextos principales.

Por ejemplo, si desea registrar información adicional sobre el tráfico a la URI /secure , puede definir un registro de acceso en un bloque location /secure {...} . Este registro de acceso reemplaza el registro de acceso general definido en otra parte de la configuración.

El ejemplo de la sección anterior aborda este problema. Utiliza dos registros de acceso en el mismo contexto, con registro condicional que registra las solicitudes de /secure en un archivo de registro dedicado.

Desafíos con los registros de acceso

Supongamos que desea determinar alguna información estadística sobre el tráfico a su sitio web:

  • ¿Cuál es la distribución geográfica típica de los usuarios?
  • ¿Qué cifrados y protocolos SSL/TLS utilizan mis usuarios?
  • ¿Cuál es la división de navegadores web?

El registro de acceso general a menudo no es el lugar adecuado para registrar esta información. Es posible que no desee contaminar el registro de acceso con campos adicionales necesarios para su estudio y, en un sitio con mucha actividad, los costos adicionales de registrar todas las transacciones serían demasiado altos.

En este caso, puede registrar un conjunto limitado de campos en un registro especializado. Para reducir la carga en el sistema, es posible que también desees muestrear un subconjunto de solicitudes.

Técnicas de muestreo

Muestreo del 1% de las solicitudes

La siguiente configuración utiliza la variable $request_id como identificador único para cada solicitud. Utiliza un bloque split_clients para muestrear datos registrando solo el 1 % de las solicitudes:

split_clients $request_id $logme {
1% 1;
* 0;
}

servidor {
list 80;

access_log /var/log/nginx/secure.log notas if=$logme;

# ...
}

Muestreo del 1% de usuarios únicos

Supongamos que deseamos muestrear un punto de datos de cada usuario (o del 1% de los usuarios), como el encabezado User-Agent . No podemos simplemente tomar muestras de todas las solicitudes porque los usuarios que generan una gran cantidad de solicitudes quedan sobrerrepresentados en nuestros datos.

Utilizamos un bloque de mapa para detectar la presencia de una cookie de sesión, que nos indica si una solicitud proviene de un nuevo usuario o de un usuario que hemos visto antes. A continuación, tomamos muestras de las solicitudes que provienen únicamente de usuarios nuevos:

map $cookie_SESSION $logme {
"" $perhaps; # Si falta la cookie, registramos if $perhaps
default 0;
}

split_clients $request_id $perhaps {
1% 1; # $perhaps es verdadero el 1% del tiempo
* 0;
}

server {
list 80;

access_log /var/log/nginx/secure.log notes if=$logme;

# Opcional: Si la aplicação no genera una cookie de sesión, nosotros
# generar nuestro propio
add_header Establecer-Cookie SESIÓN=1;

# ...
}

Muestreo de cosas únicas

Sin embargo, no todos los clientes aceptan las cookies de sesión. Por ejemplo, una araña web podría ignorar las cookies, por lo que cada solicitud que emite se identifica como proveniente de un nuevo usuario, sesgando nuestros resultados.

¿No sería fantástico si pudiéramos tomar muestras de las solicitudes cuando es la primera vez que vemos algo nuevo? El problema puede ser una nueva dirección IP, un nuevo valor de cookie de sesión, un nuevo encabezado de agente de usuario , un encabezado de host no visto antes o incluso una combinación de estos. De esta manera, tomamos muestras de datos de cada cosa solo una vez.

Claramente, necesitamos almacenar el estado (una lista de las cosas que hemos visto), y para esto recurrimos al almacén de clave-valor de NGINX Plus. El almacén de valores clave mantiene una base de datos de valores clave en memoria a la que se puede acceder desde la configuración de NGINX Plus mediante variables; la base de datos admite opcionalmente la expiración automática de entradas (el parámetro de tiempo de espera ), el almacenamiento persistente ( estado ) y la sincronización de clústeres ( sincronización ). Para cada cosa que aún no esté en la tienda, registramos la solicitud y agregamos la cosa a la tienda para que no se registre nuevamente.

En NGINX Plus R18 y versiones posteriores, es muy fácil establecer pares clave-valor mientras se procesa una transacción :

# Defina una zona keyval con los parámetros adecuados: keyval_zone zone=clients:80m timeout=3600s;

# Cree una variable $seen para cada $remote_addr única
keyval $remote_addr $seen zone=clients;

log_format notes '$remote_addr "$request" $status';

server {
list 80;

# Si $seen está vacío, actualice el keyval (establezca $seen en 1;) y registre esto.
# request (establezca $logme en 1;)
# De lo contrario, $logme no se establece y no se registra la solicitud.
# Tenga en cuenta que $seen se restablece a "" después del tiempo de espera configurado.
if ($seen = "") {
set $seen 1;
set $logme 1;
}
access_log /var/log/nginx/secure.log notes if=$logme;

ubicación / {
devuelve 200 "Todo OK: -$visto-$registrarme-\n";
}

ubicación /api {
api;
}
}

Un ejemplo del mundo real: muestreo de parámetros TLS

Este artículo se inspiró en un problema del mundo real: ¿cómo puedo configurar TLS según las buenas prácticas sin excluir a los usuarios con dispositivos heredados?

La mejor práctica de TLS es un objetivo en movimiento. TLS 1.3 se ratificó hace un año, pero muchos clientes solo aceptan versiones anteriores de TLS; los cifrados se declaran "inseguros" y se retiran, pero las implementaciones más antiguas dependen de ellos; los certificados ECC ofrecen un mayor rendimiento que RSA, pero no todos los clientes pueden aceptar ECC. Muchos ataques TLS se basan en un "intermediario" que intercepta el protocolo de negociación del cifrado y obliga al cliente y al servidor a seleccionar un cifrado menos seguro. Por lo tanto, es importante configurar NGINX Plus para que no admita cifrados débiles o heredados, pero hacerlo podría excluir a los clientes heredados.

En el siguiente ejemplo de configuración, muestreamos cada cliente TLS, registrando el protocolo SSL, el cifrado y el encabezado User-Agent . Suponiendo que cada cliente selecciona los protocolos más recientes y los cifrados más seguros que admite, podemos evaluar los datos muestreados y determinar qué proporción de clientes quedan excluidos si eliminamos el soporte para protocolos y cifrados más antiguos.

Identificamos a cada cliente por su combinación única de dirección IP y User-Agent , pero identificar a los clientes por cookie de sesión u otro método funciona igual de bien.

log_format sslparams '$ssl_protocol $ssl_cipher '
'$remote_addr "$http_user_agent"';

# Definir una zona keyval con los parámetros adecuados
keyval_zone zone=clients:80m timeout=3600s;

# Crear una variable $seen para cada combinación única de $remote_addr y
# encabezado 'User-Agent'
keyval $remote_addr:$http_user_agent $seen zone=clients;

server {
list 443 ssl;

# Configuración SSL predeterminada de NGINX
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

if ($seen = "") {
set $seen 1; establecer $logme 1;
}
acceso_registro /tmp/sslparams.log sslparams if=$logme;

# ...
}

Esto genera un archivo de registro con entradas como la siguiente:

TLSv1.2 AES128-SHA 1.1.1.1 "Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0"
TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 2.2.2.2 "Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 como Mac OS X) AppleWebKit/601.1.46 (KHTML, como Gecko) Versión/9.0 Mobile/13B143 Safari/601.1"
TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 3.3.3.3 "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 4.4.4.4 "Mozilla/5.0 (Android 4.4.2; Tableta; versión rv:65.0) Gecko/65.0 Firefox/65.0"
TLSv1 AES128-SHA 5.5.5.5 "Mozilla/5.0 (Android 4.4.2; Tableta; versión rv:65.0) Gecko/65.0 Firefox/65.0"
TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 6.6.6.6 "Mozilla/5.0 (Linux; U; Android 5.0.2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, como Gecko) Versión/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"

Luego podemos procesar el archivo utilizando una variedad de métodos para determinar la distribución de los datos:

$ cat /tmp/sslparams.log | cortar -d ' ' -f 2,2 | ordenar | uniq -c | ordenar -rn | perl -ane 'printf "%30s %s\n", $F[1], "="x$F[0];' ECDHE-RSA-AES128-GCM-SHA256 ========================== ECDHE-RSA-AES256-GCM-SHA384 ======== AES128-SHA ==== ECDHE-RSA-CHACHA20-POLY1305 == ECDHE-RSA-AES256-SHA384 ==

Identificamos los cifrados de bajo volumen y menos seguros, verificamos los registros para determinar qué clientes los están usando y luego tomamos una decisión informada sobre la eliminación de los cifrados de la configuración de NGINX Plus.

CONCLUSIÓN

El registro condicional de NGINX se puede utilizar para muestrear un subconjunto de las solicitudes que NGINX administra y escribir un registro estándar o de propósito especial. Esta técnica es útil si alguna vez necesita tomar una muestra rápida de tráfico para realizar un análisis estadístico, como por ejemplo para determinar la propagación de los parámetros SSL.

Debes pensar bien cómo muestrear los datos para que los usuarios ocupados o las arañas no estén sobrerrepresentados. Puede utilizar variables en la configuración de NGINX, junto con las directivas map y split_clients , para seleccionar y filtrar solicitudes.

Para situaciones donde la decisión es más compleja o donde se desea un alto nivel de confianza en la precisión, puede crear selectores sofisticados en la configuración de NGINX. El almacén de clave-valor de NGINX Plus le permite acumular estado y compartirlo entre instancias de NGINX Plus en un clúster si es necesario.

Pruebe usted mismo la solicitud de muestreo con NGINX Plus: comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos de uso.


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.