Introdução às políticas de rede do Kubernetes para especialistas em segurança

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

(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 kubectl, para criá-la no cluster:

kubectl create -f policy.yaml

Especificação da política de rede

A especificação da política de rede do Kubernetes consiste em quatro elementos:

  1. podSelector: define os pods afetados por esta política (alvos) — obrigatório;
  2. 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;
  3. ingress: define o tráfego de entrada permitido para os pods-alvo — opcional;
  4. 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

Introdução às políticas de rede do Kubernetes para especialistas em segurança
Introdução às políticas de rede do Kubernetes para especialistas em segurança

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.yaml

Recomendo 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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança
Introdução às políticas de rede do Kubernetes para especialistas em segurança

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.

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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.

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança
Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

3. Diferentes políticas também são combinadas com um OU lógico

Mas ao combiná-las, existe uma limitação à qual referiu Chris Cooney: 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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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: v2

A 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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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

Introdução às políticas de rede do Kubernetes para especialistas em segurança

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 yaml

Tenha 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 aqui — 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:

  1. 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 Istio.
  2. Alguns fornecedores de CNI aprimoraram suas ferramentas para que fossem além das políticas de rede do Kubernetes.
  3. Tufin Orca 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:

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster