Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Observação. trad.: O autor do artigo, Reuven Harrison, tem mais de 20 anos de experiência em desenvolvimento de software e hoje é CTO e cofundador da Tufin, empresa que cria soluções de gerenciamento de políticas de segurança. Embora ele veja as políticas de rede do Kubernetes como uma ferramenta bastante poderosa para segmentação de rede em um cluster, ele também acredita que elas não são tão fáceis de implementar na prática. Este material (bastante volumoso) pretende aumentar a consciência dos especialistas sobre esta questão e ajudá-los a criar as configurações necessárias.

Hoje, muitas empresas estão escolhendo cada vez mais o Kubernetes para executar suas aplicações. O interesse neste software é tão grande que alguns chamam o Kubernetes de “o novo sistema operacional para o data center”. Gradualmente, o Kubernetes (ou k8s) começa a ser percebido como uma parte crítica do negócio, o que requer a organização de processos de negócio maduros, incluindo segurança de rede.

Para os profissionais de segurança que ficam intrigados ao trabalhar com o Kubernetes, a verdadeira revelação pode ser a política padrão da plataforma: permitir tudo.

Este guia ajudará você a compreender a estrutura interna das políticas de rede; entenda como elas diferem das regras dos firewalls regulares. Ele também abordará algumas armadilhas e fornecerá recomendações para ajudar a proteger aplicativos no Kubernetes.

Políticas de rede Kubernetes

O mecanismo de política de rede Kubernetes permite gerenciar a interação de aplicativos implantados na plataforma na camada de rede (a terceira no modelo OSI). As políticas de rede carecem de alguns dos recursos avançados dos firewalls modernos, como a aplicação da camada 7 do OSI e a detecção de ameaças, mas fornecem um nível básico de segurança de rede que é 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 que pode ser acessado de outros pods. As políticas de rede Kubernetes definem direitos de acesso para grupos de pods da mesma forma que grupos de segurança na nuvem são usados ​​para controlar o acesso a instâncias de máquinas virtuais.

Definição de políticas de rede

Como outros recursos do Kubernetes, as políticas de rede são especificadas em YAML. No exemplo abaixo, o aplicativo balance 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

(Observação. trad.: esta captura de tela, como todas as subsequentes semelhantes, não foi criada usando ferramentas nativas do Kubernetes, mas usando a ferramenta Tufin Orca, que foi desenvolvida pela empresa do autor do artigo original e 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 recuo (especificado por espaços em vez de tabulações). Um elemento recuado pertence ao elemento recuado mais próximo acima dele. Um novo elemento da lista começa com um hífen, todos os outros elementos têm a forma valor chave.

Tendo descrito a política em YAML, use kubectlpara criá-lo no cluster:

kubectl create -f policy.yaml

Especificação de política de rede

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

  1. podSelector: define os pods afetados por esta política (destinos) - obrigatório;
  2. policyTypes: indica quais tipos de políticas estão incluídas: entrada e/ou saída - opcional, mas recomendo especificá-la explicitamente em todos os casos;
  3. ingress: define permitido de entrada o tráfego para pods de destino é opcional;
  4. egress: define permitido extrovertido o tráfego dos pods de destino é opcional.

Exemplo retirado do site do Kubernetes (substituí role em app), mostra como todos os quatro elementos são usados:

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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança
Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Observe que todos os quatro elementos não precisam ser incluídos. Só é obrigatório podSelector, outros parâmetros podem ser usados ​​conforme desejado.

Se você omitir policyTypes, a política será interpretada da seguinte forma:

  • Por padrão, presume-se que defina o lado de entrada. Se a política não declarar isso explicitamente, o sistema assumirá que todo o tráfego é proibido.
  • O comportamento no lado de saída será determinado pela presença ou ausência do parâmetro de saída correspondente.

Para evitar erros eu recomendo sempre deixe isso explícito policyTypes.

De acordo com a lógica acima, se os parâmetros ingress e / ou egress omitido, a política negará todo o tráfego (consulte "Regra de remoção" abaixo).

A política padrão é Permitir

Se nenhuma política for definida, o Kubernetes permitirá todo o tráfego por padrão. Todos os pods podem trocar informações livremente entre si. Isso pode parecer contra-intuitivo do ponto de vista da segurança, mas lembre-se de que o Kubernetes foi originalmente projetado por desenvolvedores para permitir a interoperabilidade de aplicativos. As políticas de rede foram adicionadas posteriormente.

Espaços para nome

Namespaces são o mecanismo de colaboração do Kubernetes. Eles são projetados para isolar ambientes lógicos uns dos outros, enquanto a comunicação entre espaços é permitida por padrão.

Como a maioria dos componentes do Kubernetes, as políticas de rede residem em um namespace específico. No bloco metadata você pode especificar a qual espaço a política pertence:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: my-namespace  # <<<
spec:
...

Se o namespace não for especificado explicitamente nos metadados, o sistema usará o namespace especificado em kubectl (por padrão namespace=default):

kubectl apply -n my-namespace -f namespace.yaml

Eu recomendo especifique o namespace explicitamente, a menos que você esteja escrevendo uma política que vise vários namespaces de uma só vez.

Primário elemento podSelector na política selecionará pods do namespace ao qual a política pertence (é negado o acesso aos pods de outro namespace).

Da mesma forma, podSelectors em blocos de entrada e saída só pode selecionar pods de seu próprio namespace, a menos que você os combine com namespaceSelector (isso será discutido na seção “Filtrar por namespaces e pods”).

Regras de nomenclatura de políticas

Os nomes das políticas são exclusivos no mesmo namespace. Não pode haver duas políticas com o mesmo nome no mesmo espaço, mas pode haver políticas com o mesmo nome em espaços diferentes. Isto é útil quando você deseja reaplicar a mesma política em vários espaços.

Gosto especialmente de um dos métodos de nomenclatura. Consiste em combinar o nome do namespace com os pods de destino. 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Etiquetas

Você pode anexar rótulos personalizados a objetos do Kubernetes, como pods e namespaces. Etiquetas (Labels - tags) são equivalentes às tags na nuvem. As políticas de rede do Kubernetes usam rótulos para selecionar vagensa que se aplicam:

podSelector:
  matchLabels:
    role: db

… ou espaços para nomea que se aplicam. Este exemplo seleciona todos os pods em namespaces com os rótulos correspondentes:

namespaceSelector:
  matchLabels:
    project: myproject

Um cuidado: ao usar namespaceSelector certifique-se de que os namespaces selecionados contenham o rótulo correto. Esteja ciente de que namespaces integrados, como default и kube-system, por padrão não contêm rótulos.

Você pode adicionar um rótulo a um espaço como este:

kubectl label namespace default namespace=default

Ao mesmo tempo, namespace na seção metadata deve referir-se ao nome real do espaço, não ao rótulo:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: test-network-policy
  namespace: default   # <<<
spec:
...

Fonte e destino

As políticas de firewall consistem em regras com origens e destinos. As políticas de rede do Kubernetes são definidas para um destino - um conjunto de pods aos quais se aplicam - e, em seguida, definem regras para tráfego de entrada e/ou saída. Em nosso exemplo, o alvo da política serão todos os pods no namespace default com etiqueta com chave app e significado 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança
Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Subseção ingress nesta política, abre o tráfego de entrada para os pods de destino. Em outras palavras, o ingresso é a origem e o destino é o destino correspondente. Da mesma forma, a saída é o destino e o alvo é a sua origem.

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Isso equivale a duas regras de firewall: Ingress → Target; Meta → Saída.

Saída e DNS (importante!)

Ao limitar o tráfego de saída, preste atenção especial ao DNS - Kubernetes usa este serviço para mapear serviços para endereços IP. Por exemplo, a política a seguir não funcionará porque você não permitiu o aplicativo balance acessar 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Você pode consertar abrindo 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Último elemento to está vazio e, portanto, seleciona indiretamente todos os pods em todos os namespaces, permitindo balance enviar consultas DNS para o serviço Kubernetes apropriado (geralmente em execução no espaço kube-system).

Esta abordagem funciona, mas excessivamente permissivo e inseguro, porque permite que as consultas DNS sejam direcionadas para fora do cluster.

Você pode melhorá-lo em três etapas sucessivas.

1. Permitir apenas consultas DNS dentro 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

2. Permitir consultas DNS apenas dentro do namespace kube-system.

Para fazer isso você precisa adicionar um rótulo ao namespace kube-system: kubectl label namespace kube-system namespace=kube-system - e anote na política usando 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

3. Pessoas paranóicas podem ir ainda mais longe e limitar as consultas DNS a um serviço DNS específico em kube-system. A seção “Filtrar por namespaces e pods” explicará como fazer isso.

Outra opção é resolver o DNS no nível do namespace. Neste caso, não será necessário abri-lo 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

nulo podSelector seleciona todos os pods no namespace.

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Primeira partida e ordem das regras

Nos firewalls convencionais, a ação (Permitir ou Negar) em um pacote é determinada pela primeira regra que ele satisfaz. No Kubernetes, a ordem das políticas não importa.

Por padrão, quando nenhuma política é definida, as comunicações entre os pods são permitidas e eles podem trocar informações livremente. Uma vez iniciada a formulação de políticas, cada pod afetado por pelo menos uma delas fica isolado de acordo com a disjunção (OR lógico) de todas as políticas que o selecionaram. Os pods não afetados por nenhuma política permanecem abertos.

Você pode alterar esse comportamento usando uma regra de remoção.

Regra de remoção (“Negar”)

As políticas de firewall normalmente negam qualquer tráfego que não seja explicitamente permitido.

Não há ação de negação no Kubernetes, no entanto, um efeito semelhante pode ser alcançado com uma política regular (permissiva) selecionando um grupo vazio de pods de origem (entrada):

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Ingress

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Esta política seleciona todos os pods no namespace e deixa a entrada indefinida, negando todo o tráfego de entrada.

De maneira semelhante, você pode restringir todo o tráfego de saída de um namespace:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: deny-all-egress
  namespace: default
spec:
  podSelector: {}
  policyTypes:
  - Egress

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Por favor note que quaisquer políticas adicionais que permitam o tráfego para pods no namespace terão precedência sobre esta regra (semelhante a adicionar uma regra de permissão antes de uma regra de negação em uma configuração de firewall).

Permitir tudo (Any-Any-Any-Allow)

Para criar uma política Permitir tudo, você precisa complementar a política Negar acima com um elemento vazio ingress:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: default
spec:
  podSelector: {}
  ingress: # <<<
  - {}     # <<<
  policyTypes:
  - Ingress

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Permite acesso de todos os pods em todos os namespaces (e todos os IPs) para qualquer pod no namespace default. Esse comportamento é habilitado por padrão, portanto geralmente não precisa ser definido posteriormente. No entanto, às vezes pode ser necessário desabilitar temporariamente algumas permissões específicas para diagnosticar o problema.

A regra pode ser reduzida para permitir acesso apenas a um conjunto específico de pods (app:balance) no espaço para nome default:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all-to-balance
  namespace: default
spec:
  podSelector:
    matchLabels:
      app: balance
  ingress: 
  - {}
  policyTypes:
  - Ingress

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

A política a seguir permite todo o tráfego de entrada e saída, 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança
Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Combinando múltiplas políticas

As políticas são combinadas usando OR lógico em três níveis; As permissões de cada pod são definidas de acordo com a disjunção de todas as políticas que o afetam:

1. Nos campos from и to Três tipos de elementos podem ser definidos (todos combinados usando OR):

  • namespaceSelector — seleciona todo o namespace;
  • podSelector — seleciona frutos;
  • ipBlock — seleciona uma sub-rede.

Além disso, o número de elementos (mesmo os idênticos) nas subseções from/to não limitado. Todos eles serão combinados por OR lógico.

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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

2. Dentro da seção de políticas ingress pode ter muitos elementos from (combinado por OR lógico). Da mesma forma, seção egress pode incluir muitos elementos to (também combinado 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

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

Mas ao combiná-los, há uma limitação na qual indicado Chris Cooney: O Kubernetes só pode combinar políticas com diferentes policyTypes (Ingress ou Egress). As políticas que definem a entrada (ou saída) substituir-se-ão umas às outras.

Relacionamento entre namespaces

Por padrão, o compartilhamento de informações entre namespaces é permitido. Isso pode ser alterado usando uma política de negação que restringirá o tráfego de saída e/ou entrada no namespace (consulte "Regra de remoção" acima).

Depois de bloquear o acesso a um namespace (consulte a "Regra de remoção" acima), você poderá abrir exceções à política de negação, permitindo conexões de um namespace específico usando 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Como resultado, todos os pods no namespace default terá acesso aos pods postgres no espaço para nome database. Mas e se você quiser abrir o acesso a postgres apenas pods específicos no namespace default?

Filtrar por namespaces e pods

Kubernetes versão 1.11 e superior permite combinar operadores namespaceSelector и podSelector usando AND lógico. Fica assim:

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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Por que isso é interpretado como AND em vez do OR usual?

Note-se que podSelector não começa com um hífen. Em YAML isso significa que podSelector e ficando na frente dele namespaceSelector referem-se ao mesmo elemento da lista. Portanto, eles são combinados com AND lógico.

Adicionando um hífen antes podSelector resultará no surgimento de um novo elemento da lista, que será combinado com o anterior namespaceSelector usando OR lógico.

Para selecionar pods com um rótulo específico em todos os namespaces, insira em branco 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Várias gravadoras se unem a I

As regras para um firewall com vários objetos (hosts, redes, grupos) são combinadas usando OR lógico. A regra a seguir funcionará se a origem do pacote corresponder Host_1 Ou Host_2:

| Source | Destination | Service | Action |
| ----------------------------------------|
| Host_1 | Subnet_A    | HTTPS   | Allow  |
| Host_2 |             |         |        |
| ----------------------------------------|

Pelo contrário, no Kubernetes os vários rótulos em podSelector ou namespaceSelector são combinados com AND lógico. Por exemplo, a regra a seguir selecionará pods que tenham ambos os rótulos, role=db И 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ítica, seletores de pod e seletores de namespace.

Sub-redes e endereços IP (IPBlocks)

Os firewalls usam VLANs, endereços IP e sub-redes para segmentar uma rede.

No Kubernetes, os endereços IP são atribuídos aos pods automaticamente e podem mudar com frequência, portanto, os rótulos são usados ​​para selecionar pods e namespaces nas políticas de rede.

Sub-redes (ipBlocks) são usados ​​ao gerenciar conexões externas (Norte-Sul) de entrada (entrada) ou saída (saída). Por exemplo, esta política é aberta a todos os pods do namespace default acesso ao 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

O seletor de pod vazio neste exemplo significa “selecionar todos os pods no namespace”.

Esta política permite acesso apenas ao 8.8.8.8; o acesso a qualquer outro IP é proibido. Então, em essência, você bloqueou o acesso ao serviço DNS interno do Kubernetes. Se você ainda deseja abri-lo, indique isso explicitamente.

Geralmente ipBlocks и podSelectors são mutuamente exclusivos, uma vez que os endereços IP internos dos pods não são usados ​​em ipBlocks. Ao indicar pods IP internos, você permitirá conexões de/para pods com esses endereços. Na prática, você não saberá qual endereço IP usar, por isso eles não devem ser usados ​​para selecionar pods.

Como contraexemplo, a política a seguir inclui todos os IPs e, portanto, permite 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Você pode abrir o acesso apenas a IPs externos, excluindo os 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Portas e protocolos

Normalmente, os pods escutam uma porta. Isso significa que você simplesmente não pode especificar números de porta nas políticas e deixar tudo como padrão. No entanto, é recomendável tornar as políticas o mais restritivas possível, para que, em alguns casos, você ainda possa 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Observe que o seletor ports aplica-se a todos os elementos do bloco to ou from, que contém. Para especificar portas diferentes para conjuntos diferentes de elementos, divida ingress ou egress em várias subseções com to ou from e em cada cadastre suas 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

Uma introdução às políticas de rede Kubernetes para profissionais de segurança

Operação de porta padrão:

  • Se você omitir completamente a definição da porta (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.

Prática recomendada: não confie em valores padrão, especifique explicitamente o que você precisa.

Observe que você deve usar portas de pod, não portas de serviço (mais sobre isso no próximo parágrafo).

As políticas são definidas para pods ou serviços?

Normalmente, os pods no Kubernetes acessam uns aos outros por meio de um serviço - um balanceador de carga virtual que redireciona o tráfego para os pods que implementam o serviço. Você pode 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 em portas de pod, não em portas de serviço.

Por exemplo, se um serviço escuta a porta 80, mas redireciona o tráfego para a porta 8080 de seus pods, exatamente 8080 deverá ser especificado na política de rede.

Tal mecanismo deve ser considerado abaixo do ideal: se a estrutura interna do serviço (as portas nas quais os pods escutam) mudar, as políticas de rede terão que ser atualizadas.

Nova abordagem arquitetônica usando Service Mesh (por exemplo, veja sobre o Istio abaixo - tradução aprox.) permite que você lide com esse problema.

É necessário registrar tanto o Ingress quanto o Egress?

A resposta curta é sim, para que o pod A se comunique com o pod B, ele deve ter permissão para criar uma conexão de saída (para isso você precisa configurar uma política de saída) e o pod B deve ser capaz de aceitar uma conexão de entrada ( para isso, portanto, você precisa de uma política de ingresso).

Entretanto, na prática, você pode confiar na política padrão para permitir conexões em uma ou ambas as direções.

Se algum pod-fonte será selecionado por um ou mais saída-políticos, as restrições que lhe serão impostas serão determinadas pela sua disjunção. Nesse caso, você precisará permitir explicitamente a conexão ao pod -para o destinatário. Se um pod não for selecionado por nenhuma política, seu tráfego de saída (saída) será permitido por padrão.

Da mesma forma, o destino do casulo édestinatário, selecionado por um ou mais preâmbulo-políticos, será determinado pela sua disjunção. Nesse caso, você deve permitir explicitamente que ele receba tráfego do pod de origem. Se um pod não for selecionado por nenhuma política, todo o tráfego de entrada dele será permitido por padrão.

Consulte Stateful ou Stateless abaixo.

Logs

As políticas de rede do Kubernetes não podem registrar o tráfego. Isto torna difícil determinar se uma política está funcionando conforme o esperado e complica bastante a análise de segurança.

Controle de tráfego para serviços externos

As políticas de rede do Kubernetes não permitem especificar um nome de domínio totalmente qualificado (DNS) nas seções de saída. Este fato gera inconvenientes significativos ao tentar limitar o tráfego para destinos externos que não possuem um endereço IP fixo (como aws.com).

Verificação de política

Os firewalls irão avisá-lo ou até mesmo se recusarão a aceitar a política errada. O Kubernetes também faz algumas verificações. Ao definir uma política de rede por meio do kubectl, o Kubernetes pode declarar que ela está incorreta e se recusar a aceitá-la. Em outros casos, o Kubernetes pegará a política e a preencherá com os detalhes que faltam. Eles podem ser vistos usando o comando:

kubernetes get networkpolicy <policy-name> -o yaml

Tenha em mente que o sistema de validação do Kubernetes não é infalível e pode deixar passar alguns tipos de erros.

Execução

O Kubernetes não implementa políticas de rede em si, mas é apenas um gateway de API que delega a carga de controle a um sistema subjacente chamado Container Networking Interface (CNI). Definir políticas em um cluster Kubernetes sem atribuir o CNI apropriado é o mesmo que criar políticas em um servidor de gerenciamento de firewall sem instalá-las em firewalls. Cabe a você garantir um CNI decente ou, no caso de plataformas Kubernetes, hospedado na nuvem (você pode ver a lista de provedores aqui - Aproximadamente. trad.), habilite políticas de rede que definirão o CNI para você.

Observe que o Kubernetes não irá avisá-lo se você definir uma política de rede sem o CNI auxiliar apropriado.

Com estado ou sem estado?

Todos os CNIs do Kubernetes que encontrei são stateful (por exemplo, Calico usa Linux conntrack). Isso permite que o pod receba respostas na conexão TCP iniciada sem precisar restabelecê-la. No entanto, não conheço um padrão Kubernetes que garanta a monitoração de estado.

Gerenciamento avançado de políticas de segurança

Aqui estão algumas maneiras de melhorar a aplicação da política de segurança no Kubernetes:

  1. O padrão arquitetônico Service Mesh usa contêineres secundários para fornecer telemetria detalhada e controle de tráfego no nível de serviço. Como exemplo podemos tomar Istio.
  2. Alguns dos fornecedores CNI ampliaram suas ferramentas para ir além das políticas de rede Kubernetes.
  3. Orca Tufin Fornece visibilidade e automação de políticas de rede Kubernetes.

O pacote Tufin Orca gerencia políticas de rede Kubernetes (e é a fonte das capturas de tela acima).

informação adicional

Conclusão

As políticas de rede Kubernetes oferecem um bom conjunto de ferramentas para segmentar clusters, mas não são intuitivas e possuem muitas sutilezas. Devido a essa complexidade, acredito que muitas políticas de cluster existentes apresentam erros. As soluções possíveis para este problema incluem a automatização das definições de políticas ou a utilização de outras ferramentas de segmentação.

Espero que este guia ajude a esclarecer algumas dúvidas e resolver problemas que você possa encontrar.

PS do tradutor

Leia também em nosso blog:

Fonte: habr.com

Adicionar um comentário