Políticas de rede
Se você deseja controlar o fluxo do tráfego de rede no nível do endereço IP ou de portas TCP e UDP
(camadas OSI 3 e 4) então você deve considerar usar Políticas de rede (NetworkPolicies
) do Kubernetes para aplicações
no seu cluster. NetworkPolicy
é um objeto focado em aplicações/experiência do desenvolvedor
que permite especificar como é permitido a um pod
comunicar-se com várias "entidades" de rede.
As entidades que um Pod pode se comunicar são identificadas através de uma combinação dos 3 identificadores à seguir:
- Outros pods que são permitidos (exceção: um pod não pode bloquear a si próprio)
- Namespaces que são permitidos
- Blocos de IP (exceção: o tráfego de e para o nó que um Pod está executando sempre é permitido, independentemente do endereço IP do Pod ou do Nó)
Quando definimos uma política de rede baseada em pod ou namespace, utiliza-se um selector para especificar qual tráfego é permitido de e para o(s) Pod(s) que correspondem ao seletor.
Quando uma política de redes baseada em IP é criada, nós definimos a política baseada em blocos de IP (faixas CIDR).
Pré requisitos
As políticas de rede são implementadas pelo plugin de redes. Para usar
uma política de redes, você deve usar uma solução de redes que suporte o objeto NetworkPolicy
.
A criação de um objeto NetworkPolicy
sem um controlador que implemente essas regras não tem efeito.
Pods isolados e não isolados
Por padrão, pods não são isolados; eles aceitam tráfego de qualquer origem.
Os pods tornam-se isolados ao existir uma NetworkPolicy
que selecione eles. Uma vez que
exista qualquer NetworkPolicy
no namespace selecionando um pod em específico, aquele pod
irá rejeitar qualquer conexão não permitida por qualquer NetworkPolicy
. (Outros pod no mesmo
namespace que não são selecionados por nenhuma outra NetworkPolicy
irão continuar aceitando
todo tráfego de rede.)
As políticas de rede não conflitam; elas são aditivas. Se qualquer política selecionar um pod, o pod torna-se restrito ao que é permitido pela união das regras de entrada/saída de tráfego definidas nas políticas. Assim, a ordem de avaliação não afeta o resultado da política.
Para o fluxo de rede entre dois pods ser permitido, tanto a política de saída no pod de origem e a política de entrada no pod de destino devem permitir o tráfego. Se a política de saída na origem, ou a política de entrada no destino negar o tráfego, o tráfego será bloqueado.
O recurso NetworkPolicy
Veja a referência NetworkPolicy para uma definição completa do recurso.
Uma NetworkPolicy
de exemplo é similar ao abaixo:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: 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
Campos obrigatórios: Assim como todas as outras configurações do Kubernetes, uma NetworkPolicy
necessita dos campos apiVersion
, kind
e metadata
. Para maiores informações sobre
trabalhar com arquivos de configuração, veja
Configurando containeres usando ConfigMap,
e Gerenciamento de objetos.
spec: A spec contém todas as informações necessárias para definir uma política de redes em um namespace.
podSelector: Cada NetworkPolicy
inclui um podSelector
que seleciona o grupo de pods
que a política se aplica. A política acima seleciona os pods com a label "role=db". Um podSelector
vazio seleciona todos os pods no namespace.
policyTypes: Cada NetworkPolicy
inclui uma lista de policyTypes
que pode incluir Ingress
,
Egress
ou ambos. O campo policyTypes
indica se a política se aplica ao tráfego de entrada
com destino aos pods selecionados, o tráfego de saída com origem dos pods selecionados ou ambos.
Se nenhum policyType
for definido então por padrão o tipo Ingress
será sempre utilizado, e o
tipo Egress
será configurado apenas se o objeto contiver alguma regra de saída. (campo egress
a seguir).
ingress: Cada NetworkPolicy
pode incluir uma lista de regras de entrada permitidas através do campo ingress
.
Cada regra permite o tráfego que corresponde simultaneamente às sessões from
(de) e ports
(portas).
A política de exemplo acima contém uma regra simples, que corresponde ao tráfego em uma única porta,
de uma das três origens definidas, sendo a primeira definida via ipBlock
, a segunda via namespaceSelector
e
a terceira via podSelector
.
egress: Cada política pode incluir uma lista de regras de regras de saída permitidas através do campo egress
.
Cada regra permite o tráfego que corresponde simultaneamente às sessões to
(para) e ports
(portas).
A política de exemplo acima contém uma regra simples, que corresponde ao tráfego destinado a uma
porta em qualquer destino pertencente à faixa de IPs em 10.0.0.0/24
.
Então a NetworkPolicy
acima:
-
Isola os pods no namespace "default" com a label "role=db" para ambos os tráfegos de entrada e saída (se eles ainda não estavam isolados)
-
(Regras de entrada/ingress) permite conexões para todos os pods no namespace "default" com a label "role=db" na porta TCP 6379 de:
- qualquer pod no namespace "default" com a label "role=frontend"
- qualquer pod em um namespace que tenha a label "project=myproject" (aqui cabe ressaltar que o namespace que deve ter a label e não os pods dentro desse namespace)
- IPs dentro das faixas 172.17.0.0–172.17.0.255 e 172.17.2.0–172.17.255.255 (ex.:, toda 172.17.0.0/16 exceto 172.17.1.0/24)
-
(Regras de saída/egress) permite conexões de qualquer pod no namespace "default" com a label "role=db" para a faixa de destino 10.0.0.0/24 na porta TCP 5978.
Veja o tutorial Declarando uma política de redes para mais exemplos.
Comportamento dos seletores to
e from
Existem quatro tipos de seletores que podem ser especificados nas sessões ingress.from
ou
egress.to
:
podSelector: Seleciona Pods no mesmo namespace que a política de rede foi criada, e que deve ser permitido origens no tráfego de entrada ou destinos no tráfego de saída.
namespaceSelector: Seleciona namespaces para o qual todos os Pods devem ser permitidos como origens no caso de tráfego de entrada ou destino no tráfego de saída.
namespaceSelector e podSelector: Uma entrada to
/from
única que permite especificar
ambos namespaceSelector
e podSelector
e seleciona um conjunto de Pods dentro de um namespace.
Seja cuidadoso em utilizar a sintaxe YAML correta; essa política:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
podSelector:
matchLabels:
role: client
...
contém um único elemento from
permitindo conexões de Pods com a label role=client
em
namespaces com a label user=alice
. Mas essa política:
...
ingress:
- from:
- namespaceSelector:
matchLabels:
user: alice
- podSelector:
matchLabels:
role: client
...
contém dois elementos no conjunto from
e permite conexões de Pods no namespace local com
a label role=client
, OU de qualquer outro Pod em qualquer outro namespace que tenha
a label user=alice
.
Quando estiver em dúvida, utilize o comando kubectl describe
para verificar como o
Kubernetes interpretou a política.
ipBlock: Isso seleciona um conjunto particular de faixas de IP a serem permitidos como origens no caso de entrada ou destinos no caso de saída. Devem ser considerados IPs externos ao cluster, uma vez que os IPs dos Pods são efêmeros e imprevisíveis.
Os mecanismos de entrada e saída do cluster geralmente requerem que os IPs de origem ou destino
sejam reescritos. Em casos em que isso aconteça, não é definido se deve acontecer antes ou
depois do processamento da NetworkPolicy
que corresponde a esse tráfego, e o comportamento
pode ser diferente para cada plugin de rede, provedor de nuvem, implementação de Service
, etc.
No caso de tráfego de entrada, isso significa que em alguns casos você pode filtrar os pacotes
de entrada baseado no IP de origem atual, enquanto que em outros casos o IP de origem que
a NetworkPolicy
atua pode ser o IP de um LoadBalancer
ou do Nó em que o Pod está executando.
No caso de tráfego de saída, isso significa que conexões de Pods para Services
que são reescritos
para IPs externos ao cluster podem ou não estar sujeitos a políticas baseadas no campo ipBlock
.
Políticas padrão
Por padrão, se nenhuma política existir no namespace, então todo o tráfego de entrada e saída é permitido de e para os pods nesse namespace. Os exemplos a seguir permitem a você mudar o comportamento padrão nesse namespace.
Bloqueio padrão de todo tráfego de entrada
Você pode criar uma política padrão de isolamento para um namespace criando um objeto NetworkPolicy
que seleciona todos os pods mas não permite o tráfego de entrada para esses pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-ingress
spec:
podSelector: {}
policyTypes:
- Ingress
Isso garante que mesmo pods que não são selecionados por nenhuma outra política de rede ainda serão isolados. Essa política não muda o comportamento padrão de isolamento de tráfego de saída nesse namespace.
Permitir por padrão todo tráfego de entrada
Se você deseja permitir todo o tráfego de todos os pods em um namespace (mesmo que políticas que sejam adicionadas faça com que alguns pods sejam tratados como "isolados"), você pode criar uma política que permite explicitamente todo o tráfego naquele namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-ingress
spec:
podSelector: {}
ingress:
- {}
policyTypes:
- Ingress
Bloqueio padrão de todo tráfego de saída
Você pode criar uma política de isolamento de saída padrão para um namespace criando uma política de redes que selecione todos os pods, mas não permita o tráfego de saída a partir de nenhum desses pods.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-egress
spec:
podSelector: {}
policyTypes:
- Egress
Isso garante que mesmo pods que não são selecionados por outra política de rede não seja permitido tráfego de saída. Essa política não muda o comportamento padrão de tráfego de entrada.
Permitir por padrão todo tráfego de saída
Caso você queira permitir todo o tráfego de todos os pods em um namespace (mesmo que políticas sejam adicionadas e cause com que alguns pods sejam tratados como "isolados"), você pode criar uma política explicita que permite todo o tráfego de saída no namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-all-egress
spec:
podSelector: {}
egress:
- {}
policyTypes:
- Egress
Bloqueio padrão de todo tráfego de entrada e saída
Você pode criar uma política padrão em um namespace que previne todo o tráfego de entrada E saída criando a política a seguir no namespace.
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
Isso garante que mesmo pods que não são selecionados por nenhuma outra política de redes não possuam permissão de tráfego de entrada ou saída.
Selecionando uma faixa de portas
Kubernetes v1.21 [alpha]
Ao escrever uma política de redes, você pode selecionar uma faixa de portas ao invés de uma
porta única, utilizando-se do campo endPort
conforme a seguir:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: multi-port-egress
namespace: default
spec:
podSelector:
matchLabels:
role: db
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 32000
endPort: 32768
A regra acima permite a qualquer Pod com a label "role=db" no namespace default
de se comunicar
com qualquer IP na faixa 10.0.0.0/24
através de protocolo TCP, desde que a porta de destino
esteja na faixa entre 32000 e 32768.
As seguintes restrições aplicam-se ao se utilizar esse campo:
- Por ser uma funcionalidade "alpha", ela é desativada por padrão. Para habilitar o campo
endPort
no cluster, você (ou o seu administrador do cluster) deve habilitar o feature gateNetworkPolicyEndPort
nokube-apiserver
com a flag--feature-gates=NetworkPolicyEndPort=true,...
. - O valor de
endPort
deve ser igual ou maior ao valor do campoport
. - O campo
endPort
só pode ser definido se o campoport
também for definido. - Ambos os campos
port
eendPort
devem ser números.
endPort
na especificação da política de redes.
Selecionando um Namespace pelo seu nome
Kubernetes 1.21 [beta]
A camada de gerenciamento do Kubernetes configura uma label imutável kubernetes.io/metadata.name
em
todos os namespaces, uma vez que o feature gate esteja habilitado por padrão.
O valor dessa label é o nome do namespace.
Enquanto que um objeto NetworkPolicy
não pode selecionar um namespace pelo seu nome através de
um campo específico, você pode utilizar essa label padrão para selecionar um namespace pelo seu nome.
O que você não pode fazer com NetworkPolicies
(ao menos por enquanto!)
Por enquanto no Kubernetes 1.23 as funcionalidades a seguir não existem mas você pode conseguir implementar de forma alternativa utilizando componentes do Sistema Operacional (como SELinux, OpenVSwitch, IPtables, etc) ou tecnologias da camada 7 OSI (Ingress controllers, implementações de service mesh) ou ainda admission controllers. No caso do assunto "segurança de redes no Kubernetes" ser novo para você, vale notar que as histórias de usuário a seguir ainda não podem ser implementadas:
- Forçar o tráfego interno do cluster passar por um gateway comum (pode ser implementado via service mesh ou outros proxies)
- Qualquer coisa relacionada a TLS/mTLS (use um service mesh ou ingress controller para isso)
- Políticas específicas a nível do nó kubernetes (você pode utilizar as notações de IP CIDR para isso, mas não pode selecionar nós Kubernetes por suas identidades)
- Selecionar
Services
pelo seu nome (você pode, contudo, selecionar pods e namespaces por seus labels o que torna-se uma solução de contorno viável). - Criação ou gerenciamento
- Políticas padrão que são aplicadas a todos os namespaces e pods (existem alguns plugins externos do Kubernetes e projetos que podem fazer isso, e a comunidade está trabalhando nessa especificação).
- Ferramental de testes para validação de políticas de redes.
- Possibilidade de logar eventos de segurança de redes (conexões bloqueadas, aceitas). Existem plugins CNI que conseguem fazer isso à parte.
- Possibilidade de explicitamente negar políticas de rede (o modelo das
NetworkPolicies
são "negar por padrão e conforme a necessidade, deve-se adicionar regras que permitam o tráfego). - Bloquear o tráfego que venha da interface de loopback/localhost ou que venham do nó em que o Pod se encontre.
Próximos passos
- Veja o tutorial Declarando políticas de redes para mais exemplos.
- Veja mais cenários comuns e exemplos de políticas de redes.