Сетевые политики (Network Policies) — это новая функциональность Kubernetes, которая за счет создания брандмауэров позволяет настроить сетевое взаимодействие между группами подов и других узлов сети. В этом руководстве я постараюсь объяснить особенности, не описанные в официальной документации по сетевым политикам Kubernetes. Функциональность сетевых политик стабилизировалась в Kubernetes 1.7. В этой статье их работа объясняется в теории и на практике. При желании вы можете сразу перейти к репозиторию с примерами kubernetes-networkpolicy-tutorial или к документации. В кластере Kubernetes трафик между подами по умолчанию не ограничивается. Это означает, что поды могут беспрепятственно подключаться друг к другу, и внутри кластера нет брандмауэров, которые могли бы им помешать. Сетевые политики позволяют декларативно определять, какие поды к кому могут подключаться. При настройке политик есть возможность детализировать их до пространств имен или более точно, обозначая порты, для которых будут действовать выбранные политики. В настоящее время исходящий от подов трафик таким образом контролировать невозможно. Эта функциональность запланирована в Kubernetes 1.8. При этом проект с открытым исходным кодом под названием Istio является хорошей альтернативой с поддержкой фильтрации исходящего трафика, а также многими другими возможностями, включая встроенную поддержку Kubernetes. Сетевые политики — это еще одно имя для используемых в сфере ИТ уже не одно десятилетие списков контроля доступа (англ. ACL). В кластере Kubernetes с их помощью настраиваются списки контроля доступа для подов. Так же, как и все остальные ресурсы в кластере Kubernetes, сетевые политики настраиваются с помощью декларативных манифестов. Они являются частью приложения, расположены в его репозитории и разворачиваются в Kubernetes вместе с приложением.  Сетевые политики применяются практически в реальном времени. Если между подами есть открытые соединения, применение новой политики, запрещающей такие соединения, приведет к их немедленному разрыву. Правда, за такую оперативность приходится расплачиваться небольшими потерями производительности. См. более подробную информацию и результаты эталонных тестов в этой статье. Ниже представлено несколько распространенных примеров использования сетевых политик Kubernetes. Дополнительные примеры и соответствующие манифесты можно найти на GitHub: kubernetes-networkpolicy-tutorial. Эта политика приведет к отбрасыванию (drop) всего трафика к подам приложения, выбранным с помощью селекторов подов (Pod Selector). Сценарии использования: Пример Запустим nginx-под с метками app=web и env=prod, а также откроем его 80-й порт: Запустим временный под и выполним запрос к сервису web: Работает! Теперь сохраним следующий манифест в файл web-deny-all.yaml и применим его к кластеру: Проверка Запустите контейнер еще раз и попробуйте сделать запрос к сервису web: Трафик заблокирован! Замечания В вышеприведенном манифесте для достижения желаемого мы назначили подам специальные метки app=web,env=prod. Однако в этом файле не хватает поля spec.ingress. Поэтому к поду запрещен весь трафик. Если создать другую сетевую политику, которая позволит некоторым подам получить доступ к приложению напрямую или косвенно, первая сетевая политика потеряет силу. Если есть хотя бы одна сетевая политика с разрешающими трафик правилами, этот трафик пойдет по разрешенному маршруту, невзирая на существование запрещающих правил. Очистка Вы можете создать сетевую политику, ограничивающую трафик только от определенных подов. Сценарии использования: Предоставление доступа к сервису только тем микросервисам, которым это нужно. Предоставление доступа к базе данных только использующим ее приложениям. Пример Предположим, что в нашем приложении есть сервер REST API c метками app=bookstore и role=api: Сохраните следующую сетевую политику в файл api-allow.yaml. Она разрешает доступ лишь подам (например, другим микросервисам) с меткой app=bookstore: Проверка Давайте убедимся, что подам без метки app=bookstore доступ запрещен: Трафик заблокирован! А теперь давайте проверим, что от подов с меткой app=bookstore трафик разрешен: Трафик разрешен. Очистка Сценарий использования  Это очень важная политика, которая блокирует весь трафик между подами, за исключением внесенного в белый список с помощью другой политики. Всерьез подумайте о том, чтобы применить соответствующий манифест во всех пространствах имен, в которых развернута рабочая нагрузка (но не в kube-system). С помощью этой политики можно настроить доступ типа «отклонять все по умолчанию» (default "deny all"). Таким образом можно четко определить, какие компоненты зависят от других компонентов, и внедрить сетевые политики, по которым можно построить графы зависимостей между компонентами. Манифест Несколько замечаний: Сохраните этот манифест в файл default-deny-all.yaml и примените политику: Очистка (также известно под именем LIMIT — ограничение трафика к текущему пространству имен) Вы можете настроить сетевые политики таким образом, чтобы запретить весь трафик из других пространств имен, при этом разрешив локальный трафик в рамках пространства имен, в котором находится под. Сценарии использования Пример Создайте новое пространство имен под названием secondary и запустите веб-сервис: Сохраните следующий манифест в файл web-deny-other-namespaces.yaml и примените его к кластеру: Несколько замечаний по поводу манифеста: Проверка Отправьте запрос к этому веб-сервису из пространства имен default: Трафик из пространства имен default заблокирован! При этом любой под из пространства имен secondary доступ получит: Очистка Эта политика похожа на разрешение трафика из всех пространств имен, при этом она позволяет выбрать определенное пространство имен. Сценарии использования: Пример Запустите веб-сервер в пространстве имен по умолчанию: Теперь предположим, что у вас есть вот такие пространства имен: Создайте пространства имен prod и dev: Следующий манифест разрешит трафик только от подов, находящихся в пространстве имен с меткой purpose=production. Сохраните его в web-allow-prod.yaml и примените к кластеру: Проверка Сделайте запрос к веб-серверу из пространства имен dev, убедитесь, что трафик заблокирован: Теперь сделайте запрос из пространства имен prod, убедитесь, что запрос проходит: Очистка Эта сетевая политика позволяет внешним клиентам получать доступ к поду через балансировщик нагрузки или напрямую из Интернет. Сценарии использования: Пример Запустите под и откройте его 80-й порт для доступа из Интернет через балансировщик нагрузки: Дождитесь появления EXTERNAL-IP в выводе kubectl get service. Откройте http://[EXTERNAL-IP] в браузере и убедитесь в наличии доступа к ресурсу. Следующий манифест разрешает трафик из любых источников (как внутри кластера, так и из внешних источников). Сохраните его в файл web-allow-external.yaml и примените к кластеру: Снова откройте в браузере http://[EXTERNAL-IP] и убедитесь, что он по-прежнему работает. Замечания В этом манифесте определено одно ingress-правило для подов с меткой app=web. Поскольку конкретные podSelector или namespaceSelector не указаны, будет пропускаться трафик от любых источников, в том числе и внешних. Чтобы разрешить доступ извне только к 80-му порту, воспользуйтесь следующим ingress-правилом: Очистка Сетевые политики не являются базовой функциональностью Kubernetes. И хотя вы можете отправить объект NetworkPolicy на мастер Kubernetes, политика не сработает, если соответствующая функциональность не реализована в сетевом плагине. Примеры сетевых плагинов, поддерживающих сетевые политики, можно найти на этой странице. Также сетевые политики поддерживаются плагинами Calico и Weave Net. В Google Container Engine (GKE) поддержка сетевых политик реализована в начальной стадии (alpha) путем предустановки сетевого плагина Calico. Сетевые политики применяются к соединениям, а не к сетевым пакетам. Обратите внимание на то, что соединения подразумевают двунаправленную передачу сетевых пакетов. Например, если под А может подключиться к поду Б, под Б может ответить поду А в рамках текущего соединения. Однако это не означает, что под Б может инициировать соединение с подом А. NetworkPolicy — это один из объектов Kubernetes API. В кластере может быть создано множество таких объектов. В NetworkPolicy есть две основные составляющие: Вот конкретный пример манифеста NetworkPolicy: В этой политике подам с метками app=bookstore или app=inventory разрешено подключаться к подам с метками app=bookstore или role=api. Ее можно озвучить следующим образом: «Предоставить микросервисам приложения bookstore доступ к bookstore API». Несмотря на то что проектная документация и справка по API сетевых политик весьма сложны для понимания, мне удалось выделить несколько простых правил: Дело усложняется в том случае, когда надо настроить сетевое взаимодействие между различными пространствами имен. В двух словах это работает так: Сетевые политики ограничивают сетевой обмен данными между подами и являются важной частью работы по обеспечению безопасности трафика и приложений в кластере Kubernetes. Однако, в отличие от брандмауэров, в рамках сетевых политик не выполняется глубокий анализ пакетов (deep packet inspection). В деле обеспечения безопасности трафика между подами в кластере не стоит полагаться только на сетевые политики. Рекомендую также присмотреться к таким методам, как TLS (transport layer security) со взаимной аутентификацией, который позволяет зашифровать трафик и выполнять аутентификацию при взаимодействии микросервисов. Взгляните на Google Cloud Security Whitepaper (выделение сделано мной): Упомянутые мною ранее связанные с сервисными сетками (service mesh) проекты, такие как Istio и linkerd, обещают качественные улучшения в этой области. Например, Istio может шифровать трафик между микросервисами с использованием TLS и применять сетевые политики прозрачно, без необходимости менять код приложения. Если вы хотите попробовать сетевые политики в действии, легче всего будет начать с создания кластера GKE. Также можно почитать следующее: Благодарю Matthew DeLio и Daniel Nardo за проверку черновиков этой статьи. Ссылки: CEO в Southbridge