Isole as suas cargas de trabalho em node pools dedicados

Esta página mostra como reduzir o risco de ataques de escalada de privilégios no seu cluster, indicando ao Google Kubernetes Engine (GKE) que agende as suas cargas de trabalho num conjunto de nós dedicado separado das cargas de trabalho privilegiadas geridas pelo GKE. Só deve usar esta abordagem se não conseguir usar o GKE Sandbox. O GKE Sandbox é a abordagem recomendada para o isolamento de nós. O GKE Sandbox também oferece outras vantagens de reforço para as suas cargas de trabalho.

Esta página destina-se a especialistas de segurança que requerem uma camada de isolamento em cargas de trabalho, mas não podem usar o GKE Sandbox. Para saber mais sobre as funções comuns e as tarefas de exemplo que referimos no conteúdo, consulte o artigo Funções e tarefas comuns do utilizador do GKE. Trusted Cloud by S3NS

Esta página aplica-se a clusters padrão sem aprovisionamento automático de nós. Para separar cargas de trabalho em clusters do Autopilot e em clusters padrão com o aprovisionamento automático de nós ativado, consulte o artigo Configure a separação de cargas de trabalho no GKE.

Vista geral

Os clusters do GKE usam cargas de trabalho privilegiadas geridas pelo GKE para ativar funcionalidades específicas do cluster, como a recolha de métricas. Estas cargas de trabalho recebem autorizações especiais para serem executadas corretamente no cluster.

As cargas de trabalho que implementa nos seus nós podem ser potencialmente comprometidas por uma entidade maliciosa. A execução destas cargas de trabalho juntamente com cargas de trabalho privilegiadas geridas pelo GKE significa que um atacante que saia de um contentor comprometido pode usar as credenciais da carga de trabalho privilegiada no nó para aumentar os privilégios no seu cluster.

Impeça fugas de contentores

A sua defesa principal deve ser as suas aplicações. O GKE tem várias funcionalidades que pode usar para proteger os seus clusters e pods. Na maioria dos casos, recomendamos vivamente a utilização do GKE Sandbox para isolar as suas cargas de trabalho. O GKE Sandbox baseia-se no projeto de código aberto gVisor e implementa a API do kernel do Linux no espaço do utilizador. Cada Pod é executado num kernel dedicado que isola as aplicações para impedir o acesso a chamadas de sistema privilegiadas no kernel do anfitrião. As cargas de trabalho executadas no GKE Sandbox são agendadas automaticamente em nós separados, isolados de outras cargas de trabalho.

Também deve seguir as recomendações em Reforce a segurança do cluster.

Evite ataques de escalamento de privilégios

Se não puder usar o GKE Sandbox e quiser uma camada adicional de isolamento, além de outras medidas de reforço, pode usar node taints e node affinity para agendar as suas cargas de trabalho num conjunto de nós dedicado. Uma restrição de nó indica ao GKE que deve evitar agendar cargas de trabalho sem uma tolerância correspondente (como cargas de trabalho geridas pelo GKE) nesses nós. A afinidade de nós nas suas próprias cargas de trabalho indica ao GKE para agendar os seus pods nos nós dedicados.

Limitações do isolamento de nós

  • Os atacantes continuam a poder iniciar ataques de negação de serviço (DoS) a partir do nó comprometido.
  • Os nós comprometidos ainda podem ler muitos recursos, incluindo todos os pods e namespaces no cluster.
  • Os nós comprometidos podem aceder a segredos e credenciais usados por todos os pods em execução nesse nó.
  • A utilização de um node pool separado para isolar as cargas de trabalho pode afetar a eficiência de custos, o dimensionamento automático e a utilização de recursos.
  • Os nós comprometidos podem continuar a ignorar as políticas de rede de saída.
  • Algumas cargas de trabalho geridas pelo GKE têm de ser executadas em todos os nós do cluster e estão configuradas para tolerar todas as restrições.
  • Se implementar DaemonSets com autorizações elevadas e que possam tolerar qualquer contaminação, esses pods podem ser um caminho para a escalada de privilégios a partir de um nó comprometido.

Como funciona o isolamento de nós

Para implementar o isolamento de nós para as suas cargas de trabalho, tem de fazer o seguinte:

  1. Contamine e etiquete um conjunto de nós para as suas cargas de trabalho.
  2. Atualize as suas cargas de trabalho com a regra de tolerância e afinidade de nós correspondente.

Este guia pressupõe que começa com um node pool no seu cluster. A utilização da afinidade de nós, além das restrições de nós, não é obrigatória, mas recomendamos que o faça porque beneficia de um maior controlo sobre o agendamento.

Antes de começar

Antes de começar, certifique-se de que realizou as seguintes tarefas:

  • Ative a API Google Kubernetes Engine.
  • Ative a API Google Kubernetes Engine
  • Se quiser usar a CLI gcloud para esta tarefa, instale-a e, em seguida, inicialize-a. Se instalou anteriormente a CLI gcloud, execute gcloud components update para obter a versão mais recente.
  • Escolha um nome específico para a restrição de contaminação do nó e a etiqueta do nó que quer usar para os conjuntos de nós dedicados.

Contamine e etiquete um conjunto de nós para as suas cargas de trabalho

Crie um novo node pool para as suas cargas de trabalho e aplique uma restrição de nó e uma etiqueta de nó. Quando aplica uma restrição ou uma etiqueta ao nível do conjunto de nós, todos os novos nós, como os criados pelo dimensionamento automático, recebem automaticamente as restrições e as etiquetas especificadas.

Também pode adicionar taints de nós e etiquetas de nós a pools de nós existentes. Se usar o efeito NoExecute, o GKE despeja todos os pods em execução nesses nós que não tenham uma tolerância para a nova mancha.

Para o isolamento da carga de trabalho, use sempre o prefixo node-restriction.kubernetes.io/ para as etiquetas dos nós e para os seletores correspondentes nos manifestos dos pods. Este prefixo impede que um atacante use a credencial do nó para definir ou modificar as etiquetas que usam este prefixo. Para mais informações, consulte o artigo Isolamento/restrição de nós na documentação do Kubernetes.

Para adicionar uma restrição e uma etiqueta a um novo conjunto 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=node-restriction.kubernetes.io/LABEL_KEY=LABEL_VALUE

Substitua o seguinte:

  • POOL_NAME: o nome do novo conjunto de nós para as suas cargas de trabalho.
  • CLUSTER_NAME: o nome do seu cluster do GKE.
  • TAINT_KEY=TAINT_VALUE: um par de chave-valor associado a uma programação TAINT_EFFECT. Por exemplo, workloadType=untrusted.
  • TAINT_EFFECT: um dos seguintes valores de efeito: NoSchedule, PreferNoSchedule ou NoExecute. NoExecute oferece uma garantia de despejo melhor do que NoSchedule.
  • node-restriction.kubernetes.io/LABEL_KEY=LABEL_VALUE: pares de chaves-valores para as etiquetas dos nós, que correspondem aos seletores que especifica nos manifestos da carga de trabalho. O prefixo node-restriction.kubernetes.io/ impede que as credenciais do nó sejam usadas para definir estes pares de valor-chave nos nós.

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

Depois de contaminar o pool de nós dedicado, nenhuma carga de trabalho pode ser agendada no mesmo, a menos que tenha uma tolerância correspondente à contaminação que adicionou. Adicione a tolerância à especificação das suas cargas de trabalho para permitir que esses pods sejam agendados no seu conjunto de nós contaminado.

Se etiquetou o conjunto de nós dedicado, também pode adicionar uma regra de afinidade de nós para indicar ao GKE que agende as suas cargas de trabalho apenas nesse conjunto de nós.

O exemplo seguinte adiciona uma tolerância para a restrição workloadType=untrusted:NoExecute e uma regra de afinidade de nós para a etiqueta 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: node-restriction.kubernetes.io/LABEL_KEY
                operator: In
                values:
                - "LABEL_VALUE"
      containers:
      - name: sleep
        image: ubuntu
        command: ["/bin/sleep", "inf"]

Substitua o seguinte:

  • TAINT_KEY: a chave de contaminação que aplicou ao seu conjunto de nós dedicado.
  • TAINT_VALUE: o valor de contaminação que aplicou ao seu grupo de nós dedicado.
  • LABEL_KEY: a chave da etiqueta do nó que aplicou ao seu node pool dedicado.
  • LABEL_VALUE: o valor da etiqueta do nó que aplicou ao seu node pool dedicado.

Quando atualiza a sua implementação com kubectl apply, o GKE recria os pods afetados. A regra de afinidade de nós força os pods para o node pool dedicado que criou. A tolerância permite que apenas esses pods sejam colocados nos nós.

Verifique se a separação funciona

Para verificar se o agendamento funciona corretamente, execute o seguinte comando e verifique se as suas cargas de trabalho estão no conjunto de nós dedicado:

kubectl get pods -o=wide

Recomendações e práticas recomendadas

Depois de configurar o isolamento de nós, recomendamos que faça o seguinte:

  • Restrinja pools de nós específicos apenas a cargas de trabalho geridas pelo GKE adicionando a contaminação components.gke.io/gke-managed-components. A adição desta mancha impede que os seus próprios pods sejam agendados nesses nós, o que melhora o isolamento.
  • Ao criar novos node pools, impeça que a maioria das cargas de trabalho geridas pelo GKE sejam executadas nesses nós adicionando a sua própria restrição a esses node pools.
  • Sempre que implementar novas cargas de trabalho no cluster, como quando instala ferramentas de terceiros, audite as autorizações que os pods requerem. Sempre que possível, evite implementar cargas de trabalho que usem autorizações elevadas em nós partilhados.

O que se segue?