Продолжаем разбираться с 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 говорит, что допилят), поэтому поступим следующим образом:
- настроим Kinesis Firehouse
- настроим ACL на отправку данных в Kinesis
- Kinesis будет отправлять логи в AWS S3
- а затем настроим 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 или BLOCKruleGroupList
: все правила 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:
Готово.