AWS VPC Flow Logs – сервіс Amazon, який дозволяє логувати інформацію про трафік між мережевими інтерфейсами у AWS VPC. Далі, ці логи можуть бути передані у 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. Інші версії доступні у Custom 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)
- і куди писатимемо дані – в кошик, або CloudWatch Logs
Поки подивимося, що вийде з CloudWatch Logs, а наступного разу – спробуємо візуалізувати у Kibana або Grafana.
CloudWatch Logs Log Group
Створюємо Log Group:
Створення IAM Policy та IAM 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, щоб дані не лежали вічно (ну і взагалі не забуваємо, що CloudWatch не самий дешевий сервіс):
Повертаємось до 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), тому докладно тут зупинятись не буду, проте принцип роботи подивимося.
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“:
LoadBalancer.
Якщо адреса не знаходиться в 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
CloudWatch Logs
- AWS Security Logging Fundamentals – VPC Flow Logs
- Analyze Query And Visualize AWS Cloudwatch Logs Using Logs Insight
- 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