Как можно изолировать поды и пространства имён? В этом нам помогут сетевые модели 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.