
Eu tenho uma arquitetura de microsserviço mais ou menos complexa, onde o Apache Ignite é usado como um banco de dados/cache sem estado. O Ignite Pod
é o único Pod
e Namespace
a arquitetura tem que passar por uma auditoria de segurança, que não vai passar se eu não aplicar o mais restritivo NetworkPolicy
possível para egress
o tráfego. Ele deve restringir todo o tráfego possível que não seja necessário para o próprio Ignite.
A princípio pensei:Legal, o Ignite não envia nenhum tráfego para outros Pod
s (não há outros pods nele Namespace
), então isso será feito facilmente, restringindo todo egress
o tráfego onde Namespace
o Ignite é o único Pod
!...
Bem, na verdade isso não funcionou muito bem:
qualquer egress
regra, mesmo se eu permitir o tráfego para todas as portas mencionadas na documentação do Ignite, fará com que a inicialização falhe com um IgniteSpiException
que dizFalha ao recuperar endereços IP dos pods do Ignite, Caused by: java.net.ConnectException: Operation timed out (Connection timed out)
.
O problema parece ser oTcpDiscoveryKubernetsIpFinder
, especialmente o método getRegisteredAddresses(...)
que obviamente faz algum tráfego de saída dentro do Namespace
para registrar endereços IP de nós Ignite. A porta de descoberta 47500 é obviamente permitida, mas isso não muda a situação. A funcionalidade do Ignite com os outros Pod
s de outros Namespace
s está funcionando sem egress
regras aplicadas, o que significa (para mim) que a configuração relativa a ClusterRole
, ClusterRoleBinding
, a Service
e Namespace
a configuração xml do próprio Ignite etc. Até mesmo ingress
as regras que restringem o tráfego de outros namespaces estão funcionando conforme o esperado, permitindo exatamente o tráfego desejado.
Estas são as políticas que apliquei:
[TRABALHANDO, bloqueando apenas tráfego indesejado]:
## 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
Com esses dois aplicados, tudo está funcionando bem, mas a auditoria de segurança dirá algo como
Para onde estão as restrições egress
? E se esse nó for invadido por meio das rotas permitidas porque um dos pods que usa essas rotas foi invadido antes? Ele pode chamar um servidor C&C então! Esta configuração não será permitida, proteja sua arquitetura!
[BLOQUEANDO tráfego desejado/necessário]:
Geralmente negar todo o tráfego ...
## 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
... e permitir rotas específicas posteriormente
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
A versão do Apache Ignite usada é 2.10.0
Agora a pergunta para todos os leitores é:
Como posso restringir Egress
ao mínimo absoluto dentro do Ignite Namespace
para que o Ignite seja iniciado e funcione corretamente? Seria suficiente apenas negar Egress
para fora do cluster?
Se você precisar de mais yaml
sugestões ou sugestões, sinta-se à vontade para solicitá-las em um comentário.
E desculpe pela marcação, se parecer inadequada, não consegui encontrar a tag, kubernetes-networkpolicy
pois ela está presente no stackoverflow.
ATUALIZAR:
Executando nslookup -debug kubernetes.default.svc.cluster.local
de dentro do pod de ignição sem qualquer política que restrinja egress
os shows
BusyBox v1.29.3 (2019-01-24 07:45:07 UTC) multi-call binary.
Usage: nslookup HOST [DNS_SERVER]
Query DNS about HOST
Assim que (qualquer) NetworkPolicy
for aplicado que restrinja Egress
a portas, pods e namespaces específicos, o pod Ignite se recusa a iniciar e a pesquisa não alcança kubernetes.default.svc.cluster.local
mais.
Egress
para DNS foi permitido (UDP 53 para k8s-app: kube-dns) ⇒ ainda não é possível pesquisar IP