AWS: WAF WebACL логи и Logz.io

Автор: | 07/21/2021
 

Продолжаем разбираться с AWS WAF. В посте AWS: обзор и настройка Web Application Firewall и его мониторинга ознакомились с основными компонентами, настроили ACL и Rules, подключили базовый мониторинг.

Там же настроили сбор логов WAF в AWS Kinesis, теперь хочется их увидеть в Logz.io, пока недоступен CloudWatch Logs.

В этом посте ещё раз настроим отправку логов в AWS S3 через AWS Kinesis, а затем настроим сбор логов из S3 в Logz.io, и разберёмся с содержимым логов.

AWS WAF logs

Кроме метрик и графиков CloudWatch, мы можем настроить сбор логов всех запросов, прошедших через наши ACL.

AWS WAF использует AWS Kinesis для отправки данных и AWS S3 для хранения логов.

Увы – но WAF и Kinesis не умеют слать логи в CloudWatch Logs (пока что – AWS говорит, что допилят), поэтому поступим следующим образом:

  1. настроим Kinesis Firehouse
  2. настроим ACL на отправку данных в Kinesis
  3. Kinesis будет отправлять логи в AWS S3
  4. а затем настроим Logz.io на сбор логов из корзины

AWS Kinesis

Note: One AWS WAF log is equivalent to one Kinesis Data Firehose record. If you typically receive 10,000 requests per second, set a 10,000 record per second limit in Kinesis Data Firehose to enable full logging.

Переходим в AWS Kinesis, создаём новый Data Firehose delivery stream, имя стрима должно начинаться на ‘aws-waf-logs-‘.

Выбираем Direct PUT or other sources, кликаем Next:

На следующей странице пропускаем трансформации, кликаем Next, далее для Destination выбираем S3, выбираем или создаём новую корзину:

Тут используем уже имеющуюся, а что бы логи не смешивались – добавим префикс:

Далее пока оставляем всё по-умолчанию, если что – Kinesis нам в CloudWatch сообщит о проблемах записи (так как настраиваем уже Production, и данных там будет много):

Для этого внизу оставляем включенным Error logging:

Проверяем настройки, и создаём стрим:

Ждём пару минут, пока стрим создаётся:

Или идём сразу в настройки ACL.

WAF ACL logging

Переходим к ACL, на вкладке Logging and metrics кликаем Enable logging:

Выбираем созданный выше стрим:

Тут же можем настроить исключения полей, которые будут добавлены в лог, и фильтры – какие именно запросы логгировать.

Logz.io S3 Bucket

Документация тут>>>.

Сначала нам потребуется создать IAM-политику и IAM-роль, которая будет предоставлять доступ к логам в этой корзине. См. документацию тут>>>.

Logz.io будет выполнять AssumeRole для получения прав на чтение из корзины.

Logz.io S3 configuration

Переходим в S3 Bucket, кликаем Add a bucket:

Выбираем Authenticate with a role:

Указываем имя корзины, кликаем Get the role policy:

IAM policy

Копируем содержимое, переходим в AWS IAM, создаём новую политику:

Вставляем JSON с описанием доступов:

Сохраняем политику:

IAM role

Переходим в IAM Roles, создаём новую роль.

Выбираем Another AWS account, указываем Account ID и External ID со страницы добавления S3 в Logz.io:

На странице Permissions подключаем созданную ранее политику:

И сохраняем роль:

В Trusted entities видим Account ID, который сможет выполнять Assume нашей роли.

Копируем ARN роли:

Возвращаемся к Logz.io – указываем ARN роли, и выбираем регион.

В типе данных выбираем other:

И указываем тип awswaf (см. все типы в документации тут>>>), что бы ELK могл правильно распарсить содержимое логов, которые приходят в формате JSON:

Кликаем Save, и корзина добавлена.

WAF logs – поля

Теперь осталось подключить ACL к ALB  дождаться трафика, что бы увидеть в логах запросы, попавшие под WAF ACL.

Подключаем ACL к Ingress – alb.ingress.kubernetes.io/wafv2-acl-arn:

И через несколько минут проверяем сначала S3 – появился каталог с заданными нами префиксом и годом, который добавлен уже самим Kinesis:

Первый файл лога:

Пару минут, и ждём его в Kibana.

ELK распарсит поля, и их можно использовать в поиске.

Тут подходят два – type: "awsfaw", что бы смотреть все логи, или webaclId, что бы найти лог конкретной ACL:

Из полей, которые полезны для вывода в таблице (см. все в документации тут>>>):

  • httpRequest.clientIp: откуда пришёл запрос
  • httpRequest.uri: URI запроса
  • httpRequest.args: аргументы запроса
  • terminatingRuleId: какое правило сработало последним на ALLOW или BLOCK
  • ruleGroupList: все правила ACL, которые были проверены для этого запроса

Посмотрим, что нам предоставляет лог.

Сначала обычный запрос, который был пропущен к приложению:

Тут с IP 99.***.***.101 пришёл запрос на URI /***/126/like, который был проверен в Rules из цепочки ruleGroupList, и к которому было применено Default_Action нашей ACL, т.е. Allow.

При этом в ruleGroupList видно, что одно из правил сработало – SignalNonBrowserUserAgent, но т.к. в ACL для самого правила действие установлено в Count, то срабатывание было проигнорировано:

А в поле terminatingRuleId видим срабатывание Default_Action, т.к. срабатывание на SignalNonBrowserUserAgent было исключено.

Если же запрос был блокирован – то в Default_Action увидим имя правила или группы, которое отправило запрос в Block:

Redacted fields – исключение данных из логов

В логах запросов могут приходить данные. которые в логах видеть не хочется совсем, например куки или токены аутентификации:

Что бы исключить их – переходим в настройки логгирования, и в Redacted fields выбираем поля, которые хотим исключить.

В данном случае это будет Headers, и в нём два поля – authorization и cookie:

Применяем, и теперь значений для заголовков в логе нет:

Logz.io alerting

Весьма полезно будет настроить отправку алертов.

Сделаем это через Logz.io интеграцию в Opsgenie, а Opsgenie будет слать нотификации в Slack.

Описываем условие алерта, в Filters добавим выборку по action != ALLOW:

Выбираем канал, куда слать алерты, и поля, которые хотим увидеть в сообщении:

И ждём алертов в Slack:

Готово.