
У меня есть более или менее сложная архитектура микросервисов, где Apache Ignite используется как база данных без сохранения состояния / кэш. Ignite Pod
— единственный Pod
в своем роде Namespace
, и архитектура должна пройти аудит безопасности, который она не пройдет, если я не применю максимально NetworkPolicy
возможные ограничения для egress
трафика. Она должна ограничить весь возможный трафик, который не нужен самому Ignite.
Сначала я подумал:Отлично, Ignite не перенаправляет трафик в другие Pod
модули (в них нет других модулей Namespace
), так что это можно будет легко сделать, ограничив весь egress
трафик в модуле, Namespace
в котором Ignite — единственный модуль Pod
!...
Ну, на самом деле это не сработало:
любое egress
правило, даже если я разрешу трафик на все порты, упомянутые в документации Ignite, приведет к сбою запуска с IgniteSpiException
сообщением:Не удалось получить IP-адреса модулей Ignite., Caused by: java.net.ConnectException: Operation timed out (Connection timed out)
.
Проблема, похоже, в том,TcpDiscoveryKubernetsIpFinder
, особенно метод getRegisteredAddresses(...)
, который, очевидно, делает некоторый исходящий трафик внутри Namespace
для регистрации IP-адресов узлов Ignite. Порт обнаружения 47500, конечно, разрешен, но это не меняет ситуацию. Функциональность Ignite с другими Pod
s из других Namespace
s работает без egress
применения правил, что означает (для меня), что конфигурация, касающаяся ClusterRole
, ClusterRoleBinding
, a Service
в Namespace
и конфигурация xml самого Ignite и т. д., кажется правильной. Даже ingress
правила, ограничивающие трафик из других пространств имен, работают так, как и ожидалось, разрешая именно желаемый трафик.
Вот какие политики я применил:
[РАБОТАЕТ, блокирует только нежелательный трафик]:
## Denies all Ingress traffic to all Pods in the Namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-ingress-in-cache-ns
namespace: cache-ns
spec:
# selecting nothing here will deny all traffic between pods in the namespace
podSelector:
matchLabels: {}
# traffic routes to be considered, here: incoming exclusively
policyTypes:
- Ingress
## Allows necessary ingress traffic
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: netpol-cache-ns
namespace: cache-ns
# defines the pod(s) that this policy is targeting
spec:
policyTypes:
- Ingress
podSelector:
matchLabels:
app: ignite
# <----incoming traffic----
ingress:
- from:
- namespaceSelector:
matchLabels:
zone: somewhere-else
podSelector:
matchExpressions:
- key: app
operator: In
values: [some-pod, another-pod] # dummy names, these Pods don't matter at all
ports:
- port: 11211 # JDBC
protocol: TCP
- port: 47100 # SPI communication
protocol: TCP
- port: 47500 # SPI discovery (CRITICAL, most likely...)
protocol: TCP
- port: 10800 # SQL
protocol: TCP
# ----outgoing traffic---->
# NONE AT ALL
При применении этих двух правил все работает нормально, но аудит безопасности выдаст что-то вроде
Где ограничения для egress
? Что, если этот узел будет взломан через разрешенные маршруты, потому что один из Pod, использующих эти маршруты, был взломан ранее? Тогда он может вызвать сервер C&C! Эта конфигурация не будет разрешена, укрепите свою архитектуру!
[БЛОКИРОВКА желаемого/необходимого трафика]:
Обычно запрещает весь трафик...
## Denies all traffic to all Pods in the Namespace
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-traffic-in-cache-ns
namespace: cache-ns
spec:
# selecting nothing here will deny all traffic between pods in the namespace
podSelector:
matchLabels: {}
# traffic routes to be considered, here: incoming exclusively
policyTypes:
- Ingress
- Egress # <------ THIS IS THE DIFFERENCE TO THE WORKING ONE ABOVE
... и впоследствии разрешить определенные маршруты
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: netpol-cache-ns-egress
namespace: cache-ns
# defines the pod(s) that this policy is targeting
spec:
policyTypes:
- Egress
podSelector:
matchLabels:
app: ignite
----outgoing traffic---->
egress:
# [NOT SUFFICIENT]
# allow egress to this namespace at specific ports
- to:
- namespaceSelector:
matchLabels:
zone: cache-zone
ports:
- protocol: TCP
port: 10800
- protocol: TCP
port: 47100 # SPI communication
- protocol: TCP
port: 47500
# [NOT SUFFICIENT]
# allow dns resolution in general (no namespace or pod restriction)
- ports:
- protocol: TCP
port: 53
- protocol: UDP
port: 53
# [NOT SUFFICIENT]
# allow egress to the kube-system (label is present!)
- to:
- namespaceSelector:
matchLabels:
zone: kube-system
# [NOT SUFFICIENT]
# allow egress in this namespace and for the ignite pod
- to:
- namespaceSelector:
matchLabels:
zone: cache-zone
podSelector:
matchLabels:
app: ignite
# [NOT SUFFICIENT]
# allow traffic to the IP address of the ignite pod
- to:
- ipBlock:
cidr: 172.21.70.49/32 # won't work well since those addresses are dynamic
ports:
- port: 11211 # JDBC
protocol: TCP
- port: 47100 # SPI communication
protocol: TCP
- port: 47500 # SPI discovery (CRITICAL, most likely...)
protocol: TCP
- port: 49112 # JMX
protocol: TCP
- port: 10800 # SQL
protocol: TCP
- port: 8080 # REST
protocol: TCP
- port: 10900 # thin clients
protocol: TCP
Используемая версия Apache Ignite — 2.10.0.
Теперь вопрос ко всем читателям:
Как я могу ограничить Egress
до абсолютного минимума внутри, Namespace
чтобы Ignite запустился и работал правильно? Будет ли достаточно просто запретить Egress
за пределами кластера?
Если вам нужны еще какие-либо yaml
s для обоснованной догадки или подсказки, пожалуйста, не стесняйтесь запрашивать их в комментарии.
И извините за тегирование, если оно кажется неуместным, я не смог найти тег, kubernetes-networkpolicy
так как он присутствует на stackoverflow.
ОБНОВЛЯТЬ:
Выполнение nslookup -debug kubernetes.default.svc.cluster.local
изнутри модуля Ignite без каких-либо политик, ограничивающих egress
шоу
BusyBox v1.29.3 (2019-01-24 07:45:07 UTC) multi-call binary.
Usage: nslookup HOST [DNS_SERVER]
Query DNS about HOST
Как только NetworkPolicy
применяется (любой) параметр, ограничивающий Egress
определенные порты, модули и пространства имен, модуль Ignite отказывается запускаться, и поиск kubernetes.default.svc.cluster.local
больше не выполняется.
Egress
к DNS разрешен (UDP 53 к k8s-app: kube-dns) ⇒ поиск IP по-прежнему невозможен