
Nota do tradutor.: O autor do artigo — Reuven Harrison — tem mais de 20 anos de experiência em desenvolvimento de software e, atualmente, é diretor técnico e cofundador da Tufin, que cria soluções para gerenciamento de políticas de segurança. Ao considerar as políticas de rede do Kubernetes como uma ferramenta poderosa para segmentação de rede em clustes, ele também acredita que não são tão fáceis de aplicar na prática. Este material (bastante extenso) destina-se a aumentar a conscientização dos profissionais sobre o assunto e ajudá-los na criação das configurações necessárias.
Hoje, muitas empresas estão cada vez mais optando pelo Kubernetes para executar suas aplicações. O interesse por este software é tão grande que alguns o chamam de "novo sistema operacional para data centers". Gradualmente, o Kubernetes (ou k8s) começa a ser visto como uma parte crítica do negócio, que requer a organização de processos de negócios maduros, incluindo a garantia de segurança de rede.
Para os profissionais de segurança que estão perplexos com o trabalho no Kubernetes, uma verdadeira revelação pode ser a política padrão dessa plataforma: permitir tudo.
Este guia ajudará a entender a estrutura interna das políticas de rede; compreenderá como elas diferem das regras para firewalls comuns. Também serão discutidas algumas armadilhas e fornecidas recomendações que ajudarão a proteger as aplicações no Kubernetes.
Políticas de Rede do Kubernetes
O mecanismo de políticas de rede do Kubernetes permite gerenciar a interação das aplicações implantadas na plataforma em nível de rede (o terceiro na modelo OSI). As políticas de rede carecem de algumas funcionalidades avançadas dos firewalls modernos, como controle no nível 7 do OSI e detecção de ameaças, no entanto, elas proporcionam um nível básico de segurança de rede, que serve como um bom ponto de partida.
As políticas de rede controlam as comunicações entre pods
As cargas de trabalho no Kubernetes são distribuídas entre pods, que consistem em um ou mais contêineres implantados juntos. O Kubernetes atribui a cada pod um endereço IP acessível a partir de outros pods. As políticas de rede do Kubernetes definem permissões de acesso para grupos de pods de forma semelhante a como grupos de segurança na nuvem são usados para gerenciar o acesso a instâncias de máquinas virtuais.
Definição de políticas de rede
Assim como outros recursos do Kubernetes, as políticas de rede são definidas na linguagem YAML. No exemplo abaixo, o aplicativo balance obtém acesso a postgres:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: balance
policyTypes:
- Ingress 
(Nota do tradutor.: esta captura de tela, assim como todas as seguintes semelhantes, foi criada não com ferramentas nativas do Kubernetes, mas com a ferramenta Tufin Orca, desenvolvida pela empresa do autor do artigo original, mencionada no final do material.)
Para definir sua própria política de rede, você precisará de conhecimentos básicos de YAML. Esta linguagem é baseada em recuos (definidos por espaços, e não por tabulações). Um elemento com recuo pertence ao elemento mais próximo acima com recuo. Um novo item de lista começa com um hífen; todos os outros itens têm a forma chave-valor.
Após descrever a política em YAML, use , para criá-la no cluster:
kubectl create -f policy.yamlEspecificação da política de rede
A especificação da política de rede do Kubernetes consiste em quatro elementos:
-
podSelector: define os pods afetados por esta política (alvos) — obrigatório; -
policyTypes: indica quais tipos de políticas estão incluídos nela: ingress e/ou egress — opcional, mas recomendo que seja explicitamente descrito em todos os casos; -
ingress: define o tráfego de entrada permitido para os pods-alvo — opcional; -
egress: define o tráfego tráfego de saída dos pods-alvo — opcional.
O exemplo, retirado do site do Kubernetes (substituí role para app), mostra como todos os quatro elementos são utilizados:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector: # <<<<
matchLabels:
app: db
policyTypes: # <<<<
- Ingress
- Egress
ingress: # <<<<
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress: # <<<<
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978 

Observe que não é necessário incluir todos os quatro elementos. Apenas podSelectoros demais parâmetros podem ser usados à vontade.
Se você omitir policyTypes, a política será interpretada como:
- Por padrão, presume-se que ela define a parte de ingress. Se não houver indicações explícitas a esse respeito na política, o sistema considerará que todo o tráfego está proibido.
- O comportamento na parte de egress será determinado pela presença ou ausência do parâmetro egress correspondente.
Para evitar erros, recomendo sempre especificar de forma explícita. policyTypes.
De acordo com a lógica acima, caso os parâmetros ingress e/ou egress sejam omitidos, a política proibirá todo o tráfego (veja "Regra de limpeza" abaixo).
A política padrão é permitir
Se as políticas não forem definidas, o Kubernetes por padrão permite todo o tráfego. Todos os pods podem se comunicar livremente entre si. Do ponto de vista da segurança, isso pode parecer ilógico, mas lembre-se de que o Kubernetes foi originalmente criado por desenvolvedores para garantir a interação entre aplicações. As políticas de rede foram adicionadas posteriormente.
Namespaces
Namespaces (Espaços de Nomes) são um mecanismo de trabalho colaborativo do Kubernetes. Eles são destinados a isolar ambientes lógicos uns dos outros, permitindo que a troca de dados entre namespaces seja, por padrão, permitida.
Como a maioria dos componentes do Kubernetes, as políticas de rede habitam em um namespace específico. No bloco metadata é possível especificar a qual espaço pertence a política:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: my-namespace # <<<<
spec:
... Se o namespace nas metadados não estiver explicitamente especificado, o sistema usará o namespace indicado no kubectl (por padrão namespace=default):
kubectl apply -n my-namespace -f namespace.yamlRecomendo especificar o namespace de forma explícita., a menos que você esteja escrevendo uma política destinada a vários namespaces de uma só vez.
Principal elemento podSelector na política será selecionar pods do namespace ao qual a política pertence (ele não tem acesso a pods de outro namespace).
Da mesma forma, os podSelectors nos blocos ingress e egress podem selecionar pods apenas do seu próprio namespace, a menos que você os combine usando namespaceSelector sobre o qual falaremos na seção "Filtrar por namespaces e pods".
Regras de nomenclatura de políticas
Os nomes das políticas são únicos dentro de um único namespace. Não pode haver duas políticas com o mesmo nome em um namespace, mas pode haver políticas com nomes idênticos em namespaces diferentes. Isso é conveniente quando você deseja reaplicar a mesma política em vários namespaces.
Uma das maneiras de nomear que eu particularmente gosto envolve combinar o nome do namespace com os pods-alvo. Por exemplo:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres # <<<
namespace: default
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- podSelector:
matchLabels:
app: admin
policyTypes:
- Ingress 
Rótulos
A objetos Kubernetes, como pods e namespaces, podem ser anexados rótulos personalizados. Rótulos (labels — tags) são equivalentes a tags na nuvem. As políticas de rede do Kubernetes usam rótulos para selecionar pods, aos quais se aplicam:
podSelector:
matchLabels:
role: db… ou namespaces, aos quais se aplicam. Neste exemplo, todos os pods em namespaces com os rótulos correspondentes são selecionados:
namespaceSelector:
matchLabels:
project: myproject Uma advertência: ao usar namespaceSelector verifique se os namespaces selecionados contêm o rótulo necessário. Lembre-se de que namespaces incorporados, como padrão e kube-system, por padrão, não contêm rótulos.
Para adicionar um rótulo a um namespace, você pode fazer da seguinte forma:
kubectl label namespace default namespace=default Nesse caso, o namespace na seção metadata deve referir-se ao nome real do namespace, e não ao rótulo:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default # <<<
spec:
...Fonte e destinatário
Políticas para firewalls consistem em regras com fontes e destinatários. Políticas de rede do Kubernetes são definidas para o objetivo — um conjunto de pods aos quais se aplicam, e então estabelecem regras para tráfego de entrada (ingress) e/ou saída (egress). No nosso exemplo, o objetivo da política serão todos os pods no namespace padrão com rótulo com a chave app e valor db:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
app: db # <<<
policyTypes:
- Ingress
- Egress
ingress:
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978 

Seção ingress nesta política abre o tráfego de entrada para os pods de destino. Em outras palavras, ingress atua como fonte, e o objetivo — como destinatário correspondente. Da mesma forma, egress é o destinatário, e o objetivo — sua fonte.

Isso é equivalente a duas regras para o firewall: Ingress → Objetivo; Objetivo → Egress.
Egress e DNS (importante!)
Ao restringir o tráfego de saída, preste especial atenção ao DNS — Kubernetes utiliza este serviço para mapear serviços a endereços IP. Por exemplo, a seguinte política não funcionará, pois você não permitiu que a aplicação balance acessasse o DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
policyTypes:
- Egress 
Corrigi-la pode ser feito liberando o acesso ao serviço DNS:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to: # <<<
ports: # <<<
- protocol: UDP # <<<
port: 53 # <<<
policyTypes:
- Egress 
O último elemento para — vazio, e portanto escolhe indiretamente todos os pods em todos os namespaces, permitindo balance enviar consultas DNS ao serviço Kubernetes correspondente (geralmente executado no namespace kube-system).
Essa abordagem funciona, no entanto, é excessivamente permissiva e insegura, pois permite direcionar consultas DNS para fora do cluster.
Melhorá-la pode ser feito em três etapas sequenciais.
1. Permitir consultas DNS apenas dentro do cluster, adicionando namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to:
- namespaceSelector: {} # <<<
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress 
2. Permitir consultas DNS apenas no namespace kube-system.
Para isso, é necessário adicionar um rótulo ao namespace kube-system: kubectl label namespace kube-system namespace=kube-system — e registrá-lo na política com namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
egress:
- to:
- podSelector:
matchLabels:
app: postgres
- to:
- namespaceSelector: # <<<
matchLabels: # <<<
namespace: kube-system # <<<
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress 
3. Os paranóicos podem ir ainda mais longe e restringir consultas DNS a um serviço DNS específico em kube-system. Na seção "Filtrando por namespaces e pods" será explicado como conseguir isso.
Outra opção é permitir DNS no nível do namespace. Nesse caso, não será necessário abrir para cada serviço:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.dns
namespace: default
spec:
podSelector: {} # <<<
egress:
- to:
- namespaceSelector: {}
ports:
- protocol: UDP
port: 53
policyTypes:
- Egress Vazio podSelector seleciona todos os pods no namespace.

A primeira correspondência e a ordem das regras
Em firewalls comuns, a ação ("Permitir" ou "Negar") em relação a um pacote é determinada pela primeira regra que ele satisfaz. No Kubernetes, a ordem das políticas não importa.
Por padrão, quando as políticas não são definidas, as comunicações entre pods são permitidas e eles podem trocar informações livremente. Assim que você começa a formular políticas, cada pod afetado por pelo menos uma delas se torna isolado de acordo com a disjunção (lógica OU) de todas as políticas que o selecionaram. Pods que não são afetados por nenhuma política permanecem abertos.
Esse comportamento pode ser alterado com uma regra de limpeza.
Regra de limpeza ("Negar")
As políticas de firewall normalmente negam qualquer tráfego que não seja explicitamente permitido.
No Kubernetes, não existe a ação "negar" (deny), no entanto, um efeito semelhante pode ser alcançado com uma política (permissiva) comum, selecionando um grupo de pods de origem vazio (ingress):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
namespace: default
spec:
podSelector: {}
policyTypes:
- Ingress 
Esta política seleciona todos os pods no namespace e deixa o ingress indefinido, proibindo todo o tráfego de entrada.
De maneira semelhante, você pode restringir todo o tráfego de saída do namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all-egress
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress 
Considere que qualquer política adicional que permita tráfego para os pods no namespace terá prioridade sobre esta regra (semelhante a adicionar uma regra de permissão antes de uma proibição na configuração do firewall).
Permitir tudo (Any-Any-Any-Allow)
Para criar uma política "Permitir tudo", é necessário complementar a política de proibição acima com um elemento vazio ingress:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
namespace: default
spec:
podSelector: {}
ingress: # <<<
- {} # <<<
policyTypes:
- Ingress 
Isso abre o acesso de todos os pods em todos os namespaces (e todos os IPs) a qualquer pod no namespace padrão. Comportamento semelhante está habilitado por padrão, portanto, geralmente não é necessário defini-lo adicionalmente. No entanto, às vezes pode ser necessário desativar temporariamente algumas permissões específicas para diagnosticar um problema.
A regra pode ser restringida e permitir acesso apenas a um conjunto específico de pods (app:balance) no namespace padrão:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-to-balance
namespace: default
spec:
podSelector:
matchLabels:
app: balance
ingress:
- {}
policyTypes:
- Ingress 
A política seguinte permite todo o tráfego de entrada (ingress) e saída (egress), incluindo acesso a qualquer IP fora do cluster:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all
spec:
podSelector: {}
ingress:
- {}
egress:
- {}
policyTypes:
- Ingress
- Egress 

A combinação de várias políticas
as políticas se combinam usando lógico OU em três níveis; as permissões de cada pod são determinadas pela disjunção de todas as políticas que o afetam:
1. Nos campos Harvard University e para podem ser definidos três tipos de elementos (todos combinados usando OU):
-
namespaceSelector— seleciona o namespace inteiro; -
podSelector— seleciona pods; -
ipBlock— seleciona uma sub-rede.
Nesse caso, o número de elementos (mesmo que iguais) nas subdivisões Harvard University/para não é limitado. Todos eles serão combinados logicamente por OU.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- podSelector:
matchLabels:
app: admin
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
2. Dentro da política, a seção ingress pode conter múltiplos elementos Harvard University (que são combinados com um OU lógico). Da mesma forma, a seção egress pode incluir muitos elementos para (também combinados por disjunção):
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- from:
- podSelector:
matchLabels:
app: admin
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
3. Diferentes políticas também são combinadas com um OU lógico
Mas ao combiná-las, existe uma limitação à qual : o Kubernetes pode combinar políticas apenas com diferentes policyTypes (Ingress ou Egress). Políticas que definem ingress (ou egress) irão sobrescrever umas às outras.
Vínculo entre namespaces
Por padrão, a comunicação entre namespaces é permitida. Isso pode ser alterado por meio de uma política restritiva que limita o tráfego de entrada e/ou saída para um namespace (veja "Regra de limpeza" acima).
Ao bloquear o acesso a um namespace (veja "Regra de limpeza" acima), você pode fazer exceções à política restritiva, permitindo conexões de um namespace específico através de namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector: # >>>
matchLabels:
namespace: default
policyTypes:
- Ingress 
Como resultado, todos os pods no namespace padrão terão acesso a pods postgres no namespace database. Mas e se você quiser abrir acesso apenas a postgres pods específicos dentro do namespace padrão?
Filtragem por namespaces e pods
Kubernetes versão 1.11 e superior permite combinar operadores namespaceSelector e podSelector usando um E lógico. Isso se parece com o seguinte:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector:
matchLabels:
namespace: default
podSelector: # >>>
matchLabels:
app: admin
policyTypes:
- Ingress 
Por que isso é interpretado como E em vez do esperado OU?
Observe que podSelector não começa com um hífen. No YAML, isso significa que podSelector e o que está antes dele namespaceSelector pertencem ao mesmo elemento da lista. Portanto, eles são combinados com um E.
Adicionar um hífen antes de podSelector levará à criação de um novo item de lista que será combinado com o anterior namespaceSelector usando a lógica OU.
Para selecionar pods com um determinado rótulo em todos os namespaces, digite vazio namespaceSelector:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: database.postgres
namespace: database
spec:
podSelector:
matchLabels:
app: postgres
ingress:
- from:
- namespaceSelector: {}
podSelector:
matchLabels:
app: admin
policyTypes:
- Ingress 
Vários rótulos são combinados com E
Regras de firewall com múltiplos objetos (hosts, redes, grupos) são combinadas usando a lógica OU. A próxima regra será aplicada se a origem do pacote coincidir com Host_1 OU Host_2:
| Fonte | Destino | Serviço | Ação |
| ----------------------------------------|
| Host_1 | Subnet_A | HTTPS | Permitir |
| Host_2 | | | |
| ----------------------------------------| Por outro lado, no Kubernetes, diferentes rótulos em podSelector ou namespaceSelector são combinados com a lógica E. Por exemplo, a próxima regra selecionará os pods que possuem ambos os rótulos, role=db eu posso usar version=v2:
podSelector:
matchLabels:
role: db
version: v2A mesma lógica se aplica a todos os tipos de operadores: seletores de destino de políticas, seletores de pods e seletores de namespaces.
Sub-redes e endereços IP (IPBlocks)
Para segmentação de rede, os firewalls usam VLANs, endereços IP e sub-redes.
No Kubernetes, endereços IP são atribuídos a pods automaticamente e podem mudar frequentemente, por isso rótulos são usados para selecionar pods e namespaces nas políticas de rede.
Sub-redes (ipBlocks) são usadas ao gerenciar conexões externas (North-South) de entrada (ingress) ou saída (egress). Por exemplo, esta política permite que todos os pods do namespace padrão acessam o serviço DNS do Google:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-dns
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 8.8.8.8/32
ports:
- protocol: UDP
port: 53 
Um seletor de pods vazio neste exemplo significa 'selecionar todos os pods no namespace'.
Esta política apenas permite acesso a 8.8.8.8; o acesso a qualquer outro IP é negado. Basicamente, você bloqueou o acesso ao serviço DNS interno do Kubernetes. Se você quiser abri-lo, especifique isso explicitamente.
Normalmente ipBlocks e podSelectors são mutuamente exclusivos, uma vez que endereços IP internos de pods não são usados em ipBlocks. Ao especificar endereços IP internos de pods, você está basicamente permitindo conexões de/para pods com esses endereços. Na prática, você não saberá qual IP usar, por isso não deve usar para escolher pods.
Como contraexemplo, a seguinte política inclui todos os IPs e, portanto, permite o acesso a todos os outros pods:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-any
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 
Você pode abrir acesso apenas para IPs externos, excluindo endereços IP internos dos pods. Por exemplo, se a sub-rede do seu pod for 10.16.0.0/14:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: egress-any
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 10.16.0.0/14 
Portas e protocolos
Normalmente, os pods escutam em uma única porta. Isso significa que você pode simplesmente não especificar números de porta nas políticas e deixar tudo como padrão. No entanto, recomenda-se que as políticas sejam tão restritivas quanto possível, por isso, em alguns casos, ainda é possível especificar portas:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
- podSelector:
matchLabels:
app: admin
ports: # <<<
- port: 443 # <<<
protocol: TCP # <<<
- port: 80 # <<<
protocol: TCP # <<<
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
Observe que o seletor ports se aplica a todos os elementos no bloco para ou Harvard University, no qual está contido. Para especificar portas diferentes para diferentes conjuntos de elementos, divida ingress ou egress em vários subblocos com para ou Harvard University e, em cada um, escreva suas próprias portas:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default.postgres
namespace: default
spec:
ingress:
- from:
- podSelector:
matchLabels:
app: indexer
ports: # <<<
- port: 443 # <<<
protocol: TCP # <<<
- from:
- podSelector:
matchLabels:
app: admin
ports: # <<<
- port: 80 # <<<
protocol: TCP # <<<
podSelector:
matchLabels:
app: postgres
policyTypes:
- Ingress 
Funcionamento das portas por padrão:
- Se você omitir completamente a definição de portas (
ports), isso significa todos os protocolos e todas as portas; - Se você omitir a definição do protocolo (
protocol), isso significa TCP; - Se você omitir a definição da porta (
port), isso significa todas as portas.
Melhor prática: não confie nos valores padrão, especifique o que você precisa explicitamente.
Observe que é necessário usar as portas dos pods, e não as dos serviços (mais detalhes no próximo parágrafo).
As políticas estão definidas para pods ou serviços?
Normalmente, os pods em Kubernetes se comunicam entre si através de serviços — um balanceador de carga virtual, que redireciona o tráfego para os pods que implementam o serviço. Pode-se pensar que as políticas de rede controlam o acesso aos serviços, mas não é o caso. As políticas de rede do Kubernetes funcionam com as portas dos pods, e não com os serviços.
Por exemplo, se um serviço escuta na porta 80, mas redireciona o tráfego para a porta 8080 dos seus pods, a política de rede deve especificar exatamente 8080.
Esse mecanismo deve ser considerado subótimo: ao alterar a configuração interna do serviço (as portas que os pods escutam), será necessário atualizar as políticas de rede.
Uma nova abordagem arquitetural usando Service Mesh (por exemplo, veja sobre Istio abaixo — nota do tradutor) resolve essa questão.
É necessário definir tanto o Ingress quanto o Egress?
A resposta curta é sim; para que o pod A possa se conectar ao pod B, é necessário permitir que ele estabeleça uma conexão de saída (para isso, é preciso configurar a política de egress), e o pod B deve ter a capacidade de aceitar uma conexão de entrada (para isso, logicamente, é necessária uma política de ingress).
No entanto, na prática, pode-se confiar na política padrão, que permite conexões em uma ou ambas as direções.
Se um determinado podfonte for selecionado por uma ou mais egress-políticas, as restrições aplicáveis a ele serão determinadas por sua disjunção. Nesse caso, será necessário permitir explicitamente a conexão com o pod-destinatário. Se o pod não for selecionado por nenhuma política, seu tráfego de saída (egress) é permitido por padrão.
De forma análoga, o status do pod-destinatário, selecionado por uma ou mais ingress-políticas, será determinado por sua disjunção. Nesse caso, será necessário permitir explicitamente que ele receba tráfego do pod de origem. Se o pod não for selecionado por nenhuma política, todo o tráfego de entrada (ingress) para ele é permitido por padrão.
Veja a seção "Stateful ou Stateless" abaixo.
Logs
As políticas de rede do Kubernetes não conseguem registrar o tráfego. Isso dificulta a determinação se a política está funcionando corretamente e complica bastante a análise na área de segurança.
Controle do tráfego para serviços externos
As políticas de rede do Kubernetes não permitem especificar um nome de domínio completo (DNS) nas seções de egress. Este fato causa considerável inconveniente ao tentar restringir o tráfego para destinos externos sem um endereço IP fixo (como aws.com).
Verificação de Política
Os firewalls irão alertá-lo ou até mesmo se recusarão a aceitar uma política incorreta. O Kubernetes também realiza alguma verificação. Ao definir uma política de rede através do kubectl, o Kubernetes pode afirmar que está incorreta e se recusar a aceitá-la. Em outros casos, o Kubernetes aceitará a política e a completará com detalhes faltantes. Eles podem ser visualizados com o comando:
kubernetes get networkpolicy -o yamlTenha em mente que o sistema de verificação do Kubernetes não é infalível e pode deixar passar alguns tipos de erros.
Execução
O Kubernetes não implementa as políticas de rede por conta própria, mas é apenas um gateway de API, transferindo o trabalho de controle para o sistema subjacente chamado Container Networking Interface (CNI). Definir políticas em um cluster Kubernetes sem atribuir um CNI apropriado é semelhante a criar políticas em um servidor de firewall sem instalá-las posteriormente nos firewalls. Você deve garantir que haja um CNI adequado ou, em ambientes Kubernetes hospedados na nuvem, (a lista de provedores pode ser consultada — nota do tradutor), acionar as políticas de rede que estabelecerão o CNI por você.
Observe que o Kubernetes não o alertará se você definir uma política de rede sem um CNI auxiliar apropriado.
Stateful ou Stateless?
Todos os CNIs do Kubernetes com os quais me deparei armazenam estados (por exemplo, o Calico usa o Linux conntrack). Isso permite que um pod receba respostas de uma conexão TCP iniciada por ele, sem a necessidade de reestabelecê-la. No entanto, não estou ciente de um padrão do Kubernetes que garanta a manutenção de estado.
Gerenciamento avançado de políticas de segurança
Aqui estão algumas maneiras de aumentar a eficácia na execução de políticas de segurança no Kubernetes:
- O padrão arquitetônico Service Mesh usa contêineres sidecar para garantir telemetria detalhada e controle do tráfego em nível de serviço. Como exemplo, podemos citar .
- Alguns fornecedores de CNI aprimoraram suas ferramentas para que fossem além das políticas de rede do Kubernetes.
- oferece visibilidade e automação das políticas de rede do Kubernetes.
O pacote Tufin Orca gerencia as políticas de rede do Kubernetes (e serve como fonte das capturas de tela apresentadas acima).
Informações adicionais
- ;
- ;
- ;
- .
Conclusão
As políticas de rede do Kubernetes oferecem um bom conjunto de ferramentas para segmentar clusters, mas são intuitivamente confusas e apresentam muitas sutilezas. Acredito que devido a essa complexidade, as políticas de muitos clusters existentes contêm erros. Possíveis soluções para esse problema incluem a automação das definições de políticas ou a aplicação de outras ferramentas de segmentação.
Espero que este guia ajude a esclarecer algumas questões e resolver problemas que você possa encontrar.
P.S. do tradutor
Confira também em nosso blog:
- «De Volta aos Microserviços com Istio»: , , ;
- «Guia ilustrado para a estrutura da rede no Kubernetes»: , ;
- «»;
- «»;
- «».
Fonte: habr.com
