DEV Community

Arseny Zinchenko
Arseny Zinchenko

Posted on • Originally published at rtfm.co.ua on

AWS: VPC Flow Logs  -  знайомство та аналітика з CloudWatch Logs Insights

AWS: VPC Flow Logs  -  знайомство та аналітика з CloudWatch Logs Insights

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}
Enter fullscreen mode Exit fullscreen mode

Див. таблицю 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": "*"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Зберігаємо:

Створюємо роль.

Переходимо в 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"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Зберігаємо:

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
Enter fullscreen mode Exit fullscreen mode

Окей, а що з іншими форматами?

Наприклад, хочеться побачити напрямок запиту (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
Enter fullscreen mode Exit fullscreen mode

У 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}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Тут кількість “*" в @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
Enter fullscreen mode Exit fullscreen mode

Додамо:

  • 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
Enter fullscreen mode Exit fullscreen mode

Отримуємо:

Ми також можемо використовувати негативні фільтри та комбінувати умови фільтра з операторами 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
Enter fullscreen mode Exit fullscreen mode

Див. 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
Enter fullscreen mode Exit fullscreen mode

Отримуємо топ відкинутих запитів — спрацювало правило SecurityGroup або VPC Network Access List.

І дивимося — що за IP у dstaddr – кому йшов пакет, який був заблокований?

Переходимо в EC2 > Network Interfaces, шукаємо Private IP:

Знаходимо “Elastic IP address owner”:

LoadBalancer.

Якщо адреса не знаходиться в AWS — можливо, це якийсь ендпоінт у Kubernetes — шукаємо наприклад так:

$ 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
Enter fullscreen mode Exit fullscreen mode

Загалом на це все.

У наступній частині — налаштуємо збір логів в AWS S3, потім будемо їх звідти збирати в ELK, і там спробуємо зробити візуалізацію та алерти.

Посилання по темі

VPC Flow Logs

CloudWatch Logs

Originally published at RTFM: Linux, DevOps, and system administration.

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay