- PVSM.RU - https://www.pvsm.ru -
Сетевые политики (Network Policies) — это новая функциональность Kubernetes, которая за счет создания брандмауэров позволяет настроить сетевое взаимодействие между группами подов и других узлов сети. В этом руководстве я постараюсь объяснить особенности, не описанные в официальной документации по сетевым политикам Kubernetes.
Функциональность сетевых политик стабилизировалась в Kubernetes 1.7. В этой статье их работа объясняется в теории и на практике. При желании вы можете сразу перейти к репозиторию с примерами kubernetes-networkpolicy-tutorial [1] или к документации [2].
В кластере Kubernetes трафик между подами по умолчанию не ограничивается. Это означает, что поды могут беспрепятственно подключаться друг к другу, и внутри кластера нет брандмауэров, которые могли бы им помешать.
Сетевые политики позволяют декларативно определять, какие поды к кому могут подключаться. При настройке политик есть возможность детализировать их до пространств имен или более точно, обозначая порты, для которых будут действовать выбранные политики.
В настоящее время исходящий от подов трафик таким образом контролировать невозможно. Эта функциональность запланирована в Kubernetes 1.8.
При этом проект с открытым исходным кодом под названием Istio [3] является хорошей альтернативой с поддержкой фильтрации исходящего трафика, а также многими другими возможностями, включая встроенную поддержку Kubernetes.
Сетевые политики — это еще одно имя для используемых в сфере ИТ уже не одно десятилетие списков контроля доступа (англ. ACL). В кластере Kubernetes с их помощью настраиваются списки контроля доступа для подов. Так же, как и все остальные ресурсы в кластере Kubernetes, сетевые политики настраиваются с помощью декларативных манифестов. Они являются частью приложения, расположены в его репозитории и разворачиваются в Kubernetes вместе с приложением.
Сетевые политики применяются практически в реальном времени. Если между подами есть открытые соединения, применение новой политики, запрещающей такие соединения, приведет к их немедленному разрыву. Правда, за такую оперативность приходится расплачиваться небольшими потерями производительности. См. более подробную информацию и результаты эталонных тестов в этой статье [4].
Ниже представлено несколько распространенных примеров использования сетевых политик Kubernetes. Дополнительные примеры и соответствующие манифесты можно найти на GitHub: kubernetes-networkpolicy-tutorial [1].
Эта политика приведет к отбрасыванию (drop) всего трафика к подам приложения, выбранным с помощью селекторов подов (Pod Selector).
Сценарии использования:
Пример
Запустим nginx-под с метками app=web
и env=prod
, а также откроем его 80-й порт:
kubectl run web --image=nginx --labels app=web,env=prod --expose --port 80
Запустим временный под и выполним запрос к сервису web
:
$ kubectl run --rm -i -t --image=alpine test-$RANDOM -- sh
/ # wget -qO- http://web
<!DOCTYPE html>
<html>
<head>
...
Работает! Теперь сохраним следующий манифест в файл web-deny-all.yaml
и применим его к кластеру:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-deny-all
spec:
podSelector:
matchLabels:
app: web
env: prod
$ kubectl apply -f web-deny-all.yaml
networkpolicy "access-nginx" created
Проверка
Запустите контейнер еще раз и попробуйте сделать запрос к сервису web
:
$ kubectl run --rm -i -t --image=alpine test-$RANDOM -- sh
/ # wget -qO- --timeout=2 http://web
wget: download timed out
Трафик заблокирован!
Замечания
В вышеприведенном манифесте для достижения желаемого мы назначили подам специальные метки app=web,env=prod
. Однако в этом файле не хватает поля spec.ingress
. Поэтому к поду запрещен весь трафик.
Если создать другую сетевую политику, которая позволит некоторым подам получить доступ к приложению напрямую или косвенно, первая сетевая политика потеряет силу.
Если есть хотя бы одна сетевая политика с разрешающими трафик правилами, этот трафик пойдет по разрешенному маршруту, невзирая на существование запрещающих правил.
Очистка
kubectl delete deploy web
kubectl delete service web
kubectl delete networkpolicy web-deny-all
Вы можете создать сетевую политику, ограничивающую трафик только от определенных подов.
Сценарии использования:
Предоставление доступа к сервису только тем микросервисам, которым это нужно.
Предоставление доступа к базе данных только использующим ее приложениям.
Пример
Предположим, что в нашем приложении есть сервер REST API c метками app=bookstore
и role=api
:
kubectl run apiserver --image=nginx --labels app=bookstore,role=api --expose --port 80
Сохраните следующую сетевую политику в файл api-allow.yaml
. Она разрешает доступ лишь подам (например, другим микросервисам) с меткой app=bookstore
:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: api-allow
spec:
podSelector:
matchLabels:
app: bookstore
role: api
ingress:
- from:
- podSelector:
matchLabels:
app: bookstore
$ kubectl apply -f api-allow.yaml
networkpolicy "api-allow" created
Проверка
Давайте убедимся, что подам без метки app=bookstore
доступ запрещен:
$ kubectl run test-$RANDOM --rm -i -t --image=alpine -- sh
/ # wget -qO- --timeout=2 http://apiserver
wget: download timed out
Трафик заблокирован!
А теперь давайте проверим, что от подов с меткой app=bookstore
трафик разрешен:
$ kubectl run test-$RANDOM --rm -i -t --image=alpine --labels app=bookstore,role=frontend -- sh
/ # wget -qO- --timeout=2 http://apiserver
<!DOCTYPE html>
<html><head>
Трафик разрешен.
Очистка
kubectl delete deployment apiserver
kubectl delete service apiserver
kubectl delete networkpolicy api-allow
Сценарий использования
Это очень важная политика, которая блокирует весь трафик между подами, за исключением внесенного в белый список с помощью другой политики.
Всерьез подумайте о том, чтобы применить соответствующий манифест во всех пространствах имен, в которых развернута рабочая нагрузка (но не в kube-system
).
С помощью этой политики можно настроить доступ типа «отклонять все по умолчанию» (default "deny all"). Таким образом можно четко определить, какие компоненты зависят от других компонентов, и внедрить сетевые политики, по которым можно построить графы зависимостей между компонентами.
Манифест
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny-all
namespace: default
spec:
podSelector:
matchLabels:
Несколько замечаний:
namespace
— по умолчанию применяйте эту политику в пространстве имен default
.matchLabels
— не заполнено, это означает соответствие всем подам. Таким образом, политика будет применена ко всем подам в указанном пространстве имен.ingress
-правила не определены, поэтому отклоняться будет трафик, идущий к выбранным (всем) подам.Сохраните этот манифест в файл default-deny-all.yaml
и примените политику:
$ kubectl apply -f default-deny-all.yaml
networkpolicy "default-deny-all" created
Очистка
kubectl delete networkpolicy default-deny-all
(также известно под именем LIMIT — ограничение трафика к текущему пространству имен)
Вы можете настроить сетевые политики таким образом, чтобы запретить весь трафик из других пространств имен, при этом разрешив локальный трафик в рамках пространства имен, в котором находится под.
Сценарии использования
test
могли случайно направить какой-либо трафик сервисам или базам данных в пространстве имен prod
.
Пример
Создайте новое пространство имен под названием secondary
и запустите веб-сервис:
kubectl create namespace secondary
kubectl run web --namespace secondary --image=nginx
--labels=app=web --expose --port 80
Сохраните следующий манифест в файл web-deny-other-namespaces.yaml
и примените его к кластеру:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
namespace: secondary
name: web-deny-other-namespaces
spec:
podSelector:
matchLabels:
ingress:
- from:
- podSelector: {}
$ kubectl apply web-deny-other-namespaces.yaml
networkpolicy "web-deny-other-namespaces" created"
Несколько замечаний по поводу манифеста:
namespace: secondary
приведет к применению манифеста в пространстве имен secondary
;secondary
, поскольку spec.podSelector.matchLabels
значения не содержит, выбирая таким образом все поды;secondary
, поскольку spec.ingress.from.podSelector
значения не содержит, что также означает соответствие всем подам.Проверка
Отправьте запрос к этому веб-сервису из пространства имен default
:
$ kubectl run test-$RANDOM --namespace=default --rm -i -t --image=alpine -- sh
/ # wget -qO- --timeout=2 http://web.secondary
wget: download timed out
Трафик из пространства имен default
заблокирован!
При этом любой под из пространства имен secondary
доступ получит:
$ kubectl run test-$RANDOM --namespace=secondary --rm -i -t --image=alpine -- sh
/ # wget -qO- --timeout=2 http://web.secondary
<!DOCTYPE html>
<html>
Очистка
kubectl delete deployment web -n secondary
kubectl delete service web -n secondary
kubectl delete networkpolicy web-deny-other-namespaces -n secondary
kubectl delete namespace secondary
Эта политика похожа на разрешение трафика из всех пространств имен [5], при этом она позволяет выбрать определенное пространство имен.
Сценарии использования:
Пример
Запустите веб-сервер в пространстве имен по умолчанию:
kubectl run web --image=nginx
--labels=app=web --expose --port 80
Теперь предположим, что у вас есть вот такие пространства имен:
default
— создано Kubernetes, здесь развернут ваш API;prod
— здесь развернуты другие production-сервисы; на него установлена метка purpose=prod
;dev
— это dev/test-окружение; на него установлена метка purpose=testing
.Создайте пространства имен prod
и dev
:
kubectl create namespace dev
kubectl label namespace/dev purpose=testing
kubectl create namespace prod
kubectl label namespace/prod purpose=production
Следующий манифест разрешит трафик только от подов, находящихся в пространстве имен с меткой purpose=production
. Сохраните его в web-allow-prod.yaml
и примените к кластеру:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-prod
spec:
podSelector:
matchLabels:
app: web
ingress:
- from:
- namespaceSelector:
matchLabels:
purpose: production
$ kubectl apply -f web-allow-prod.yaml
networkpolicy "web-allow-prod" created
Проверка
Сделайте запрос к веб-серверу из пространства имен dev
, убедитесь, что трафик заблокирован:
$ kubectl run test-$RANDOM --namespace=dev --rm -i -t --image=alpine -- sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.default
wget: download timed out
(трафик заблокирован)
Теперь сделайте запрос из пространства имен prod
, убедитесь, что запрос проходит:
$ kubectl run test-$RANDOM --namespace=prod --rm -i -t --image=alpine -- sh
If you don't see a command prompt, try pressing enter.
/ # wget -qO- --timeout=2 http://web.default
<!DOCTYPE html>
<html>
<head>
...
(трафик разрешен)
Очистка
kubectl delete networkpolicy web-allow-prod
kubectl delete deployment web
kubectl delete service web
kubectl delete namespace {prod,dev}
Эта сетевая политика позволяет внешним клиентам получать доступ к поду через балансировщик нагрузки или напрямую из Интернет.
Сценарии использования:
Пример
Запустите под и откройте его 80-й порт для доступа из Интернет через балансировщик нагрузки:
kubectl run web --image=nginx
--labels=app=web --port 80
kubectl expose deployment/web --type=LoadBalancer
Дождитесь появления EXTERNAL-IP в выводе kubectl get service
. Откройте http://[EXTERNAL-IP]
в браузере и убедитесь в наличии доступа к ресурсу.
Следующий манифест разрешает трафик из любых источников (как внутри кластера, так и из внешних источников). Сохраните его в файл web-allow-external.yaml
и примените к кластеру:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: web-allow-external
spec:
podSelector:
matchLabels:
app: web
ingress:
- from: []
$ kubectl apply -f web-allow-external.yaml
networkpolicy "web-allow-external" created
Снова откройте в браузере http://[EXTERNAL-IP]
и убедитесь, что он по-прежнему работает.
Замечания
В этом манифесте определено одно ingress-правило для подов с меткой app=web
. Поскольку конкретные podSelector
или namespaceSelector
не указаны, будет пропускаться трафик от любых источников, в том числе и внешних.
Чтобы разрешить доступ извне только к 80-му порту, воспользуйтесь следующим ingress-правилом:
ingress:
- ports:
- port: 80
from: []
Очистка
kubectl delete deployment web
kubectl delete service web
kubectl delete networkpolicy web-allow-external
Сетевые политики не являются базовой функциональностью Kubernetes. И хотя вы можете отправить объект NetworkPolicy на мастер Kubernetes, политика не сработает, если соответствующая функциональность не реализована в сетевом плагине.
Примеры сетевых плагинов, поддерживающих сетевые политики, можно найти на этой странице [7]. Также сетевые политики поддерживаются плагинами Calico [8] и Weave Net [9].
В Google Container Engine (GKE) [10] поддержка сетевых политик реализована в начальной стадии (alpha) путем предустановки сетевого плагина Calico.
Сетевые политики применяются к соединениям, а не к сетевым пакетам. Обратите внимание на то, что соединения подразумевают двунаправленную передачу сетевых пакетов. Например, если под А может подключиться к поду Б, под Б может ответить поду А в рамках текущего соединения. Однако это не означает, что под Б может инициировать соединение с подом А.
NetworkPolicy — это один из объектов Kubernetes API. В кластере может быть создано множество таких объектов. В NetworkPolicy есть две основные составляющие:
Вот конкретный пример манифеста NetworkPolicy:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: api-allow
spec:
podSelector:
matchLabels:
app: bookstore
role: api
ingress:
- from:
- podSelector:
matchLabels:
app: bookstore
- from:
- podSelector:
matchLabels:
app: inventory
В этой политике подам с метками app=bookstore
или app=inventory
разрешено подключаться к подам с метками app=bookstore
или role=api
. Ее можно озвучить следующим образом: «Предоставить микросервисам приложения bookstore доступ к bookstore API».
Несмотря на то что проектная документация [11] и справка по API [12] сетевых политик весьма сложны для понимания, мне удалось выделить несколько простых правил:
Дело усложняется в том случае, когда надо настроить сетевое взаимодействие между различными пространствами имен. В двух словах это работает так:
podSelector
можно выбрать только поды из того же пространства имен, в котором развернут объект NetworkPolicy.namespaceSelector
сетевой политики пода Б.Сетевые политики ограничивают сетевой обмен данными между подами и являются важной частью работы по обеспечению безопасности трафика и приложений в кластере Kubernetes. Однако, в отличие от брандмауэров, в рамках сетевых политик не выполняется глубокий анализ пакетов (deep packet inspection).
В деле обеспечения безопасности трафика между подами в кластере не стоит полагаться только на сетевые политики. Рекомендую также присмотреться к таким методам, как TLS (transport layer security) со взаимной аутентификацией, который позволяет зашифровать трафик и выполнять аутентификацию при взаимодействии микросервисов.
Взгляните на Google Cloud Security Whitepaper [13] (выделение сделано мной):
Глубоко эшелонированная оборона (Defense in depth) описывает множество уровней системы безопасности, которая защищает сеть Google от атак извне. Проход разрешен только авторизованным сервисам и протоколам, отвечающим нашим требованиям безопасности. Все остальное отбрасывается автоматически. Для разделения сетей используются брандмауэры промышленного уровня и списки контроля доступа (ACLs). Весь трафик направляется через специальным образом настроенные серверы GFE (Google Front End), что позволяет выявлять и останавливать вредоносные запросы и DDoS-атаки. Также GFE-серверам разрешено взаимодействовать лишь с внутренними серверами, находящимися в особом списке. Такая политика типа «запретить по умолчанию (default deny)» позволяет предотвратить доступ с GFE-серверов к тем ресурсам, которые им не нужны. […]
При передаче через Интернет и внутренние сети данные становятся уязвимы, и к ним может быть осуществлен неавторизованный доступ. […] Серверы Google Front End (GFE) поддерживают надежные протоколы шифрования, такие как TLS, что позволяет обеспечить безопасность соединений между устройствами клиентов и веб-сервисами Google.
Упомянутые мною ранее связанные с сервисными сетками (service mesh) проекты, такие как Istio [3] и linkerd [14], обещают качественные улучшения в этой области. Например, Istio может шифровать трафик между микросервисами с использованием TLS и применять сетевые политики прозрачно, без необходимости менять код приложения.
Если вы хотите попробовать сетевые политики в действии, легче всего будет начать с создания кластера GKE [15]. Также можно почитать следующее:
Благодарю Matthew DeLio и Daniel Nardo за проверку черновиков этой статьи.
Ссылки:
Автор: olemskoi
Источник [17]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/263311
Ссылки в тексте:
[1] kubernetes-networkpolicy-tutorial: https://github.com/ahmetb/kubernetes-networkpolicy-tutorial
[2] документации: https://kubernetes.io/docs/concepts/services-networking/network-policies/
[3] Istio: https://istio.io/
[4] этой статье: http://blog.kubernetes.io/2016/09/high-performance-network-policies-kubernetes.html
[5] разрешение трафика из всех пространств имен: https://github.com/ahmetb/kubernetes-networkpolicy-tutorial/blob/master/05-allow-traffic-from-all-namespaces.md
[6] при этом запрещая весь трафик, не внесенный в белый список: https://github.com/ahmetb/kubernetes-networkpolicy-tutorial/blob/master/03-deny-all-non-whitelisted-traffic-in-the-namespace.md
[7] на этой странице: https://kubernetes.io/docs/concepts/cluster-administration/networking/
[8] Calico: https://kubernetes.io/docs/tasks/administer-cluster/calico-network-policy/
[9] Weave Net: https://kubernetes.io/docs/tasks/administer-cluster/weave-network-policy/
[10] Google Container Engine (GKE): https://cloud.google.com/container-engine
[11] проектная документация: https://github.com/kubernetes/community/blob/b77ecdb66c2c77d1fc36b0b87e8caa5bca6aff88/contributors/design-proposals/network-policy.md#behavior
[12] справка по API: https://kubernetes.io/docs/api-reference/v1.7/#networkpolicyspec-v1-networking
[13] Google Cloud Security Whitepaper: https://cloud.google.com/security/whitepaper#a_global_network_with_unique_security_benefits
[14] linkerd: https://linkerd.io/
[15] создания кластера GKE: https://github.com/ahmetb/kubernetes-networkpolicy-tutorial/blob/master/00-create-cluster.md
[16] Securing Kubernetes Cluster Networking: https://ahmet.im/blog/kubernetes-network-policy/?imm_mid=0f591b&cmp=em-webops-na-na-newsltr_20170818
[17] Источник: https://habrahabr.ru/post/337088/
Нажмите здесь для печати.