Как можно изолировать поды и пространства имён? В этом нам помогут сетевые модели Kubernetes.
Сетевая модель Kubernetes определяет, что:
Каждый под получает собственный IP-адрес.
Поды могут взаимодействовать с любыми другими подами в кластере при помощи IP-адресов подов (без NAT).
Изоляция (ограничение того, с чем может взаимодействовать каждый под) определяется сетевыми политиками.
Давайте создадим два пространства имён и развернём в них несколько подов, а после этого потестируем, как именно поды взаимодействуют друг с другом в кластере Kubernetes.
Взаимодействие между подами в пределах одного пространства имён
Создайте новое пространство имён с именем prod и разверните в нём три пода.
# Create a new namespace and add label to that namespaces > kubectl create ns prod > kubectl label ns prod team=prod # Change context to the new context (namespace) > kubectl config set-context --current --namespace=prod # Deploy three webservers into the prod namespace > kubectl run webserver-1 --image=nginx --labels='role=webserver-1' > kubectl run webserver-2 --image=nginx --labels='role=webserver-2' > kubectl run webserver-3 --image=nginx --labels='role=webserver-3' # Fetch the IP-Addresses of the pods > kubectl get pods -o wide ----------------------------------------------------------------- NAME READY STATUS RESTARTS AGE IP webserver-1 1/1 Running 0 3m7s 10.244.189.206 webserver-2 1/1 Running 0 2m21s 10.244.151.207 webserver-3 1/1 Running 0 2m15s 10.244.151.208 -----------------------------------------------------------------
Создайте другое пространство имён с именем dev и разверните в нём два пода.
# Create a new namespace and add label to that namespaces > kubectl create ns dev > kubectl label ns dev team=dev # Deploy two pod into the dev namespace > kubectl run testserver-1 --image=nginx --labels='role=testserver-1' -n dev > kubectl run testserver-2 --image=nginx --labels='role=testserver-2' -n dev # Fetch the IP-Addresses of the pods > kubectl get pods -o wide -A | grep -i ------------------------------------------------------------------------------ NAMESPACE NAME READY STATUS RESTARTS AGE IP dev testserver-1 1/1 Running 0 3m7s 10.244.189.207 dev testserver-2 1/1 Running 0 2m21s 10.244.189.208 ------------------------------------------------------------------------------
Теперь давайте посмотрим, могут ли два пода (webserver-1 и webserver-2) взаимодействовать друг с другом в одном пространстве имён (prod):
# Dive into the webserver-1 resides in the "prod" namespace > kubectl exec -it webserver-1 -n prod bash # Run curl to access pod named "webserver-2" resides in the same namespace root@webserver-1:> curl 10.244.151.207 #ip-address of the "webserver-2" pod ------------------------------------------------------------------------------------------ <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> # Successfully accessed <style> .... ------------------------------------------------------------------------------------------
Аналогичным образом webserver-2 может взаимодействовать с webserver-3.
Взаимодействие между подами из разных пространств имён
Теперь мы протестируем связь между двумя пространствами имён. Давайте посмотрим, сможет ли под (testserver-1), находящийся в пространстве имён “dev”, взаимодействовать с подом (webserver-1), находящимся в пространстве имён “prod”:
# Dive into the pod "testserver-1" resides in the "dev" namespace > kubectl exec -it testserver-1 -n dev bash # Run curl to access the pod named "webserver-1" resides in the "prod" namespace root@testserver-1:> curl 10.244.189.206 #ip-address of the "webserver-1" pod ------------------------------------------------------------------------------------------ <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> # Successfully accessed <style> ... ------------------------------------------------------------------------------------------
Мы увидели, что под может свободно взаимодействовать с другими подами; даже поды из разных пространств имён могут взаимодействовать друг с другом. В многопользовательской производственной среде распространена практика распределения доступов между подами. В Kubernetes распределение доступов между подами осуществляется с помощью сетевых политик (Network Policy).
Сетевая политика (Network Policy)
Сетевая политика позволяет нам ограничивать входящий и исходящий трафик в поды и из подов. Используя сетевые политики, мы можем сдерживать входящий трафик баз данных подов только backend подами, а также мы можем ограничить входящий трафик backend пода только frontend подом. В результате, если абстрактный злоумышленник получит доступ к frontend приложениям, он не сможет напрямую получить доступ к базам данных подов или любым другим подам.
Что касается программного и аппаратного обеспечения, то управление трафиком может осуществляться при помощи брандмауэров. Но, в случае с Kubernetes, функциональность управления трафиком реализуется сетевыми плагинами и контролируется сетевыми политиками.
Предварительные условия
Сетевой плагин реализует сетевые политики. Для применения сетевых политик вы должны использовать решение, поддерживающее сетевые политики.
Подробнее о сетевых плагинах и процессе установки.
Пошаговая инструкция
Давайте пошагово пройдёмся по сетевой политике, представленной ниже.
--- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: test-network-policy namespace: database-tier spec: podSelector: # To which the policy applies. matchLabels: role: db policyTypes: # Include either Ingress, Egress, or both. - Ingress - Egress ingress: # Allows traffic which matches both the "from" and "ports" sections. - from: - namespaceSelector: # Allows a all pods within a praticular namespace. matchLabels: tier: web-tier - podSelector: # Allows a particular pod. matchLabels: role: frontend ports: # Allows a particular "protocol" and "port". - protocol: TCP port: 8080 egress: # Allows traffic which matches both the "to" and "ports" sections. - to: - ipBlock: # Allows a particular IP CIDR ranges. cidr: 10.3.0.0/16 except: # Restricts a particular IP CIDR ranges. - 10.3.1.0/24 ports: - protocol: TCP port: 32000 # Targeting a range of ports. endPort: 32768 # The "endPort" must be equal to or greater than the "port". ---
Предостережения
namespaceSelector И podSelector
Если мы хотим разрешить связь с определённым под'ом или от него ( to/from) в пределах определённого пространства имён, мы должны настроить правила следующим образом —
.. ingress: - from: - namespaceSelector: # matchLabels: # tier: database # Allows after matching podSelector: # namespaceSelector AND podSelector matchLabels: # role: db # ...
namespaceSelector ИЛИ podSelector
Если мы хотим разрешить трафику входить или выходить из опредёленного пространства имён (to/from) или определённым группам подов впускать и выпускать трафик из любых пространст�� имён (to/from), тогда мы должны настроить правила следующим образом —
... ingress: - from: - namespaceSelector: # matchLabels: # tier: database # Allows after matching - podSelector: # namespaceSelector OR podSelector matchLabels: # role: db # ...
1. Входящий трафик
1.1 Разрешите входящий трафик из подов в том же пространстве имён
# Create the network-policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-allow-ingress.yaml --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-ingress-webserver-1 namespace: prod spec: podSelector: matchLabels: role: webserver-1 policyTypes: - Ingress ingress: - from: - podSelector: matchLabels: role: webserver-2 ports: - port: 80 ---
Если мы создадим сетевую политику, используя вышеприведённый файл манифеста, то наш webserver-1 разрешит только входящий трафик с webserver-2, но поскольку мы ничего не настраивали для исходящего трафика, webserver-1 может отправить исходящий трафик на webserver-2 и webserver-3. Посмотрите на следующее изображение для лучшего понимания:
1.1.0 Входящий тест
# Dive into the webserver-2 pod > kubectl exec -it webserver-2 bash # Try to reach webserver-1 pod > curl 10.244.189.206 #IP address of webserver-1 pod --------------------------------------------------------------- <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ... --------------------------------------------------------------- # Exit from the webserver-2 pod # Dive into the webserver-3 pod > kubectl exec -it webserver-3 bash # Try to reach webserver-1 pod > curl 10.244.189.206 #IP address of webserver-1 pod --------------------------------------------------------------- You can see that from webserver-3 to webserver-1 is unreachable ---------------------------------------------------------------
1.2 Разрешить входящий трафик из подов в другом пространстве имён
# Create a network policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-allow-ingress-from-different-ns.yaml --- kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: allow-ingress-from-different-ns namespace: prod spec: podSelector: matchLabels: role: webserver-1 ingress: - from: - podSelector: matchLabels: role: testserver-1 namespaceSelector: matchLabels: team: dev ports: - port: 80 ---
Если мы создадим сетевую политику, используя вышеприведённый файл манифеста, то webserver-1 разрешит только входящий трафик с testserver-1, который находится в другом пространстве имён с именем dev. Посмотрите на следующее изображение для лучшего понимания:
Теперь позвольте мне спросить вас: testserver-1 из пространства имён dev может получить доступ только к webserver-1 или также может получить доступ ко всем существующим площадкам в пространстве имён prod?
Ответ ДА!
Прямо сейчас testserver1 из пространства имён dev сможет получить доступ не только к поду webserver-1 или группе подов, но также ко всем существующим подам в пространстве имён prod.
Если вы не хотите задействовать все поды в разных пространствах имён, лучше всего по умолчанию применить к пространствам имён сетевую политику deny-all ingress.
1.3 Создайте политику deny-all ingress по умолчанию
Следующая сетевая политика реализует политику deny-all ingress по умолчанию, которая запрещает весь входящий трафик на поды в определённом пространстве имён.
# Create default deny-all ingress network policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-default-deny-all-ingress.yaml --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-ingress namespace: prod spec: podSelector: matchLabels: {} policyTypes: - Ingress ---
Весь входящий трафик на поды в определённом пространстве имён (prod) будет запрещён, если только трафик явно не разрешён другой сетевой политикой.
Когда мы применим политику deny-all ingress по умолчанию вместе со входом из другого пространства имён, после этого из разных пространств имён можно будет получить доступ только к выбранным подам.
2. Исходящий трафик
2.1 Разрешите исходящий трафик для подов в том же пространстве имён
# Create the network-policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-allow-egress-from-pod.yaml --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-egress-from-webserver-3 namespace: prod spec: podSelector: matchLabels: role: webserver-1 policyTypes: - Egress egress: - to: - podSelector: matchLabels: role: webserver-3 ports: - protocol: TCP port: 80 ---
Когда мы создадим сетевую политику, используя приведённый выше файл манифеста, ваш webserver-1 сможет отправлять только исходящий трафик на webserver-3. Но поскольку мы ничего не настраивали для входящего трафика, webserver-1 разрешит входящий трафик из любого пространства. Посмотрите на следующее изображение для лучшего понимания:
2.1.0 Исходящий тест
# Dive into the webserver-1 pod > kubectl exec -it webserver-1 bash # Try to reach webserver-2 pod > curl 10.244.151.207 #IP address of webserver-2 pod --------------------------------------------------------------- You will see, webserver-2 is unreachable from webserver-1 --------------------------------------------------------------- # Try to reach webserver-3 pod > curl 10.244.151.208 #IP address of webserver-3 pod --------------------------------------------------------------- <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> ... ---------------------------------------------------------------
2.2 Разрешите исходящий трафик для подов в разных пространствах имён
# Create network policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-allow-egress-different-namespace.yaml --- kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: allow-egress-different-namespace namespace: prod spec: podSelector: matchLabels: role: webserver-1 egress: - to: - podSelector: matchLabels: role: testserver-1 namespaceSelector: matchLabels: team: dev ports: - port: 80 ---
Если мы создадим сетевую политику, используя приведённый выше файл манифеста, то наш под webserver-1 в пространстве имён prod сможет отправлять исходящий трафик только на определённые поды (testserver-1) в пространстве имён dev. Другие поды, находящиеся в пространстве имён dev, не смогут быть доступны с подов webserver-1. Для лучшего понимания:
В приведённой выше иллюстрации мы увидели, что webserver-1 может отправлять трафик только на под testserver-1. Но мы также должны иметь в виду, что не только под webserver-1 может отправлять трафик в под testserver-1, но и другие поды, находящиеся в пространстве имён prod, могут отправлять трафик в пространство имён dev.
Если вы не хотите разрешать другим подам в пространстве имён prod отправлять исходящий трафик в пространство имён dev или предотвращать случайный доступ к подам, рекомендуется применять политику по умолчанию deny-all egress наряду с другими политиками.
# Create default deny-all-egress network policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-default-deny-all-egress.yaml --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-egress namespace: prod spec: podSelector: matchLabels: {} policyTypes: - Egress ---
Выбранные поды смогут отправлять исходящий трафик в разные пространства имён только при условии, что мы применим политику deny-all ingress.
3. Deny all ingress по умолчанию и весь исходящий трафик
Мы можем создать default-политику для пространства имён, которая предотвращает весь входящий и исходящий трафик, создав следующую NetworkPolicy в этом пространстве имён
# Create default deny-all network policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-default-deny-all.yaml --- kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: default-deny-all namespace: prod spec: podSelector: matchLabels: {} policyTypes: - Ingress - Egress ---
Это гарантирует, что всем подам в определенном пространстве имён (в данном случае - prod) не будет разрешён входящий или исходящий трафик, если только трафик явно не разрешён другой сетевой политикой.

Бонус
Давайте ещё чуть подробнее рассмотрим сетевые политики.
Предположим, у нас имеется несколько пространств имён в кластере k8s, но у нас также есть требование изолировать наше пространство имён prod от других пространств имён. Единственное пространство имён, которое может получить доступ к пространству имён prod, — это пространство имён dev. Давайте посмотрим, как мы можем этого достичь:
Чтобы достичь вышеописанной цели, для начала нужно применить сетевые политики deny-all ingress и all-egress traffic по умолчанию к пространству имён prod. Затем нужно применить другую сетевую политику к пространству имён prod. Таким образом, все поды в пространстве имён prod смогут разрешать входящий трафик только из пространства имён dev. Создайте сетевую политику, используя следующий файл манифеста —
# Allow ingress from dev namespace by creating a network policy using the following manifest file: > kubectl create -f \ https://raw.githubusercontent.com/shamimice03/Kubernetes/main/Security/netpol-from-ns.yaml --- apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-dev-namespace-ingress namespace: prod spec: podSelector: matchLabels: {} ingress: - from: - podSelector: matchLabels: {} namespaceSelector: matchLabels: team: dev ---
После применения сетевой политики, показанной выше, только пространство имён dev сможет отправлять трафик в пространство имён prod.
