Network Policies
Vamos iniciar com o básico de redes...

As respostas ficam permitidas para quem enviou a requisição. Precisamos controlar o que ela pode receber e para onde elas podem ir.
Neste cenário:
A aplicação frontend deve permitir um tráfego de entrada na porta 443 HTTPS que ela escuta para a Internet e deve permitir a comunicação com o backend na porta 5000.
A aplicação backend somente deve aceitar solicitação na porta 5000, responde-las, e pode fazer solicitação para o database na porta 3306.
O database somente aceita solicitações na porta 3306 e respondê-las, não aceitando sair para lugar nenhum.
Para isso precisamos criar regras para os ingress e egress dessas aplicações.
Ingress Rule são as regras de entrada e Egress Rule são as regras de saída.
Quais regras são necessárias para que tudo funcione?
-
Frontend
- Permitir porta 443 em ingress
- Permitir backend:5000 em egress
-
Backend
- Permitir porta 5000 em ingress
- Permitir database:3306 de egress
-
Database
- Permitir porta 3306 em ingress
Um dos pré requisitos para o workflow no kubernetes é que qualquer pod possa se comunicar com os outros sem nenhuma configuração adicional como rotas.

Nesta solução de redes todos os pods estão é uma rede virtual que se estende através dos nodes no cluster kubernetes e todos eles, POR PADRÃO, podem chegar aos outros através de ips, nomes e services configurados para este propósito.
O Kubernetes é configurado por padrão com uma regra (All Allow) que permite o tráfego de qualquer pod para qualquer outro pod.
Voltando ao cenário proposto, tanto o frontend, backend e database podem se comunicar entre si sem nenhum impedimento dentro do cluster. As regras estão indo além do que queremos; para isso precisamos restringir esses pods.
Políticas de rede são aplicadas aos pods, não nos pods. É uma regra completamente independente do pod.
Por exemplo, precisamos que o database somente permita tráfego vindo dos pods backend na porta 3306.
Para vincular uma regra de rede a um pod, usamos a mesma técnica que vinculamos replicasets com pods e services com pods, usando labels e selectors.


apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dbpolicy
spec:
podSelector:
# Será aplicada em todos os pods que tem a label app: database
matchLabels:
app: database
policyTypes:
- Ingress
# Regras de entrada aceita o tráfego de pods que tem a label app: backend
ingress:
- from:
- podSelector:
matchLabels:
app: backend
# Na porta 3306 usando protocolo tcp
ports:
- protocol: TCP
port: 3306
Só existe efeito se tiver ingress e ou egress no policy types pois a regra deve ser aplicada ou na entrada ou na saída.
O CNI usado para solução de network no cluster deve suportar o network policies, caso contrário não surtirá efeito.
Calico, Cilium, Weavenet, Kube-router suportam nativamente network policies
Flannel não suporta.
Agora vamos pensar no seguinte. Temos diferentes pods que podem ter o mesmo label, mas em diferentes namespaces.

Dessa forma podemos também fechar a nível de namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dbpolicy
spec:
podSelector:
# Será aplicada em todos os pods que tem a label app: database
matchLabels:
app: database
policyTypes:
- Ingress
# Regras de entrada aceita o tráfego de pods que tem a label app: backend e estão no namespace prod.
ingress:
- from:
- podSelector:
matchLabels:
app: backend
namespaceSelector:
matchLabels:
name: prod
# Na porta 3306 usando protocolo tcp
ports:
- protocol: TCP
port: 3306
Se somente usarmos o namespaceSelector todos os pods dentro do namespace poderiam ter acesso ao database.
E se um servidor de backup precisasse acessar diretamente esse database? Na regra anterior não funcionaria.
Porém se analisarmos melhor o yaml veremos que from é uma lista de regras que são permitidas. Se alguma das regras satisfazer então pode passar. No exemplo acima somente temos uma regra (ser do namespace prod e ter a label backend). Vamos adicionar então uma outra regra.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dbpolicy
spec:
podSelector:
# Será aplicada em todos os pods que tem a label app: database
matchLabels:
app: database
policyTypes:
- Ingress
# Regras de entrada aceita o tráfego de pods que tem a label app: backend e estão no namespace prod.
ingress:
- from:
########### 1 regra ##########
- podSelector:
matchLabels:
app: backend
namespaceSelector:
matchLabels:
name: prod
########### 2 regra ##########
- ipBlock:
cidr: 192.168.5.10/32 #Ip do servidor de backup
# Na porta 3306 usando protocolo tcp
ports:
- protocol: TCP
port: 3306
Isso mostra que temos duas regras de entrada e qualquer uma que for satisfeita é suficiente para permitir a conexão.
Regra 1 - Estar no namespace de prod e o pod precisa ter a label app: backend Regra 2 - A conexão precisaria vir de 192.168.5.10
Se tivesse feito isso, apenas cometido o erro de colocar um - na frente de namespaceSelector.
ingress:
- from:
- podSelector:
matchLabels:
app: backend
- namespaceSelector:
matchLabels:
name: prod
- ipBlock:
cidr: 192.168.5.10/32 #Ip do servidor de backup
Teria 3 regras diferentes:
Regra 1 - Qualquer pod que tenha a label app: backend não interessando o namespace poderia ser permitido.
Regra 2 - Qualquer pod no namespace prod seria permitido
Regra 3 - A requisição vinda do ip 192.168.5.10 seria permitida
Basta um erro aqui que tudo pode mudar!
Mas vamos imaginar que o database quem conecta com o backup na porta 80 e não o contrário, logo.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dbpolicy
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
- Egress # Adicionado também regra de saída
ingress:
- from:
- podSelector:
matchLabels:
app: backend
namespaceSelector:
matchLabels:
name: prod
ports:
- protocol: TCP
port: 3306
egress:
- to:
- ipBlock:
cidr: 192.168.5.10/32
ports:
- protocol: TCP
port: 80
Tanto o from do ingress e o to do egress também são listas. Logo poderíamos ainda ter mais regras dentro da mesma police.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dbpolicy
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
- Egress # Adicionado também regra de saída
ingress:
- from:
- podSelector:
matchLabels:
app: backend
namespaceSelector:
matchLabels:
name: prod
ports:
- protocol: TCP
port: 3306
- from:
- podSelector:
matchLabels:
app: backend
namespaceSelector:
matchLabels:
name: staging
ports:
- protocol: TCP
port: 3306
egress:
- to:
- ipBlock:
cidr: 192.168.5.10/32
ports:
- protocol: TCP
port: 80
- to:
- ipBlock:
cidr: 192.168.5.10/32
ports:
- protocol: TCP
port: 443
Eu sei que isso poderia ser mais simples, mas foi só para ilustrar.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: dbpolicy
spec:
podSelector:
matchLabels:
app: database
policyTypes:
- Ingress
- Egress # Adicionado também regra de saída
ingress:
- from:
- podSelector:
matchLabels:
app: backend
matchExpressions:
- key: name
operator: In
values:
- prod
- staging
ports:
- protocol: TCP
port: 3306
egress:
- to:
- ipBlock:
cidr: 192.168.5.10/32
ports:
- protocol: TCP
port: 80
ports:
- protocol: TCP
port: 443