AWS VPC Flow Logs позволяет логгировать инфомрацию о трафике между сетевыми интерфейсами в VPC. Далее, эти логи могут быть сохранены в AWS S3 или отправлены в AWS CloudWatch Logs, при этом включение логгирования трафика никак не виляет на производительность работы сетевого интерфейса.
Кратко рассмотрим основные понятия, доступные настройки и настроим Flow Logs для VPC с передачей данных для анализа в CloduWatch Logs.
Содержание
Описание VPC Flow Logs
Логи могут быть включены для целой VPC, для подсети, или конкретного интерфейса. При включении для всей VPC – логгирование будет включено для всех сетевых интерфейсов.
Сервисы, для которых можно использовать Flow Logs:
- Elastic Load Balancing
- Amazon RDS
- Amazon ElastiCache
- Amazon Redshift
- Amazon WorkSpaces
- NAT gateways
- Transit gateways
Данные записываются как flow log records и представляют собой запись с заданными полями.
Use Cases – примеры использования
Что можно отслеживать с помощью Flow logs?
- срабатывания правил SecuirtyGroup/Network Access List – заблокированные запросы будут отмечены как REJECTED
- то, ради чего логи внедряем мы – получить картину трафика между VPC и сервисами, что бы понять кто больше всего трафика потребляет, где и сколько cross-AZ трафика и так далее
- мониторинг удалённых логинов в систему – следить за портами 22 (SSH), 3389 (RDP)
- отслеживание сканирования портов
Flow Log record – поля
Каждая запись в логе представляет собой данные об IP-трафике, полученном за aggregation interval и представляет собой строку с полями, разделённые пробелами, где каждое поле содержит информацию о передаче данных, например – Source IP, Destination IP и протокол.
По-умолчанию используется следующий формат:
${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}
См. таблицу Available fields в документации, всё в колонке Version 2 включено в default format.
При создании Flow Logs, мы можем использоваться дефолтный формат, или создать свой – рассмотрим его чуть ниже:
Ограничения VPC Flow Logs
- нельзя использовать с инстансами EC2-Classic
- нельзя создать логи для VPC-пирингов, если они ведут к VPC вдругом аккаунте
- после создания лога – нельзя изменить его конфигурацию или формат записей
- ?! если у интерфейса несколько IPv4-адресов, и траифк отправляется к одному из secondary-адресов, то в поле dstaddr будет отображён primary-адрес; что бы получить оригинальный адрес – используйте поле pkt-dstaddr
- ?! если трафик отправлен с или на сетевой интерфейс, поля srcaddr и dstaddr будут содержать его primary private IPv4 адрес; что бы получить оригинальный адрес – используйте поле pkt-dstaddr и pkt-dstaddr
Также, учитывайте, что:
- не логгируются записи к DNS Amazon, но пишутся, если используется свой DNS
- не логгируется трафик на и с адреса 169.254.169.254 для получения метаданных EC2-инстанса
- не логгируется трафик между сетевым интерфейсом EC2 и интерфейсом AWS Network Load Balancer
См. все ограничения в Flow log limitations.
Создание VPC Flow Log
Для создания нам требуется указать:
- ресурс, логи которого будем писать – VPC, подсеть или конкретный сетевой интерфейс
- тип трафика, который логгируем (accepted traffic, rejected traffic или all traffic)
- и куда будем писать данные – в корзину, или CloudWtch Logs
Пока посмотрим, что получится с CloudWatch Logs, а в следующий раз – попробуем визуализировать в Kibana.
CloudWatch Logs Log Group
Создаём Log Group:
Создание IAM Policy и Role
Для того, что бы сервис Flow Logs мог писать в наш CloudWatch – настраиваем ему права доступа.
Переходим в AWS IAM, создаём IAM Policy и IAM Role.
Начинаем с Policy:
Добавляем саму политику:
{ "Version": "2012-10-17", "Statement": [ { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams" ], "Effect": "Allow", "Resource": "*" } ] }
Сохраняем:
Создаём роль.
Переходим в IAM Roles, создаём новую, выбираем тип EC2:
Находим созданную выше политику, подключаем:
Задаём имя, сохраняем:
Переходим к Role Trust relationshitp (см. AWS: IAM AssumeRole – описание, примеры), редактируем – меняем значение поля Service
на vpc-flow-logs.amazonaws.com:
Указываем:
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "vpc-flow-logs.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }
Сохраняем:
VPC – включение Flow Logs
И наконец-то переходим к включению логов – находим нужную VPC, кликаем Flow Logs > Create:
Задаём имя, Filter, Interval:
В Destination выбираем CloudWatch Logs, указываем созданные ранее Log Group и IAM Role:
Format – оставляем Default.
Проверяем Status:
И через несколько минут – данные пошли:
В лог-группе появился первый стрим с именем равным имени Elastic Network Interface, с которого снимаются данные:
CloudWatch Logs Insights
Быстренько посмотрим, что нам доступно в Logs Insights.
Клиаем Queries для получения подсказки по синтаксису запросов:
Например, топ-15 хостов по количеству пакетов:
Или по объёму отправленных данных:
stats sum(bytes) as BytesSent by srcAddr, dstAddr | sort BytesSent desc
Окей, а что с другими форматами?
К примеру, хочется увидеть направление запроса (egress/ingress) и значение поля pkt-dstaddr
.
VPC Flow Log – Custom format
См. примеры на странице Flow log record examples.
Используем такой формат:
region vpc-id az-id subnet-id instance-id interface-id flow-direction srcaddr dstaddr srcport dstport pkt-srcaddr pkt-dstaddr pkt-src-aws-service pkt-dst-aws-service traffic-path packets bytes action
В CloudWatch Logs создаём новый Log group, назовём его bttrm-eks-dev-1-21-vpc-fl-custom, не забываем про retention, что бы данные не лежали вечно:
Возвращаемся к VPC, находим нужную сеть, создаём новый Flow Log, назовём его bttrm-eks-dev-1-21-vpc-fl-custom:
Выбираем Custom Format и поля, которые хотим записывать. При этом учитывайте, что очередность полей в логе будет та, которую вы используете при выборе полей тут.
Т.е. если первым кликнуть на “region” – то и в логе он будет задан первым:
Получается так:
${region} ${vpc-id} ${az-id} ${subnet-id} ${instance-id} ${interface-id} ${flow-direction} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${pkt-srcaddr} ${pkt-dstaddr} ${pkt-src-aws-service} ${pkt-dst-aws-service} ${traffic-path} ${packets} ${bytes} ${action}
Flow Log Custom format и CloudWatch Logs Insights
Но если мы зайдём в Logs Insights, и попробуем любой из предыдущих запросов – получим совсем не те поля, которые хотели:
Т.е. данные мы видим, но как разбить поля по колонкам?
Мы вряд ли будем плотно пользоваться CloudWatch Logs, скорее всего данные пойдут в S3 и потом в ELK (logz.io), поэтому подробно тут останавливаться не буду, но принцип работы посмотрим – пригодится позже для работы с ELK.
CloudWatch Logs по-умолчанию создаёт несколько мета-полей, которые мы можем использовать в запросах:
@message
: “сырые” данные – всё сообщение в text@timestamp
: время события@logStream
: имя стрима
Для Custom format, что бы сформировать поля, используем команду parse
, которой передаём поле @message
со всем содержимым, а затем парсим его по полям, которые разделены пробелами:
parse @message "* * * * * * * * * * * * * * * * * * *" | as region, vpc_id, az_id, subnet_id, instance_id, interface_id, | flow_direction, srcaddr, dstaddr, srcport, dstport, | pkt_srcaddr, pkt_dstaddr, pkt_src_aws_service, pkt_dst_aws_service, | traffic_path, packets, bytes, action | sort start desc
Тут количество “*
” в @message
должно быть равным количеству имён полей, которые мы задаём – ${vpc-id}
и т.д.
Кроме того, имена полей не должны содержать тире. Т.е. оригинальное имя поля ${vpc-id}
для вывода в имени колонки указываем как vpc_id
(или vpcID
– кому какой формат больше нравится).
Проверяем:
Другое дело!
Кроме parse
, мы можем использовать такие команды как filter
, display
, stats
. См. все в CloudWatch Logs Insights query syntax.
Примеры Logs Insights
Ну и попробуем что-то изобразить, например – получить все заблокированные запросы SecuirtyGroup/Network Access List – они будут отмечены как REJECTED.
К нашему запросу:
parse @message "* * * * * * * * * * * * * * * * * * * * * *" | as start, end, region, vpc_id, az_id, subnet_id, instance_id, interface_id, | flow_direction, srcaddr, dstaddr, srcport, dstport, protocol, | pkt_srcaddr, pkt_dstaddr, pkt_src_aws_service, pkt_dst_aws_service, | traffic_path, packets, bytes, action
Добавим:
filter action="REJECT"
stats count(action) as redjects by srcaddr
sort redjects desc
Тут:
- фильтруем по действию над пакетом – выбираем все REJECTED
- считаем количество записей по полю action, выбирая по IP-адресу источника, выводим в колонке redjects
- и сортируем по колонке redjects
Т.е. полностью запрос сейчас будет:
parse @message "* * * * * * * * * * * * * * * * * * *" | as region, vpc_id, az_id, subnet_id, instance_id, interface_id, | flow_direction, srcaddr, dstaddr, srcport, dstport, | pkt_srcaddr, pkt_dstaddr, pkt_src_aws_service, pkt_dst_aws_service, | traffic_path, packets, bytes, action | filter action="REJECT" | stats count(action) as redjects by srcaddr | sort redjects desc
Получаем:
Мы можем также использовать негативные фильтры и комбинировать условия фильтра с операторами and
/or
.
К примеру, убрать из вывода все IP, начинающиеся с 162.142.125 – добавляем filter (srcaddr not like "162.142.125.")
:
... | filter action="REJECT" | filter (srcaddr not like "162.142.125.") | stats count(action) as redjects by srcaddr | sort redjects desc
См. Sample queries.
И добавим фильтр на выборку только входящих запросов – flow_direction
== ingress:
... | filter action="REJECT" | filter (srcaddr not like "162.142.125.") and (flow_direction like "ingress") | stats count(action) as redjects by flow_direction, srcaddr, dstaddr, pkt_srcaddr, pkt_dstaddr | sort redjects desc
Получаем топ отброшенных запросов – сработало правило SecurityGroup или VPC Network Access List.
И смотрим – что за IP в dstaddr
– кому шёл пакет, который был заблокирован?
Переходим в EC2 > Network Interfaces, ищем по Private IP:
Находим “Elastic IP address owner“:
Балансировщику.
Если адрес не находится в AWS – возможно, это какой-то ендпоинт в Kubernetes – ищем например так:
[simterm]
$ kubectl get endpoints --all-namespaces | grep 10.1.55.140 dev-ios-check-translation-ns ios-check-translation-backend-svc 10.1.55.140:3000 58d dev-ios-check-translation-ns ios-check-translation-frontend-svc 10.1.55.140:80 58d
[/simterm]
В целом на это всё.
В следующей части – настроим сбор логов в AWS S3, затем будем их оттуда собирать в ELK, и там попробуем сделать визуализацию и алерты.
Ссылки по теме
VPC Flow Logs
- Collect Amazon VPC flow logs with Elastic Agent – поля и прочее для Кибаны.
- Flow log record examples
CloudWatch Logs
- AWS Security Logging Fundamentals – VPC Flow Logs – пример Cloudwatch Logs с Athena
- Analyze Query And Visualize AWS Cloudwatch Logs Using Logs Insight – прмиеры запросов в Cloudwatch Logs
- How to Visualize and Refine Your Network’s Security by Adding Security Group IDs to Your VPC Flow Logs
- Visualizing log data in graphs
- Analyze CloudWatch Logs like a pro
- Filter, Parse & Group Log Data in AWS CloudWatch Logs Insights
- How can I analyze custom VPC Flow Logs using CloudWatch Logs Insights? – ещё примеры с логами и выборками в Инсайтах
- How can I use CloudWatch Logs Insights queries with my VPC flow log?
- CloudWatch Logs Insights query syntax
- Triaging Networking Issues Using AWS CloudWatch Logs Insights