Isolar as cargas de trabalho em pools de nós dedicados


Nesta página, mostramos como reduzir o risco de ataques de escalonamento de privilégios no cluster instruindo o Google Kubernetes Engine (GKE) a programar as cargas de trabalho em um pool de nós dedicado e separado das cargas de trabalho privilegiadas gerenciadas pelo GKE. Esta página se aplica aos clusters padrão sem provisionamento automático de nós. Para separar cargas de trabalho em clusters do Autopilot e em clusters padrão com provisionamento automático de nós ativado, consulte Configurar a separação de cargas de trabalho no GKE.

Visão geral

Os clusters do GKE usam cargas de trabalho privilegiadas gerenciadas pelo GKE para ativar funcionalidades e recursos específicos, como a coleta de métricas. Essas cargas de trabalho recebem permissões especiais para serem executadas corretamente no cluster.

As cargas de trabalho que você implanta nos nós podem ser comprometidas por uma entidade maliciosa. A execução dessas cargas de trabalho com as cargas de trabalho privilegiadas gerenciadas pelo GKE significa que um invasor que rompe um contêiner comprometido pode usar as credenciais da carga de trabalho privilegiada no nó para escalonar privilégios no cluster.

Como evitar rompimentos de contêiner

Sua defesa principal deve ser os aplicativos. O GKE tem vários recursos que podem ser usados para aumentar a proteção dos clusters e pods. Na maioria dos casos, recomendamos usar o GKE Sandbox para isolar as cargas de trabalho. O GKE Sandbox é baseado no projeto de código aberto gVisor e implementa a API Linux kernel no espaço do usuário. Cada pod é executado em um kernel dedicado que coloca aplicativos no sandbox para evitar o acesso a chamadas de sistema privilegiadas no kernel do host. As cargas de trabalho em execução no GKE Sandbox são programadas automaticamente em nós separados e isolados de outras cargas de trabalho.

Siga também as recomendações em Aumentar a segurança do cluster.

Como evitar ataques de escalonamento de privilégios

Se você não puder usar o GKE Sandbox e quiser uma camada extra de isolamento além de outras medidas de aumento da proteção, use taints de nó e afinidade de nó para programar as cargas de trabalho em um pool de nós dedicado. Um taint de nó instrui o GKE a evitar a programação de cargas de trabalho sem uma tolerância correspondente (como cargas de trabalho gerenciadas pelo GKE) nesses nós. A afinidade de nó nas cargas de trabalho instrui o GKE a programar os pods nos nós dedicados.

Limitações do isolamento de nós

  • Os invasores ainda podem iniciar ataques de negação de serviço (DoS) no nó comprometido.
  • Os nós comprometidos ainda podem ler muitos recursos, incluindo todos os pods e namespaces no cluster.
  • Os nós comprometidos podem acessar Secrets e credenciais usadas por todos os pods em execução nesse nó.
  • O uso de um pool de nós separado para isolar as cargas de trabalho pode afetar a economia, o escalonamento automático e a utilização de recursos.
  • Os nós comprometidos ainda podem ignorar as políticas de saída de rede.
  • Algumas cargas de trabalho gerenciadas pelo GKE precisam ser executadas em todos os nós do cluster e são configuradas para tolerar todos os taints.
  • Se você implantar DaemonSets que tenham permissões elevadas e possam tolerar qualquer taint, esses pods poderão ser um caminho para o escalonamento de privilégios de um nó comprometido.

Como funciona o isolamento de nós

Para implementar o isolamento de nós para as cargas de trabalho, faça isto:

  1. Atribua um taint e um identificador a um pool de nós para as cargas de trabalho.
  2. Atualize as cargas de trabalho com a tolerância e a regra de afinidade de nó correspondente.

Este guia pressupõe que você começará com um pool de nós no cluster. O uso da afinidade de nó, além dos taints de nó, não é obrigatório, mas isso é recomendável porque você se beneficia de um maior controle sobre a programação.

Antes de começar

Antes de começar, verifique se você realizou as tarefas a seguir:

  • Ativar a API Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Se você quiser usar a Google Cloud CLI para essa tarefa, instale e, em seguida, inicialize a CLI gcloud. Se você instalou a CLI gcloud anteriormente, instale a versão mais recente executando gcloud components update.
  • Escolha um nome específico para o taint e o identificador do nó que você quer usar nos pools de nós dedicados. Neste exemplo, usamos workloadType=untrusted.

Atribuir um taint e um identificador a um pool de nós para as cargas de trabalho

Crie um novo pool de nós para as cargas de trabalho e atribua um taint e um identificador de nó. Quando você atribui um taint ou um identificador no nível do pool de nós, todos os novos nós, como aqueles criados pelo escalonamento automático, recebem automaticamente os taints e identificadores especificados.

Também é possível adicionar taints e identificadores de nós a pools de nós que já existem. Se você usar o efeito NoExecute, o GKE removerá todos os pods em execução nesses nós que não tiverem uma tolerância ao novo taint.

Para adicionar um taint e um identificador a um novo pool de nós, execute o seguinte comando:

gcloud container node-pools create POOL_NAME \
    --cluster CLUSTER_NAME \
    --node-taints TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
    --node-labels LABEL_KEY=LABEL_VALUE

Substitua:

  • POOL_NAME: o nome do novo pool de nós para as cargas de trabalho.
  • CLUSTER_NAME: o nome do cluster do GKE.
  • TAINT_KEY=TAINT_VALUE: um par de chave-valor associado a um TAINT_EFFECT de programação. Por exemplo, workloadType=untrusted.
  • TAINT_EFFECT: um dos seguintes valores de efeito: NoSchedule, PreferNoSchedule ou NoExecute. NoExecute oferece uma garantia de remoção melhor do que NoSchedule.
  • LABEL_KEY=LABEL_VALUE: pares de chave-valor para os rótulos de nó, que correspondem aos seletores especificados nos manifestos das cargas de trabalhos.

Adicionar uma tolerância e uma regra de afinidade de nó às cargas de trabalho

Depois que você atribui um taint ao pool de nós dedicado, nenhuma carga de trabalho poderá ser programada nele, a menos que tenha uma tolerância correspondente ao taint adicionado. Adicione a tolerância à especificação das cargas de trabalho para permitir que esses pods sejam programados no pool de nós com taint.

Se você atribuiu um identificador ao pool de nós dedicado, também é possível adicionar uma regra de afinidade de nó para instruir o GKE a programar apenas as cargas de trabalho nesse pool de nós.

O exemplo a seguir adiciona uma tolerância ao taint workloadType=untrusted:NoExecute e uma regra de afinidade de nó para o identificador de nó workloadType=untrusted.

kind: Deployment
apiVersion: apps/v1
metadata:
  name: my-app
  namespace: default
  labels:
    app: my-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      tolerations:
      - key: TAINT_KEY
        operator: Equal
        value: TAINT_VALUE
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: LABEL_KEY
                operator: In
                values:
                - "LABEL_VALUE"
      containers:
      - name: sleep
        image: ubuntu
        command: ["/bin/sleep", "inf"]

Substitua:

  • TAINT_KEY: a chave do taint que você aplicou ao pool de nós dedicado.
  • TAINT_VALUE: o valor do taint que você aplicou ao pool de nós dedicado.
  • LABEL_KEY: a chave do rótulo do nó que você aplicou ao pool de nós dedicado.
  • LABEL_VALUE: o valor do rótulo do nó que você aplicou ao pool de nós dedicado.

Quando você atualiza a implantação com kubectl apply, o GKE recria os pods afetados. A regra de afinidade de nó força os pods no pool de nós dedicado que você criou. A tolerância permite que apenas esses pods sejam posicionados nos nós.

Verificar se a separação funciona

Para verificar se a programação funciona corretamente, execute o comando a seguir e verifique se as cargas de trabalho estão no pool de nós dedicado:

kubectl get pods -o=wide

Conselhos e práticas recomendadas

Após configurar o isolamento de nós, recomendamos que você faça isto:

  • Para restringir pools de nós específicos a cargas de trabalho gerenciadas pelo GKE, basta adicionar o taint components.gke.io/gke-managed-components. A adição desse taint impede que seus próprios pods sejam programados nesses nós, melhorando o isolamento.
  • Ao criar novos pools de nós, impeça que a maioria das cargas de trabalho gerenciadas pelo GKE seja executada nesses nós adicionando o próprio taint a esses pools de nós.
  • Sempre que você implantar novas cargas de trabalho no cluster, como ao instalar ferramentas de terceiros, faça a auditoria das permissões exigidas pelos pods. Sempre que possível, evite implantar cargas de trabalho que usam permissões elevadas para nós compartilhados.

A seguir