Análisis de logs de ALB con Athena
Licencia: CC BY-SA 4.0 / Fuente: Wikimedia
Introducción
¿Qué es un ALB?
Si has mantenido algún proyecto en AWS es muy probable que estés familiarizado con los Application Load Balancer (ALB). Se trata de un servicio administrado de AWS que facilita un balanceador elástico que actúa como la capa de aplicación, es decir, la séptima capa del modelo de interconexión de sistemas abiertos (OSI). Es ampliamente utilizado junto a los grupos de autoscaling (ASG) para ofrecer un servicio web con alta disponibilidad.
Este servicio cuenta de forma opcional con un sistema de log, que por defecto viene deshabilitado. Para habilitarlo hay que indicarle un bucket de S3 donde se almacenarán los logs del acceso al balanceador. No es posible guardar dichos logs de entrada en ningún otro servicio, bien sea de AWS o exterior. Por lo tanto, para analizar dichos logs es necesario hacerlo directamente en S3, o bien, exportando los archivos generados. Estos logs quedan almacenados en pequeños ficheros comprimidos en GZIP cada uno con pocos minutos de trazas.
¿Por qué querrías analizarlos?
Pero, ¿Para qué nos sirven estos logs? En el log quedan reflejadas todas las peticiones procesadas por el balanceador, por lo tanto, es altamente útil para diagnosticar problemas en la aplicación web.
También nos puede servir para analizar el tráfico y detectar posibles comportamientos anómalos que puedan estar perjudicando el funcionamiento de la aplicación.
Estas trazas contienen multitud de información que puede llegar a ser muy útil. El formato completo de las trazas es el siguiente (se puede obtener más información en la documentación oficial):
- type time elb client_ip client_port target_ip target_port request_processing_time target_processing_time response_processing_time elb_status_code target_status_code received_bytes sent_bytes request_verb request_url request_proto user_agent ssl_cipher ssl_protocol target_group_arn trace_id domain_name chosen_cert_arn matched_rule_priority request_creation_time actions_executed redirect_url lambda_error_reason target_port_list target_status_code_list classification
Como hemos indicado, los logs se almacenan como ficheros de texto comprimidos con GZIP, así que, siempre podemos descargarlos y analizarlos de la forma que prefiramos.
AWS cuenta con una herramienta que nos facilita esta tarea y que nos permite llevar a cabo potentes análisis, se trata de Amazon Athena.
¿Qué es Amazon Athena?
Amazon Athena es un servicio de consultas interactivo que facilita el análisis de datos en Amazon S3 con SQL estándar.
Se trata de un servicio serverless para el que no hay que administrar infraestructura y en el que se paga por uso, es decir, por la cantidad de datos analizados por las consultas. Se puede obtener más información sobre el coste en este enlace.
Este servicio utiliza Presto, que es un query engine creado por Facebook inicialmente para realizar consultas de bigdata utilizando SQL sobre Hadoop. Posteriormente, se incluyó soporte para más fuentes de datos como MySQL, MongoDB y el caso que nos ocupa AWS S3.
Amazon Athena es altamente disponible y ejecuta consultas usando recursos de computación de varias instalaciones y numerosos dispositivos de cada instalación. Usa Amazon S3 como almacén de datos subyacente, por lo que sus datos tienen altos niveles de disponibilidad y durabilidad.
¿Cómo configurar Athena para analizar los logs de un ALB?
La configuración de Athena para el análisis de logs de ALB es muy simple. Empezamos creando una base de datos que contendrá nuestra tabla de análisis de logs. Para ello accedemos al editor de consultas de Athena y ejecutamos el comando de Hive data definition language (DDL) CREATE DATABASE con el nombre de base de datos que deseemos.
Lo siguiente es crear la tabla. Para ello, ejecutamos la siguiente sentencia en el editor de queries sustituyendo LOCATION 's3://your-alb-logs-directory/AWSLogs/<ACCOUNT-ID>/elasticloadbalancing/<REGION>/' con la información de nuestra cuenta:
CREATE EXTERNAL TABLE IF NOT EXISTS alb_logs (
type string,
time string,
elb string,
client_ip string,
client_port int,
target_ip string,
target_port int,
request_processing_time double,
target_processing_time double,
response_processing_time double,
elb_status_code int,
target_status_code string,
received_bytes bigint,
sent_bytes bigint,
request_verb string,
request_url string,
request_proto string,
user_agent string,
ssl_cipher string,
ssl_protocol string,
target_group_arn string,
trace_id string,
domain_name string,
chosen_cert_arn string,
matched_rule_priority string,
request_creation_time string,
actions_executed string,
redirect_url string,
lambda_error_reason string,
target_port_list string,
target_status_code_list string,
classification string,
classification_reason string
)
PARTITIONED BY (day STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.RegexSerDe'
WITH SERDEPROPERTIES (
'serialization.format' = '1',
'input.regex' =
'([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*):([0-9]*) ([^ ]*)[:-]([0-9]*) \
\([-.0-9]*) ([-.0-9]*) ([-.0-9]*) (|[-0-9]*) (-|[-0-9]*) \
\([-0-9]*) ([-0-9]*) \"([^ ]*) (.*) (- |[^ ]*)\" \"([^\"]*)\" \
\([A-Z0-9-_]+) ([A-Za-z0-9.-]*) ([^ ]*) \"([^\"]*)\" \
\\"([^\"]*)\" \"([^\"]*)\" ([-.0-9]*) ([^ ]*) \"([^\"]*)\" \
\\"([^\"]*)\" \"([^ ]*)\" \"([^\s]+?)\" \"([^\s]+)\" \
\\"([^ ]*)\" \"([^ ]*)\"'
)
LOCATION
's3://your-alb-logs-directory/AWSLogs/\
\<ACCOUNT-ID>/elasticloadbalancing/<REGION>/'
TBLPROPERTIES (
"projection.enabled" = "true",
"projection.day.type" = "date",
"projection.day.range" = "2022/01/01,NOW",
"projection.day.format" = "yyyy/MM/dd",
"projection.day.interval" = "1",
"projection.day.interval.unit" = "DAYS",
"storage.location.template" =
"s3://your-alb-logs-directory/AWSLogs/\
\<ACCOUNT-ID>/elasticloadbalancing/<REGION>/${day}"
)
Advertencia: Por formato está dividida la expresión regular y el path en múltiples líneas
Esta tabla utilizará proyección de particiones, ya que los registros de ALB tienen una estructura conocida, reduciendo así el tiempo de ejecución de las consultas y automatizando la administración de particiones.
En este punto ya podemos realizar consultas utilizando SQL en la nueva tabla que hemos creado con toda la información sobre los logs de nuestro ALB.
A continuación os mostramos algunos ejemplos útiles del tipo de consultas que se pueden hacer sobre los logs:
- Número de solicitudes HTTP GET que el balanceador de carga ha recibido agrupadas en función de la dirección IP del cliente:
SELECT COUNT(request_verb) AS
count,
request_verb,
client_ip
FROM alb_logs
GROUP BY request_verb, client_ip
LIMIT 10;
- Podemos analizar si hay posibles atacantes buscando vulnerabilidades en nuestra aplicación, por ejemplo, tratando de ejecutar ficheros php que no existen. Con la siguiente consulta obtenemos un conteo por IP:
SELECT client_ip, request_verb ,request_url, count(*) as count
from alb_logs
WHERE
request_url LIKE ‘%.php%’ AND elb_status_code = 404
GROUP by client_ip, request_verb ,request_url
ORDER by count DESC
LIMIT 10;
Advertencia: Por formato está dividida la expresión regular y el path en múltiples líneas
- Además de limitar el número de resultados con LIMIT, podemos acotar la fecha de los mismos de la siguiente manera:
SELECT client_ip, sum(received_bytes)
FROM alb_logs
WHERE parse_datetime(time,'yyyy-MM-dd''T''HH:mm:ss.SSSSSS''Z')
BETWEEN
parse_datetime(2022-06-30-06:00:00','yyyy-MM-dd-HH:mm:ss')
AND
parse_datetime(2022-06-30-10:00:00','yyyy-MM-dd-HH:mm:ss')
GROUP BY client_ip;
Advertencia: Por formato está dividida la expresión regular y el path en múltiples líneas
Estos son solo algunos ejemplos de lo que se puede extraer de los logs de un ALB mediante Athena.
Con conocimiento de SQL podemos obtener cantidad de información, ya sea para la solución de incidencias o para la mejora del servicio.