Привет, Хабр!

Меня зовут Рустем Галиев, я Senior DevOps Engineer в IBM, и мы продолжаем разбираться, как искать и эксплуатировать уязвимости в контейнеризированных средах на примере практических атак. Первую часть статьи можно найти тут, а ссылку на третью добавлю сюда, когда выложу.

Неправильная конфигурация CNI, тут можно провести межконтейнерные атаки через ARP спуфинг

Ошибки конфигурации CNI (Container Network Interface) могут сделать контейнерную сеть уязвимой для межконтейнерных атак, включая такие методы, как ARP-спуфинг. ARP-спуфинг позволяет злоумышленнику подделывать ARP-ответы, перенаправляя трафик между контейнерами через свой контейнер и таким образом перехватывать или модифицировать данные. Эта уязвимость особенно опасна в условиях микросервисной архитектуры, где контейнеры взаимодействуют друг с другом через сеть и обрабатывают чувствительные данные.

Как ARP-спуфинг работает в контейнерных сетях

ARP (Address Resolution Protocol) используется для разрешения IP-адресов в MAC-адреса в локальных сетях. Когда контейнер хочет отправить данные другому контейнеру в той же сети, он отправляет запрос ARP, чтобы узнать MAC-адрес получателя. В случае ARP-спуфинга злоумышленник отвечает на запрос с поддельным MAC-адресом, направляя трафик жертвы на свой контейнер.

При неправильной конфигурации CNI могут отсутствовать ограничения на ARP, что позволяет злоумышленнику успешно подделывать ARP-ответы и выполнять атаки «Man in the middle» (MITM) для перехвата, модификации и перенаправления трафика.

Уязвимости и проблемы конфигурации CNI, приводящие к ARP-спуфингу

  • Отсутствие сетевой изоляции: Без надлежащих сетевых политик трафик между контейнерами в одном и том же namespace или подсети может быть неограничен. В результате злоумышленник может беспрепятственно отправлять ARP-ответы, перенаправляя трафик от одного контейнера к другому.

  • Отключенные функции безопасности сети: CNI-плагины, такие как Calico и Cilium, позволяют настраивать сетевые политики для ограничения трафика. Если такие политики отключены или неправильно настроены, контейнеры могут свободно обмениваться трафиком на уровне L2, создавая возможности для атак, включая ARP-спуфинг.

  • Отсутствие проверок подлинности на уровне ARP: В некоторых контейнерных сетях нет механизма проверки подлинности ARP-сообщений, что позволяет злоумышленникам беспрепятственно отправлять поддельные ARP-ответы.

  • Общие сетевые namespaces: В Kubernetes и Docker, если контейнеры находятся в общем сетевом namespace (например, при использовании hostNetwork: true в Kubernetes), то они могут напрямую взаимодействовать на уровне сети хоста. Злоумышленник может использовать это, чтобы рассылать поддельные ARP-пакеты всем контейнерам в этом пространстве имен.

Пример атаки ARP-спуфингом в контейнерной сети

Предположим, что у нас есть два контейнера в одной сети — Container A и Container B, которые взаимодействуют друг с другом. В сети также находится злоумышленник с Container C. Если CNI сконфигурирована неправильно и не ограничивает ARP-запросы, злоумышленник может выполнить ARP-спуфинг следующим образом:

Подделка ARP-ответа: Злоумышленник из Container C отправляет поддельный ARP-ответ контейнеру A, утверждая, что IP-адрес контейнера B привязан к MAC-адресу контейнера C. В результате контейнер A направляет трафик, предназначенный для B, в контейнер C.

Перехват и изменение трафика: Теперь злоумышленник из контейнера C получает трафик, который должен был идти на контейнер B. Он может либо просто перехватить данные для анализа, либо модифицировать их перед пересылкой в B, выполняя атаку MITM.

Защита от ARP-спуфинга в контейнерных сетях

Чтобы защитить контейнерную сеть от атак, таких как ARP-спуфинг, можно использовать несколько методов:

  • Настройка сетевых политик Kubernetes: Настройте сетевые политики, чтобы ограничить трафик между контейнерами. Это можно сделать с помощью сетевых CNI-плагинов, таких как Calico или Cilium, которые позволяют создать правила, ограничивающие сетевое взаимодействие между подами на основе их меток и пространств имен.

  • Использование проверок подлинности на уровне сети: Некоторые CNI-плагины, такие как Weave Net, поддерживают шифрование трафика и механизмы проверки подлинности, что позволяет предотвратить атаки на уровне L2.

  • Изоляция сетевых namespaces: По возможности, избегайте использования общих сетевых пространств имен, таких как hostNetwork, чтобы не допускать контейнеры к ресурсам хост-системы и ограничить возможности прямого взаимодействия между контейнерами на уровне сети хоста.

  • Использование ARP-фильтрации и защита от ARP-спуфинга: На уровне сетевого интерфейса можно включить ARP-фильтрацию (например, с помощью инструментов, встроенных в сетевые интерфейсы хоста или через настройки на уровне CNI-плагина), чтобы отклонять подозрительные ARP-запросы.

  • Регулярное сканирование на уязвимости: Сканируйте и проверяйте конфигурации CNI на возможные уязвимости и потенциальные ошибки настройки, которые могут позволить злоумышленнику реализовать межконтейнерные атаки.

Неправильная конфигурация CNI может серьезно подорвать безопасность контейнерной сети, открывая двери для атак, таких как ARP-спуфинг. Настройка и поддержка сетевых политик, внедрение проверок подлинности и применение функций безопасности помогут минимизировать риски и защитить сетевые взаимодействия между контейнерами.

Докерфайл который содержит в себе захардкоденные ключи, или запускается от рута

Ошибки при написании Dockerfile могут привести к серьезным проблемам безопасности, особенно если Dockerfile содержит захардкоженные (встроенные в код) конфиденциальные данные или если контейнер запускается с правами суперпользователя (root). Эти ошибки предоставляют злоумышленнику легкий доступ к конфиденциальной информации, таким как ключи доступа и пароли, и могут создать возможность для компрометации контейнера и потенциально — хост-системы.

Как незащищенный Dockerfile может привести к утечке данных

  • Захардкоденные ключи и пароли: При создании Dockerfile иногда включают чувствительные данные, такие как ключи API, пароли и учетные данные базы данных, чтобы приложение могло подключаться к внешним сервисам. Если эти данные не зашифрованы или не скрыты, злоумышленник, получив доступ к образу или контейнеру, сможет легко извлечь их.

  • Запуск контейнера от имени пользователя root: По умолчанию контейнеры запускаются от имени пользователя root, если в Dockerfile не указано другое. Это опасно, поскольку root-права внутри контейнера дают злоумышленнику обширные привилегии для выполнения команд. Если контейнер вырывается из своей изоляции, root-доступ также может распространиться на хост-систему.

  • Неудаление временных файлов и секретов: Если во время сборки Docker-образа добавляются конфиденциальные файлы, такие как .env или ключи API, и они не удаляются после использования, эти файлы остаются доступными в итоговом образе. Их можно легко извлечь, даже если контейнер больше не использует эти данные.

  • Избыточные права доступа: Установка привилегированных прав для запускаемых процессов (например, использование флага --privileged) делает контейнер менее защищенным, так как позволяет приложению получать доступ к системным ресурсам хоста.

Пример небезопасного Dockerfile

Рассмотрим пример неправильного Dockerfile, содержащего захардкоженные секреты и работающего от root-пользователя:

# Не делайте так

FROM python:3.9

# Захардкоженные ключи и пароли

ENV AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE

ENV AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

# Установка зависимостей

RUN apt-get update && apt-get install -y \

curl \

vim

# Запуск приложения от имени root

CMD ["python", "app.py"]

Этот Dockerfile небезопасен по следующим причинам:

  • Захардкоденные секреты: Ключи AWS остаются открытыми и могут быть использованы любым, кто имеет доступ к образу.

  • Запуск от имени root: Отсутствие явного указания пользователя в Dockerfile приводит к запуску от имени пользователя root.

  • Избыточные пакеты: Установка лишних инструментов (например, vim) создает дополнительные поверхности для атак.

Как улучшить безопасность Dockerfile

  • Избегайте захардкоженных секретов: Никогда не добавляйте конфиденциальные данные в Dockerfile. Вместо этого используйте механизмы для передачи секретов, такие как:

  • Переменные среды во время запуска: Задавайте переменные среды с конфиденциальной информацией во время запуска контейнера через команду docker run -e.

  • Docker Secrets в Swarm: Docker Swarm позволяет безопасно передавать секреты в контейнеры, и они будут храниться в памяти, не оставляя следов в образе.

  • Vault-системы (например, HashiCorp Vault): Используйте специализированные системы для управления секретами.

  • Не используйте пользователя root: Добавьте в Dockerfile отдельного пользователя для запуска приложения с минимальными привилегиями

FROM python:3.9

# Создание пользователя с минимальными правами

RUN useradd -m appuser

USER appuser

# Установка зависимостей

RUN apt-get update && apt-get install -y \

curl

CMD ["python", "app.py"]

В этом случае даже если злоумышленник получит доступ к контейнеру, он не сможет выполнять команды с правами root.

Удаление временных файлов: Если для конфигурации требуются файлы с секретами (например, .env), удалите их после использования

COPY .env /app/.env

RUN source /app/.env && rm /app/.env

Сканируйте образ на наличие уязвимостей: Перед развертыванием используйте инструменты сканирования безопасности, такие как Snyk, Trivy или Docker Bench, чтобы убедиться, что в образе нет уязвимостей и захардкоденных секретов.

Например использование Twistlock в Jenkins пайплайне после сборки образа

sh ' tt images pull-and-scan --user "${TWISTLOCKUSER}":"${TWISTLOCKAPI}" --url "${TWISTLOCKAPIADDRESS}" --imagetype prod --iam-api-key ${CLOUDAPI} -g ${TWISTLOCKGROUP} ${SCAN_REGISTRY}/${IMAGE}:${TAG}'

Минималистичные образы: Использование минимальных образов, таких как Alpine Linux, вместо более крупных базовых образов (например, Ubuntu), снижает вероятность включения лишних инструментов, которые могут быть использованы для атак.

Пример безопасного Dockerfile

# Минималистичный базовый образ

FROM python:3.9-alpine

# Создание пользователя с минимальными правами

RUN adduser -D appuser

USER appuser

# Установка зависимостей и удаление временных файлов

RUN apk add --no-cache curl

# Запуск приложения

CMD ["python", "app.py"]

Этот Dockerfile:

  • Не содержит захардкоденных секретов.

  • Запускается от имени пользователя с ограниченными правами.

  • Основан на минималистичном образе, который уменьшает размер и уменьшает количество потенциальных уязвимостей.

Ошибки в Dockerfile, такие как захардкоденные ключи и запуск от имени root, могут поставить под угрозу контейнер и даже весь хост. Соблюдение лучших практик, таких как использование некорневого пользователя, внедрение безопасного управления секретами и регулярное сканирование, помогает минимизировать эти риски и обеспечить безопасность контейнеров в продакшене.



Стартовый курс для администраторов и инженеров, которые хотят освоить основы работы с k8s — «Kubernetes База»

Продвинутый курс для тех, кто уже работал с k8s и хочет повысить компетенции с точки зрения развертывания и сопровождения кластеров K8s — «Kubernetes Мега»

Комментарии (3)


  1. dsoastro
    04.12.2024 18:22

    Можете привести пример конфига calico, который ограничивает arp-spoofing? Пока кроме ограничения capabilities у контейнеров ничего не приходит в голову (но это функция cri)


    1. Hedgehog_art Автор
      04.12.2024 18:22

      Для ограничения ARP-spoofing с помощью Calico можно использовать настройку, которая включает фильтрацию ARP в профилях безопасности сети. NetworkPolicy в Calico, которая помогает защититься от ARP-spoofing:

      apiVersion: projectcalico.org/v3

      kind: GlobalNetworkPolicy

      metadata:

        name: deny-arp-spoofing

      spec:

        selector: all() 

        types:

          - Ingress

          - Egress

        ingress:

          - action: Allow

            protocol: ARP

            source:

              nets:

                - 0.0.0.0/0

            destination:

              nets:

                - 0.0.0.0/0

        egress:

          - action: Allow

            protocol: ARP

            source:

              nets:

                - 0.0.0.0/0

            destination:

              nets:

                - 0.0.0.0/0

        doNotTrack: true

        preDNAT: true

      1. Фильтрация ARP: Политика явно разрешает только ARP-трафик между источниками и назначениями, что помогает предотвратить отправку ложных ARP-запросов.

      2. doNotTrack: Отключение отслеживания состояния пакетов делает фильтрацию более строгой.

      3. preDNAT: Обеспечивает, что политика применяется до любых изменений NAT.


      1. dsoastro
        04.12.2024 18:22

        В protocol нет типа ARP - есть только: TCP, UDP, ICMP, ICMPv6, SCTP, UDPLite, 1-255. Неужели ChatGPT вам политику сгенерировал?

        https://docs.tigera.io/calico/latest/reference/resources/globalnetworkpolicy