Isole as suas cargas de trabalho em node pools dedicados

Esta página mostra como isolar as cargas de trabalho dos contentores em pools de nós dedicados no Google Distributed Cloud (GDC) com isolamento de ar para lhe dar mais controlo dos seus pods. O isolamento da carga de trabalho oferece algumas vantagens, como:

  • Risco reduzido de ataques de escalada de privilégios no seu cluster do Kubernetes.
  • Mais controlo sobre agrupamentos que requerem recursos adicionais.

Para estes casos, considere isolar as cargas de trabalho do contentor para ter mais controlo e otimização.

Por que motivo devo isolar as minhas cargas de trabalho?

O isolamento das cargas de trabalho em pools de nós dedicados não é obrigatório, mas pode ser uma ação prudente para evitar potenciais problemas. No entanto, tenha em atenção que a gestão de pools de nós dedicados requer mais supervisão e, muitas vezes, é desnecessária.

Os clusters do Kubernetes usam cargas de trabalho privilegiadas geridas pelo GDC para ativar capacidades e 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 GDC 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.

Os conjuntos de nós dedicados também são úteis quando tem de agendar pods que requerem mais recursos do que outros, como mais memória ou mais espaço no disco local.

Pode usar os seguintes mecanismos para agendar as suas cargas de trabalho num conjunto de nós dedicado:

Uma restrição de nó informa o seu cluster do Kubernetes para evitar o agendamento de cargas de trabalho sem uma tolerância correspondente, como cargas de trabalho geridas pelo GDC, nesses nós. A afinidade de nós nas suas próprias cargas de trabalho indica ao cluster 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 GDC têm de ser executadas em todos os nós do cluster e estão configuradas para tolerar todas as manchas.

  • Se implementar recursos DaemonSet 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:

  • Escolha um nome específico para a restrição de nós e a etiqueta de nós que quer usar para os conjuntos de nós dedicados. Por exemplo, workloadType=untrusted.

  • Se necessário, peça ao administrador de IAM da organização para lhe conceder a função de programador de clusters de utilizadores (user-cluster-developer), que não está associada a um espaço de nomes.

Contamine e etiquete um novo conjunto de nós

Quando aplica uma restrição ou uma etiqueta a um novo conjunto de nós, todos os nós, incluindo os nós adicionados posteriormente, recebem automaticamente as restrições e as etiquetas especificadas.

Para adicionar uma restrição e uma etiqueta a um novo conjunto de nós, conclua os seguintes passos:

  1. Edite a secção nodePools do recurso personalizado Cluster diretamente quando criar o node pool:

    nodePools:
      ...
      - machineTypeName: n2-standard-2-gdc
        name: nodepool-1
        nodeCount: 3
        taints: TAINT_KEY=TAINT_VALUE:TAINT_EFFECT
        labels: LABEL_KEY=LABEL_VALUE
    

    Substitua o seguinte:

    • 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: os agrupamentos que não toleram esta contaminação não são agendados no nó; os agrupamentos existentes não são removidos do nó.
      • PreferNoSchedule: o Kubernetes evita agendar pods que não toleram esta contaminação no nó.
      • NoExecute: o pod é removido do nó se já estiver a ser executado no nó e não é agendado para o nó se ainda não estiver a ser executado no nó.
    • LABEL_KEY=LABEL_VALUE: os pares de chaves-valores para as etiquetas dos nós, que correspondem aos seletores que especifica nos manifestos da carga de trabalho.
  2. Aplique o recurso Cluster para criar o novo node pool:

    kubectl apply -f cluster.yaml \
        --kubeconfig MANAGEMENT_API_SERVER
    

    Substitua MANAGEMENT_API_SERVER pelo caminho kubeconfig do servidor de API zonal onde o cluster Kubernetes está alojado. Se ainda não gerou um ficheiro kubeconfig para o servidor da API na zona segmentada, consulte Iniciar sessão para ver detalhes.

Aplique uma restrição e etiquete um conjunto de nós existente

Para aplicar uma restrição ou uma etiqueta a um conjunto de nós existente, tem de aplicar as alterações a cada nó existente. Não pode atualizar dinamicamente as configurações do conjunto de nós.

Para adicionar uma restrição e uma etiqueta a um conjunto de nós existente, conclua os seguintes passos:

  1. Liste os nós no node pool dedicado:

    kubectl get node --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG \
        -l baremetal.cluster.gke.io/node-pool=NODE_POOL_NAME
    

    Substitua as seguintes variáveis:

    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o cluster do Kubernetes.
    • NODE_POOL_NAME: o nome do seu node pool dedicado.

    Tome nota do ID de cada nó de todos os nós no conjunto de nós a partir do resultado.

  2. Para cada nó no conjunto de nós, aplique as manchas:

    kubectl taint nodes NODE_ID \
        TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Substitua as seguintes variáveis:

    • NODE_ID: o ID do nó trabalhador no conjunto de nós dedicado.
    • 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: os agrupamentos que não toleram esta contaminação não são agendados no nó; os agrupamentos existentes não são removidos do nó.
      • PreferNoSchedule: o Kubernetes evita agendar pods que não toleram esta contaminação no nó.
      • NoExecute: o pod é removido do nó se já estiver a ser executado no nó e não é agendado para o nó se ainda não estiver a ser executado no nó.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o cluster do Kubernetes.
  3. Para cada nó no conjunto de nós, aplique as etiquetas que correspondem aos seletores que vai definir nas cargas de trabalho de contentores:

    kubectl label NODE_ID \
        LABEL_KEY:LABEL_VALUE \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Substitua as seguintes variáveis:

    • NODE_ID: o ID do nó trabalhador no conjunto de nós dedicado.
    • LABEL_KEY:LABEL_VALUE: os pares de chaves-valores para as etiquetas dos nós, que correspondem aos seletores que especifica nos manifestos da carga de trabalho.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o cluster do Kubernetes.

Adicione uma tolerância e uma regra de afinidade de nós

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 pool de nós dedicado, também pode adicionar uma regra de afinidade de nós para indicar ao GDC que agende as suas cargas de trabalho apenas nesse pool de nós.

Para configurar a carga de trabalho do contentor para ser executada no conjunto de nós dedicado, conclua os seguintes passos:

  1. Adicione as seguintes secções à secção .spec.template.spec da carga de trabalho do contentor:

    kind: Deployment
    apiVersion: apps/v1
        ...
        spec:
        ...
          template:
            spec:
              tolerations:
              - key: TAINT_KEY
                operator: Equal
                value: TAINT_VALUE
                effect: TAINT_EFFECT
              affinity:
                nodeAffinity:
                  requiredDuringSchedulingIgnoredDuringExecution:
                    nodeSelectorTerms:
                    - matchExpressions:
                      - key: LABEL_KEY
                        operator: In
                        values:
                        - "LABEL_VALUE"
              ...
    

    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 conjunto de nós dedicado.
    • TAINT_EFFECT: um dos seguintes valores de efeito:
      • NoSchedule: os agrupamentos que não toleram esta contaminação não são agendados no nó; os agrupamentos existentes não são removidos do nó.
      • PreferNoSchedule: o Kubernetes evita agendar pods que não toleram esta contaminação no nó.
      • NoExecute: o pod é removido do nó se já estiver a ser executado no nó e não é agendado para o nó se ainda não estiver a ser executado no nó.
    • 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.

    Por exemplo, o recurso Deployment seguinte adiciona uma tolerância para a falha de funcionamento 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: workloadType
            operator: Equal
            value: untrusted
            effect: NoExecute
          affinity:
            nodeAffinity:
              requiredDuringSchedulingIgnoredDuringExecution:
                nodeSelectorTerms:
                - matchExpressions:
                  - key: workloadType
                    operator: In
                    values:
                    - "untrusted"
          containers:
          - name: my-app
            image: harbor-1.org-1.zone1.google.gdc.test/harborproject/my-app
            ports:
            - containerPort: 80
          imagePullSecrets:
          - name: SECRET
    
  2. Atualize a sua implementação:

    kubectl apply -f deployment.yaml -n NAMESPACE \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Substitua as seguintes variáveis:

    • NAMESPACE: o espaço de nomes do projeto da sua carga de trabalho do contentor.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o cluster do Kubernetes.

O GDC recria os agrupamentos 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 -n NAMESPACE \
    --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG

Recomendações e práticas recomendadas

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

  • Ao criar novos node pools, impeça que a maioria das cargas de trabalho geridas pela GDC sejam executadas nesses nós adicionando a sua própria marca de contaminação a esses node pools.
  • Sempre que implementar novas cargas de trabalho no cluster, como quando instalar 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.