Перейти к содержимому
GUARDCORE Инженерная база знаний Поиск

Раздел

Инструменты

4 материала Последняя публикация: 21.09.2026
Инструменты

mTLS и service mesh: где шифрование действительно добавляет защиту

<p>Внутри Kubernetes трафик между сервисами часто выглядит «внутренним», а потому по умолчанию считается безопасным. Это опасная модель. Pod может оказаться на другом узле, сеть может быть скомпрометирована, а ошибочно выданные сетевые права позволяют обращаться к соседнему сервису. На этом фоне mTLS — взаимная TLS-аутентификация — решает две конкретные задачи: шифрует соединение и позволяет сторонам удостовериться, с кем они установили связь. Но это не универсальный «режим безопасного Kubernetes».</p> <p>Важно начать с границы ответственности. Kubernetes не включает service mesh как базовую функцию. Сетевые политики Kubernetes определяют, каким Pod разрешены соединения, но шифрование и способ его реализации зависят от CNI либо отдельного продукта. Kubernetes Security Checklist прямо рекомендует NetworkPolicy и допускает service mesh как вариант шифрования внутрикластерного трафика, если выбранный CNI этого не делает. Поэтому слова «включим mTLS» всегда должны сопровождаться названием продукта, моделью его внедрения и владельцем сертификатов.</p> <h2>Что mTLS меняет, а чего не меняет</h2> <p>При обычном TLS клиент проверяет сервер. При mTLS проверяются обе стороны: клиент предъявляет сертификат, сервер предъявляет свой. В service mesh это обычно происходит не в прикладном коде, а в прокси или другом компоненте data plane. Контрольный компонент выдаёт короткоживущие учётные данные и распространяет правила. В результате приложение <code>payments</code> может получить криптографически подтверждаемую идентичность вызывающего, а трафик между точками обработки становится зашифрованным.</p> <p>Это полезно, но это не заменяет следующие уровни:</p> <table> <thead> <tr> <th>Вопрос</th> <th>Что отвечает</th> </tr> </thead> <tbody><tr> <td>Может ли Pod установить сетевое соединение?</td> <td>NetworkPolicy и её реализация CNI</td> </tr> <tr> <td>Кто действительно подключился?</td> <td>mTLS и идентичность workload</td> </tr> <tr> <td>Разрешено ли этому субъекту вызвать именно этот метод?</td> <td>прикладная или mesh-авторизация</td> </tr> <tr> <td>Кто может создать, изменить или прочитать объект Kubernetes?</td> <td>RBAC и защита API</td> </tr> <tr> <td>Что произошло после запуска процесса?</td> <td>журналирование, мониторинг и runtime detection</td> </tr> </tbody></table> <p>Например, сервис <code>frontend</code> имеет разрешённый egress к <code>orders</code>, а <code>orders</code> принимает соединения только от идентичности <code>frontend</code>. Здесь NetworkPolicy уменьшает число возможных путей, а mTLS не позволяет любому Pod, оказавшемуся на допустимом IP-пути, выдать себя за <code>frontend</code>. Однако если у самого <code>frontend</code> есть уязвимость и он легитимно обращается к <code>orders</code>, mTLS не определит, что бизнес-запрос вредоносен. Нужны авторизация, валидация входа и наблюдаемость.</p> <h2>Не начинайте с режима strict на всём кластере</h2> <p>Самый частый риск внедрения — превратить сильную цель в массовый простой. В ряде mesh-реализаций есть миграционный режим, в котором приёмник временно допускает и обычный трафик, и mTLS. В Istio такой режим называется <code>PERMISSIVE</code>; <code>STRICT</code> принимает только mTLS. Это свойство Istio, а не API Kubernetes, поэтому названия и точное поведение обязательно проверяют в документации выбранного продукта.</p> <p>Безопасный порядок работы выглядит так:</p> <ol> <li>Выберите один непубличный сервисный контур и зафиксируйте все его клиенты: workloads, Jobs, интеграции извне кластера, probes, gateways и администрирование.</li> <li>Определите, какая идентичность соответствует каждому workload. Нужен не просто список имён сервисов, а понятная связь «service account / namespace → допустимый сервис».</li> <li>Включите mesh в пилотном namespace и соберите наблюдаемость: сколько соединений уже mTLS, какие остаются plaintext и почему.</li> <li>Исправьте исключения: включите proxy там, где это предусмотрено моделью продукта, либо оформите контролируемый gateway для внешнего клиента. Не маскируйте проблему постоянным глобальным исключением.</li> <li>Лишь после подтверждения всех путей переведите <em>приёмник</em> пилотного сервиса в строгий режим. Затем проверьте доступность, трассы, ошибки TLS и автоматическую ротацию сертификатов.</li> </ol> <p>На практике «сначала permissive, затем strict» — не цель сама по себе, а способ увидеть реальный legacy-трафик до блокировки. Если у выбранного решения нет такого режима, пилот должен быть ещё меньше: отдельный сервис, контролируемые клиенты и заранее подготовленный откат.</p> <h2>Минимальная проверка перед принуждением</h2> <p>До изменения режима владелец сервиса и платформа должны ответить на вопросы ниже не предположениями, а наблюдаемыми данными.</p> <ul> <li>Все ли исходящие клиенты известны, включая CronJob и отладочные утилиты?</li> <li>Все ли конечные точки на пути поддерживают модель mesh: сам workload, ingress/egress gateway, внешняя интеграция?</li> <li>Есть ли отдельный ответственный за корневое доверие, выдачу, срок жизни и отзыв сертификатов?</li> <li>Видна ли в телеметрии идентичность peer и признак шифрования, а не только HTTP-код?</li> <li>Проверяли ли ротацию сертификата в рабочем окружении или реплике production?</li> </ul> <p>Проверка результата должна быть двусторонней. Позитивный тест: <code>frontend</code> вызывает разрешённый API <code>orders</code>, приложение получает ожидаемый ответ, а данные mesh показывают зашифрованное соединение и ожидаемую идентичность клиента. Негативный тест: тестовый Pod с другой service account пытается обратиться к тому же маршруту и получает отказ по политике идентичности либо по NetworkPolicy. Если виден только успешный HTTP 200, это ещё не доказательство mTLS: запрос мог пройти plaintext или обойти data plane.</p> <p>Для Istio минимальная строгая политика приёмника имеет вид ниже. Это <strong>пример именно Istio</strong>, а не универсальный манифест Kubernetes; применять его стоит только в отдельном пилотном namespace после инвентаризации клиентов.</p> <pre><code class="language-yaml">apiVersion: security.istio.io/v1 kind: PeerAuthentication metadata: name: orders-strict namespace: pilot spec: selector: matchLabels: app: orders mtls: mode: STRICT </code></pre> <p>После применения не ограничивайтесь тем, что объект создался. Проверьте, что клиент действительно использует data plane выбранного mesh, что запросы от <code>frontend</code> проходят, а известный plaintext-клиент перестал проходить предсказуемо. Затем отмените или скорректируйте политику в рамках заранее согласованного rollback, если отказ затронул критичный путь.</p> <h2>Сертификаты — не деталь установки</h2> <p>mTLS надёжен ровно настолько, насколько надёжны его идентичности и доверие. Требуется определить:</p> <ul> <li>кто владеет CA и имеет право менять trust bundle;</li> <li>как часто выдаются и автоматически обновляются workload-сертификаты;</li> <li>что происходит при компрометации service account, узла или корневого ключа;</li> <li>где доступны журналы выпуска и ошибок валидации;</li> <li>как проходит смена CA без одновременного отключения всех сервисов.</li> </ul> <p>Нельзя переносить административный корневой сертификат кластера в mesh «для простоты» без отдельной архитектурной оценки. У разных продуктов разные механизмы доверия, хранение ключей и интеграция с внешним PKI. Это отдельная зона контроля: в ней должны быть аудит, ограниченный доступ и проверенный сценарий ротации.</p> <h2>Когда service mesh оправдан</h2> <p>Mesh уместен, когда ценность идентичности workload и шифрования выше его операционной цены: есть много внутренних сервисов, чувствительные данные, несколько команд, требования к аудитам или необходимость вводить авторизацию между сервисами единообразно. Для небольшой системы с несколькими сервисами иногда достаточно TLS в приложении или возможности CNI шифровать трафик, плюс аккуратные NetworkPolicy. Это не «хуже» и не «лучше»: нужно сравнить покрытие угроз, сложность сопровождения и ответственность за инциденты.</p> <p>Итоговая архитектура должна быть слоистой. Сначала минимальные сетевые права, затем криптографическая идентичность и шифрование, затем авторизация действий и полноценная телеметрия. Если хотя бы один из этих уровней не проверен, надпись «mTLS enabled» остаётся настройкой, а не доказанной мерой защиты.</p> <h2>Официальные источники</h2> <ul> <li>Kubernetes Security Checklist: <a href="https://kubernetes.io/docs/concepts/security/security-checklist/">https://kubernetes.io/docs/concepts/security/security-checklist/</a></li> <li>Kubernetes NetworkPolicy: <a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">https://kubernetes.io/docs/concepts/services-networking/network-policies/</a></li> <li>Istio Security and mTLS: <a href="https://istio.io/latest/docs/concepts/security/">https://istio.io/latest/docs/concepts/security/</a></li> </ul>

6 минут Открыть →
Инструменты

Наблюдаемость Kubernetes: как связать flow logs, Audit и DNS в доказательства

<p><strong>Цикл:</strong> «Сетевая безопасность Kubernetes: от основ до практической защиты» · материал 9 из 12<br><strong>Формат:</strong> практический разбор</p> <h2>Кратко</h2> <p>Нельзя строить NetworkPolicy по догадкам. Но и один network flow не объясняет инцидент: IP Pod быстро меняется, flow не показывает действие через Kubernetes API, а DNS-запрос не доказывает установление соединения. Нужна связка источников: сетевые потоки для фактической связности, Audit для действий через API, DNS для имён, runtime для процесса-инициатора и perimeter/proxy для внешнего направления.</p> <p>Цель наблюдаемости не «собирать все логи». Она должна позволять ответить на конкретные вопросы: какой workload установил соединение, было ли оно разрешено политикой, кто изменил NetworkPolicy или RBAC, обращался ли Pod к новому имени и как это повлияло на бизнес-сценарий.</p> <h2>Пять источников — пять разных ответов</h2> <table> <thead> <tr> <th>Источник</th> <th>На что отвечает</th> <th>Чего не знает сам по себе</th> </tr> </thead> <tbody><tr> <td>Network flow</td> <td>кто с кем соединялся, протокол, порт, allow/deny</td> <td>кто изменил Kubernetes-объект</td> </tr> <tr> <td>Kubernetes Audit</td> <td>кто и как обращался к API</td> <td>проходил ли TCP-пакет между Pod</td> </tr> <tr> <td>DNS</td> <td>какое имя запрашивал workload</td> <td>был ли затем успешный HTTPS/TCP-сеанс</td> </tr> <tr> <td>Runtime telemetry</td> <td>какой процесс в контейнере действовал</td> <td>полную сетевую политику и API-авторизацию</td> </tr> <tr> <td>Proxy/NGFW</td> <td>куда ушёл внешний трафик</td> <td>какой Pod стоит за source IP без Kubernetes metadata</td> </tr> </tbody></table> <p>Именно поэтому строки вида <code>10.244.2.15 → 10.244.3.10</code> недостаточно. Через час IP может принадлежать другому Pod. В момент создания flow должны сохраняться namespace, имя Pod, workload, node, destination, порт, направление и verdict. Если CNI умеет связать flow с конкретной policy — сохраняйте и её имя, но не объявляйте это универсальной функцией Kubernetes.</p> <h2>Сначала определите вопросы, затем включайте сбор</h2> <p>Минимальный набор use cases для пилотного namespace:</p> <ol> <li>Показать реальные зависимости перед <code>default deny</code>.</li> <li>Найти поток, заблокированный после изменения policy.</li> <li>Обнаружить новый egress во внешний адрес или домен.</li> <li>Установить, кто создал, изменил или удалил NetworkPolicy, RoleBinding и Service.</li> <li>Сопоставить создание/обновление Deployment с новым Pod и его сетевым поведением.</li> </ol> <p>Если для каждого случая нет ответственного, правила хранения и действия по сигналу, это не детектирование, а дорогой архив.</p> <h2>Kubernetes Audit: журнал API, а не сетевой лог</h2> <p>Kubernetes Audit создаётся в <code>kube-apiserver</code>: запрос может записываться на нескольких стадиях, а audit policy определяет, что именно попадёт в выбранный backend. Поэтому Audit не появляется «сам по себе в SIEM» только от факта работы Kubernetes.</p> <p>Для ИБ в первую очередь нужны действия с <code>networkpolicies</code>, <code>roles</code>, <code>rolebindings</code>, <code>clusterrolebindings</code>, <code>serviceaccounts</code>, <code>secrets</code>, <code>deployments</code>, <code>daemonsets</code>, <code>pods</code>, <code>services</code> и <code>ingresses</code>/Gateway-объектами. Для чувствительных объектов чаще достаточно метаданных запроса; не включайте тела ответов к Secrets ради удобства расследования — это создаст новый канал раскрытия данных. Точную audit policy согласовывают с владельцем платформы и проверяют на тестовом изменении.</p> <p>Проверочный сценарий прост: в учебном namespace создать или изменить одну именованную NetworkPolicy, затем найти в Audit время, пользователя/ServiceAccount, verb, URI ресурса, namespace и результат. Если записи нет, сначала исправляют policy, backend или доставку в SIEM; не утверждают, что «аудит включён».</p> <h2>DNS: контекст имени и отдельная зависимость</h2> <p>Kubernetes создаёт DNS-записи для Service и настраивает DNS Pod. После egress deny ошибка разрешения имени часто выглядит как недоступность backend. Поэтому в процессе изменения policy собирают не только flow, но и проверку <code>nslookup</code> из самого namespace.</p> <p>Для внешнего egress DNS полезен как ранний сигнал: workload начал спрашивать неизвестный домен. Но DNS не равен соединению: запрос мог завершиться ошибкой, адрес мог быть кэширован, а приложение может обращаться к IP напрямую. Коррелируйте DNS с последующим flow и proxy/NGFW-событием по времени, workload и destination IP.</p> <p>Не используйте Kubernetes <code>Event</code> как основной журнал. Официальная документация определяет их как best-effort информацию с ограниченным хранением; они полезны для оперативной диагностики, но не для доказательств инцидента.</p> <h2>Практический минимум для CNI с flow telemetry</h2> <p>Сначала проверьте возможности именно установленного CNI: формат, доступность verdict, metadata, экспорт и retention. Например, Hubble — средство наблюдаемости Cilium; оно не появляется в Calico, OVN или другом CNI автоматически.</p> <p>В стенде из статьи 5 зафиксируйте одну разрешённую и одну запрещённую связь:</p> <pre><code class="language-bash">kubectl -n np-lab exec deploy/client -- \ curl -fsS --max-time 3 http://backend:8080 kubectl -n np-lab exec other -- \ curl -fsS --max-time 3 http://backend:8080 || echo "blocked as expected" </code></pre> <p>В консоли или экспортируемом потоке CNI должны различаться хотя бы source Pod, destination Pod/IP, TCP/8080, время и verdict. Если policy correlation доступна, дополнительно проверяется имя политики. Если telemetry не показывает deny, это не доказывает, что deny отсутствует, но означает, что этим источником нельзя подтверждать блокировку.</p> <h2>Корреляция, которая имеет смысл</h2> <p>Полезная цепочка расследования выглядит так:</p> <pre><code class="language-text">Audit: изменён Deployment → Kubernetes: создан новый Pod → DNS: Pod запросил незнакомое имя → Flow: Pod открыл TLS-соединение наружу → Proxy/NGFW: подтверждено внешнее назначение </code></pre> <p>Это гипотеза, а не автоматическое доказательство компрометации. Проверяющий должен установить владельца Deployment, ожидаемость новой версии и назначение домена. Сильная корреляция не отменяет контекст.</p> <h2>Retention, доступ и стоимость</h2> <p>Хранение определяют для каждого источника отдельно. Audit может быть малым по объёму, но критичным для расследования изменений. Flow обычно объёмнее. DNS может содержать чувствительные сведения о сервисах и поведении пользователей. Нужно заранее определить срок хранения, защиту от изменения, экспорт, резервирование, доступ по ролям и способ поиска по namespace/workload.</p> <p>Не включайте L7, packet capture и все debug-события навсегда. Сначала измерьте поток событий в пилоте, оцените CPU/память на node, пропускную способность collector и стоимость хранения. При перегрузке приоритетом остаются metadata и security use cases, а не бесконечная детализация.</p> <h2>Итог</h2> <p>Observability предшествует строгому enforcement. Сначала наблюдают реальные зависимости, затем формируют узкие policy, после чего отслеживают deny и новые исключения. Flow, Audit и DNS дают разные части картины; только их корреляция позволяет объяснить, что произошло и кто должен принять решение.</p> <p>Следующая статья покажет, где нужен mTLS и service mesh, а где эти механизмы только усложняют простую L3/L4-сегментацию.</p> <h2>Официальные источники</h2> <ul> <li><a href="https://kubernetes.io/docs/tasks/debug/debug-cluster/audit/">Kubernetes: Auditing</a></li> <li><a href="https://kubernetes.io/docs/concepts/security/controlling-access/">Kubernetes: Controlling Access to the API</a></li> <li><a href="https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/">Kubernetes: DNS for Services and Pods</a></li> <li><a href="https://kubernetes.io/docs/reference/kubernetes-api/core/event-v1/">Kubernetes API: Event</a></li> <li><a href="https://docs.cilium.io/en/stable/overview/intro/">Cilium: Hubble</a></li> <li><a href="https://docs.cilium.io/en/latest/observability/hubble/hubble-cli/">Cilium: Inspecting network flows</a></li> </ul> <hr> <p><strong>Навигация по циклу:</strong><br>← <a href="https://guardcore.by/ingress-egress-kubernetes-pochemu-zakryt-vhod-nedostatochno/">Ingress и egress в Kubernetes: почему закрыть вход недостаточно</a> · <a href="https://guardcore.by/pochemu-privychnaya-setevaya-bezopasnost-ne-rabotaet-v-kubernetes/">Начало цикла</a> · <a href="https://guardcore.by/servis-mesh-mtls-kubernetes/">mTLS и service mesh: где заканчивается NetworkPolicy →</a></p>

6 минут Открыть →
Инструменты

CNI и eBPF в Kubernetes: как проверить, кто применяет сетевую политику

<p><strong>Цикл:</strong> «Сетевая безопасность Kubernetes: от основ до практической защиты» · материал 6 из 12<br><strong>Формат:</strong> практический разбор<br><strong>Для кого:</strong> ИБ-специалист, DevOps-инженер, архитектор и разработчик, которым нужно понять, где в Kubernetes реально принимается решение «разрешить или заблокировать пакет».</p> <h2>Кратко</h2> <p><code>NetworkPolicy</code> — это объект Kubernetes API с описанием желаемого правила. Он сам не фильтрует ни одного пакета. Реальную работу выполняет реализация pod-сети: она подключает Pod к сети, отслеживает изменения в API и программирует datapath на worker node. Без поддержки NetworkPolicy со стороны этой реализации YAML можно успешно создать, но трафик останется открытым.</p> <p>eBPF — один из способов построить такой datapath в Linux. Он не является самостоятельным firewall, не заменяет RBAC, защиту образов, аудит или реагирование. Его польза возникает только в связке: корректные правила, поддерживаемая версия ядра, контролируемая конфигурация и возможность доказать по телеметрии, почему поток был разрешён или заблокирован.</p> <p>Ниже — методика: определить используемую реализацию сети, проверить enforcement на стенде из предыдущей статьи, собрать минимальный паспорт datapath и понять, что именно проверять перед выбором или изменением CNI.</p> <h2>Сначала разделим три разные вещи</h2> <p>Термины часто смешивают, из-за чего CNI превращается в «магический сетевой компонент». На практике это разные уровни.</p> <table> <thead> <tr> <th>Уровень</th> <th>Что делает</th> <th>Что не доказывает</th> </tr> </thead> <tbody><tr> <td>Kubernetes API</td> <td>Хранит <code>NetworkPolicy</code>, Service, Pod и их labels</td> <td>Что пакет был отфильтрован</td> </tr> <tr> <td>Реализация pod-сети / CNI</td> <td>Подключает Pod к сети и может реализовать policy, маршрутизацию и Service</td> <td>Что правила безопасны и полны</td> </tr> <tr> <td>Datapath на node</td> <td>Обрабатывает конкретный пакет: маршрут, трансляция, allow/drop</td> <td>Кто и зачем создал широкое правило</td> </tr> <tr> <td>Observability</td> <td>Связывает поток с Pod, namespace, Service и verdict</td> <td>Что блокировка не сломала бизнес-сценарий</td> </tr> </tbody></table> <p>Официальная документация Kubernetes прямо отделяет API от реализации: pod-сеть и NetworkPolicy обычно обеспечиваются внешней реализацией сети; часть простых реализаций не поддерживает NetworkPolicy вовсе. Поэтому наличие ресурсов <code>networkpolicy.networking.k8s.io</code> в кластере — ещё не доказательство защиты.</p> <h2>Что такое CNI без маркетинга</h2> <p>CNI (Container Network Interface) — спецификация и набор плагинов, через которые container runtime на node настраивает сеть sandbox Pod. Kubernetes требует совместимый сетевой плагин для реализации своей модели pod-сети. Но CNI не означает фиксированный набор функций и не является названием конкретного продукта.</p> <p>Одна реализация может только подключать интерфейс и выдавать IP. Другая дополнительно реализует межузловую маршрутизацию, NetworkPolicy, балансировку Service, шифрование, DNS/FQDN-политику или flow telemetry. Поэтому вопрос «у нас есть CNI?» бесполезен. Нужен другой вопрос: <strong>какая реализация pod-сети установлена, какие функции включены и где они применяются?</strong></p> <p>Не путайте эту роль с <code>kube-proxy</code>. Kubernetes даёт стандартную реализацию Service proxy через <code>kube-proxy</code>, но часть сетевых решений реализует Service handling внутри собственного datapath. Для расследования это важно: один и тот же вызов <code>backend.default.svc.cluster.local</code> может сначала быть виден как Service, а затем как соединение с конкретным endpoint Pod.</p> <h2>Как пакет связан с предыдущей статьёй</h2> <p>Возьмём стенд <code>client → backend</code> из материала о NetworkPolicy. После <code>default deny</code> успешное обращение по TCP/8080 возможно только когда:</p> <ol> <li>DNS разрешил имя <code>backend</code>;</li> <li>Service направил соединение к endpoint <code>backend</code>;</li> <li>datapath источника разрешил egress от <code>client</code>;</li> <li>datapath получателя разрешил ingress к <code>backend</code>;</li> <li>обратный трафик был обработан как ответ разрешённого соединения.</li> </ol> <p>Схема не означает, что каждый CNI применяет правила в одинаковых точках ядра. Она показывает границы проверки. Если поток не проходит, нельзя заключать «NetworkPolicy сломана», пока не разделены DNS, Service/endpoints, policy и сама связность между node.</p> <pre><code class="language-text">client Pod → DNS / Service → datapath на source node → сеть между node → datapath на destination node → backend Pod │ │ │ имя/endpoint egress policy ingress policy </code></pre> <h2>Почему одинаковый YAML может работать по-разному</h2> <p>Стандартный API NetworkPolicy задаёт ожидаемый результат на L3/L4: какой Pod выбран, откуда или куда разрешён TCP/UDP/SCTP. Он не предписывает конкретный внутренний механизм. Реализация может использовать Linux routing, <code>iptables</code>/<code>nftables</code>, виртуальные интерфейсы, overlay-туннель, BGP-маршрутизацию или eBPF. Эти технологии не являются взаимозаменяемыми пунктами настройки: в одном кластере может сочетаться несколько из них.</p> <p>Из этого следуют два практических правила.</p> <p>Первое: нельзя переносить инструкции «посмотрите правило в iptables» в другой кластер и считать их универсальной проверкой. Второе: нельзя оценивать CNI только по YAML совместимости. Нужно проверять фактический поток в конкретной версии CNI, Kubernetes и ядра Linux.</p> <h2>Минимальная инвентаризация без доступа к node</h2> <p>Начните с read-only команд. Они не раскрывают внутреннее устройство datapath полностью, но дают основу для дальнейшего запроса к платформенной команде.</p> <pre><code class="language-bash">kubectl get nodes -o wide kubectl -n kube-system get daemonset kubectl -n kube-system get pods -o wide kubectl get networkpolicy -A kubectl get svc -A </code></pre> <p>Зафиксируйте результат в паспорте кластера, а не в личных заметках:</p> <table> <thead> <tr> <th>Поле</th> <th>Что записать</th> <th>Зачем</th> </tr> </thead> <tbody><tr> <td>CNI и версия</td> <td>точное имя реализации и release</td> <td>определяет документацию и известные ограничения</td> </tr> <tr> <td>Kubernetes и ядро node</td> <td>версии control plane, worker OS/kernel</td> <td>важны для совместимости и eBPF-функций</td> </tr> <tr> <td>Pod/Service CIDR</td> <td>фактические диапазоны</td> <td>нужны для маршрутизации, egress и расследований</td> </tr> <tr> <td>Межузловая схема</td> <td>direct routing, overlay, BGP или иное</td> <td>определяет путь трафика и возможные слепые зоны</td> </tr> <tr> <td>Service handling</td> <td><code>kube-proxy</code> или замена CNI</td> <td>объясняет трансляцию Service→endpoint</td> </tr> <tr> <td>NetworkPolicy</td> <td>поддержка, режим enforcement, scope</td> <td>отвечает на вопрос, действует ли default deny</td> </tr> <tr> <td>Телеметрия</td> <td>источник flows, поля, retention, экспорт</td> <td>делает policy проверяемой и расследуемой</td> </tr> </tbody></table> <p>Названия DaemonSet и Pod могут подсказать поставщика, но это не доказательство включённых функций. Версию и режим policy нужно подтвердить конфигурацией и документацией именно этого CNI.</p> <h2>Проверка, что policy действительно действует</h2> <p>Не заменяйте функциональную проверку просмотром объектов. Возьмите отдельный namespace <code>np-lab</code> из статьи 5 и выполните три теста в таком порядке:</p> <pre><code class="language-bash"># 1. До изоляции: client должен достичь backend kubectl -n np-lab exec deploy/client -- \ curl -fsS --max-time 3 http://backend:8080 # 2. После default deny: тот же поток не должен пройти kubectl -n np-lab exec deploy/client -- \ curl -fsS --max-time 3 http://backend:8080 || echo "blocked as expected" # 3. После DNS и узких ingress/egress policy: поток снова проходит kubectl -n np-lab exec deploy/client -- \ curl -fsS --max-time 3 http://backend:8080 </code></pre> <p>Это не тест производительности и не полная приёмка CNI. Он отвечает на базовый вопрос: выбранная реализация изменила судьбу реального соединения после изменения NetworkPolicy или нет.</p> <p>Для отрицательного теста добавьте Pod без разрешающей метки и убедитесь, что он не получает доступ к <code>backend</code>. Успешный allow-тест сам по себе слабое доказательство: соединение могло пройти из-за слишком широкого правила, другой политики или отсутствия enforcement.</p> <p>Результат нужно фиксировать как артефакт изменения: версия CNI, namespace, применённые манифесты, время, allow/deny-результат и ссылка на flow/event, если он доступен.</p> <h2>eBPF: что это и чего от него не ждать</h2> <p>eBPF — механизм Linux kernel, позволяющий исполнять проверенные программы в разрешённых точках ядра. В сетевом datapath он может обрабатывать пакет на раннем этапе, сопоставлять его с картами состояний, применять policy или собирать metadata. Это механизм исполнения, а не отдельная политика безопасности.</p> <p>Например, Cilium использует eBPF-программы, привязанные к сетевым hook. Его документация описывает проверку policy на veth/TC-пути и сопоставление пакета с identity и policy. Это описание относится к Cilium; его нельзя объявлять устройством любого CNI.</p> <p>У eBPF есть реальные преимущества для динамичной среды: решение может связать flow не только с краткоживущим IP, но и с Kubernetes identity; Service lookup и policy могут использовать общую картину endpoints. Но «у нас eBPF» не отвечает ни на один из критичных вопросов: есть ли default deny, кто может менять правила, включена ли телеметрия, хватает ли ресурсов или защищены ли сами node.</p> <h2>Cilium и Hubble: отдельный, а не обязательный вариант</h2> <p>Если кластер действительно использует Cilium, проверяйте его как конкретный продукт. Cilium документирует identity-aware L3/L4 policy для Pod-to-Pod; для расширенных возможностей использует собственные CRD. Hubble строится поверх Cilium и предоставляет распределённую observability: потоки, DNS-события и verdict policy.</p> <p>Это полезно для ИБ, потому что расследование перестаёт опираться только на IP. Но Hubble не компенсирует ошибочную политику и не превращает наблюдение в блокировку. Сначала нужна минимальная связность, подтверждённая allow/deny-тестами; затем — осмысленный экспорт нужных событий и срок хранения.</p> <p>Ниже команды допустимы <strong>только после подтверждения, что установлен Cilium и разрешён доступ к его агенту</strong>:</p> <pre><code class="language-bash">kubectl -n kube-system get pods -l k8s-app=cilium kubectl -n kube-system exec ds/cilium -- cilium status --wait </code></pre> <p>Не копируйте эти команды в кластер с другим CNI. Для него используйте штатную диагностику поставщика и проверьте: отображается ли источник, назначение, DNS-имя (если оно нужно), порт, verdict, причина/политика и время события.</p> <h2>Как выбрать нужную глубину контроля</h2> <p>Стандартная NetworkPolicy подходит, когда нужно управлять Pod/namespace/IP и портом на L3/L4. Это базовый переносимый минимум. Запросы «разрешить только конкретное DNS-имя», «только HTTP <code>GET /health</code>» или «видеть HTTP-код ответа» выходят за пределы стандартного API и требуют расширения конкретного CNI, egress proxy, Gateway/API gateway или service mesh.</p> <p>Не начинайте с L7 только потому, что оно доступно в интерфейсе продукта. Более глубокий контроль добавляет компоненты, правила, сертификаты, нагрузку и точки отказа. Он оправдан, когда L3/L4 не выражает необходимую границу риска: например, один общий порт обслуживает и разрешённый, и опасный API-метод.</p> <h2>Нагрузка, отказ и обновление</h2> <p>Вопрос «eBPF быстрее iptables?» не является критерием проектного решения. Итог зависит от режима CNI, ядра, числа endpoints, Service, policy, включённого шифрования и объёма наблюдения. Нужны измерения на репрезентативной нагрузке, а не обещание из презентации.</p> <p>Перед включением глубоких flow logs или L7-observability определите:</p> <ol> <li>какие события действительно нужны для защиты и эксплуатации;</li> <li>ожидаемый поток событий и retention;</li> <li>CPU, память и сетевой трафик на node;</li> <li>куда экспортируются события и кто имеет к ним доступ;</li> <li>поведение при недоступности collector или переполнении буфера;</li> <li>порядок обновления CNI и проверку rollback.</li> </ol> <p>Особый риск — изменение CNI или его datapath одновременно с <code>default deny</code>. Это две переменные в одном инциденте. Сначала докажите базовую связность и policy enforcement в пилотном namespace, затем отдельно меняйте CNI/режим и повторяйте те же тесты.</p> <h2>Чек-лист приёмки CNI с точки зрения ИБ</h2> <p>Перед тем как считать CNI частью контролируемой защиты, должны быть положительные ответы на вопросы:</p> <ol> <li>Поддерживает ли текущая версия именно стандартный Kubernetes NetworkPolicy и включён ли enforcement?</li> <li>Подтверждён ли отрицательный тест <code>default deny</code> на реальном Pod-трафике?</li> <li>Проверены ли ingress и egress, DNS, Service и связь между разными node?</li> <li>Известны ли режим маршрутизации, Service handling и поведение egress/NAT?</li> <li>Есть ли диагностика deny и корректная связь IP с Kubernetes metadata?</li> <li>Ограничены ли права на изменение CNI-конфигурации, labels и NetworkPolicy?</li> <li>Зафиксированы ли ресурсные лимиты, обновление, rollback и ответственные?</li> </ol> <p>Если на несколько пунктов ответ «не знаю», CNI нельзя считать проверенным средством сегментации. Это не основание немедленно менять продукт; это основание закрыть неизвестность тестом, документацией поставщика и измерением в своём кластере.</p> <h2>Итог</h2> <p>NetworkPolicy описывает, что разрешено. Реализация pod-сети и её datapath решают, как это будет применено. Observability позволяет увидеть, что произошло. eBPF может быть сильной технической основой для этих задач, но не является заменой архитектуры безопасности.</p> <p>Следующая статья переходит к другой границе: ServiceAccount и RBAC. Даже идеальная сетевая сегментация не спасает, если скомпрометированный Pod может через Kubernetes API читать Secrets или менять политики.</p> <h2>Официальные источники</h2> <ul> <li><a href="https://kubernetes.io/docs/concepts/extend-kubernetes/compute-storage-net/network-plugins/">Kubernetes: Network Plugins</a></li> <li><a href="https://kubernetes.io/docs/concepts/services-networking/">Kubernetes: Services, Load Balancing, and Networking</a></li> <li><a href="https://kubernetes.io/docs/concepts/services-networking/network-policies/">Kubernetes: Network Policies</a></li> <li><a href="https://docs.cilium.io/en/stable/overview/intro/">Cilium: Introduction to Cilium and Hubble</a></li> <li><a href="https://docs.cilium.io/en/stable/network/ebpf/intro/">Cilium: eBPF datapath</a></li> <li><a href="https://docs.cilium.io/en/stable/network/kubernetes/intro/">Cilium: Kubernetes networking</a></li> </ul> <hr> <p><strong>Навигация по циклу:</strong><br>← <a href="https://guardcore.by/networkpolicy-s-nulya-kak-izolirovat-prilozheniya-kubernetes/">NetworkPolicy с нуля: как реально изолировать приложения в Kubernetes →</a> · <a href="https://guardcore.by/pochemu-privychnaya-setevaya-bezopasnost-ne-rabotaet-v-kubernetes/">Начало цикла</a> · <a href="https://guardcore.by/serviceaccount-rbac-bezopasnost-kubernetes-api/">ServiceAccount и RBAC: почему сетевая защита Kubernetes невозможна без контроля API →</a></p>

10 минут Открыть →