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

Este documento explica como melhorar a segurança e o gerenciamento do seu cluster do Kubernetes isolando cargas de trabalho de contêiner em pools de nós dedicados na Google Distributed Cloud (GDC) isolada por air-gap. Isolar as cargas de trabalho oferece mais controle sobre os pods e reduz o risco de ataques de escalonamento de privilégios no cluster do Kubernetes. Para mais informações sobre os benefícios e as limitações dos pools de nós dedicados, consulte Visão geral do isolamento de nós.

Há vários fluxos de trabalho envolvidos no isolamento das cargas de trabalho de contêineres, incluindo:

  • Atribuir um taint e um identificador a um pool de nós: aplique um taint e um identificador a um pool de nós para que ele repila os pods, a menos que eles sejam especificamente identificados para execução ali.

  • Adicione uma tolerância e uma regra de afinidade de nó: aplique tolerâncias e regras aos pods para forçar a execução deles apenas no pool de nós designado.

  • Verifique se a separação funciona: confirme se os pools de nós corrompidos estão executando apenas os pods que você rotulou para serem executados lá.

Esses fluxos de trabalho são destinados a públicos-alvo como administradores de TI no grupo de administradores da plataforma, responsáveis por gerenciar os pools de nós de um cluster do Kubernetes, e desenvolvedores de aplicativos no grupo de operadores de aplicativos, responsáveis por gerenciar cargas de trabalho de contêineres. Para mais informações, consulte Públicos-alvo da documentação isolada do GDC.

Antes de começar

Antes de começar, veja se você realizou as seguintes tarefas:

  • Escolha um nome específico para o taint e o identificador do nó que você quer usar nos pools de nós dedicados. Por exemplo, workloadType=untrusted

  • Se necessário, peça ao administrador do IAM da organização para conceder a você o papel de desenvolvedor de cluster de usuário (user-cluster-developer), que não está vinculado a um namespace.

Atribuir um taint e um identificador a um novo pool de nós

Quando você aplica um taint ou um identificador a um novo pool de nós, todos os nós, incluindo os adicionados posteriormente, recebem automaticamente os taints e identificadores especificados.

Para adicionar um taint e um rótulo a um novo pool de nós, siga estas etapas:

  1. Edite diretamente a seção nodePools do recurso personalizado Cluster ao criar o pool de nós:

    nodePools:
      # Several lines of code are omitted here.
      - machineTypeName: n2-standard-2-gdc
        name: nodepool-1
        nodeCount: 3
        taints:
        - key: "TAINT_KEY"
          value: "TAINT_VALUE"
          effect: "TAINT_EFFECT"
        labels:
          LABEL_KEY: LABEL_VALUE
    

    Substitua:

    • TAINT_KEY: a parte da chave de taint do par de chave-valor associado a um TAINT_EFFECT de programação. Por exemplo, workloadType.
    • TAINT_VALUE: a parte do valor de taint do par de chave-valor associado a um TAINT_EFFECT de programação. Por exemplo, untrusted.
    • TAINT_EFFECT: um dos seguintes valores de efeito:
      • NoSchedule: pods que não toleram esse taint não são programados no nó. Os pods atuais não são removidos do nó.
      • PreferNoSchedule: o Kubernetes evita a programação de pods que não toleram esse taint no nó.
      • NoExecute: o pod é removido do nó quando já está em execução nele e não é programado no nó quando ainda não está em execução nele.
    • LABEL_KEY: LABEL_VALUE: os pares de chave-valor para os rótulos de nó, que correspondem aos seletores especificados nos manifestos das cargas de trabalho.
  2. Aplique o recurso Cluster para criar o novo pool de nós:

    kubectl apply -f cluster.yaml --kubeconfig MANAGEMENT_API_SERVER
    

    Substitua MANAGEMENT_API_SERVER pelo caminho do kubeconfig do servidor da API zonal em que o cluster do Kubernetes está hospedado. Se você ainda não gerou um arquivo kubeconfig para o servidor da API na zona de destino, consulte Recursos do servidor da API de gerenciamento zonal para mais informações.

Atribuir um taint e um identificador a um pool de nós atual

Para aplicar uma restrição ou um rótulo a um pool de nós, é necessário aplicar as mudanças a cada nó. Não é possível atualizar dinamicamente as configurações do pool de nós.

Para adicionar um taint e um rótulo a um pool de nós atual, siga estas etapas:

  1. Liste os nós no pool de nós 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 kubeconfig do cluster do Kubernetes.
    • NODE_POOL_NAME: o nome do pool de nós dedicados.

    Anote o ID de cada nó no pool de nós da saída.

  2. Para cada nó no pool de nós, aplique as restrições:

    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ó de trabalho no pool de nós dedicado.
    • 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: pods que não toleram esse taint não são programados no nó. Os pods atuais não são removidos do nó.
      • PreferNoSchedule: o Kubernetes evita a programação de pods que não toleram esse taint no nó.
      • NoExecute: o pod é removido do nó quando já está em execução nele e não é programado no nó quando ainda não está em execução nele.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig do cluster do Kubernetes.
  3. Para cada nó no pool de nós, aplique os rótulos que correspondem aos seletores que você vai definir nas cargas de trabalho de contêiner:

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

    Substitua as seguintes variáveis:

    • NODE_ID: o ID do nó de trabalho no pool de nós dedicado.
    • LABEL_KEY:LABEL_VALUE: os pares de chave-valor para os rótulos de nó, que correspondem aos seletores especificados nos manifestos das cargas de trabalho.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig do cluster do Kubernetes.

Adicionar uma tolerância e uma regra de afinidade de nó

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 rótulo ao pool de nós dedicado, também é possível adicionar uma regra de afinidade de nó para instruir o GDC a programar apenas as cargas de trabalho nesse pool de nós.

Para configurar sua carga de trabalho de contêiner para ser executada no pool de nós dedicado, siga estas etapas:

  1. Adicione as seções a seguir à seção .spec.template.spec do arquivo de manifesto da carga de trabalho do contêiner, como um recurso personalizado Deployment:

      # Several lines of code are omitted here.
        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"
            # Several lines of code are omitted here.
    

    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.
    • TAINT_EFFECT: um dos seguintes valores de efeito:
      • NoSchedule: pods que não toleram esse taint não são programados no nó. Os pods atuais não são removidos do nó.
      • PreferNoSchedule: o Kubernetes evita a programação de pods que não toleram esse taint no nó.
      • NoExecute: o pod é removido do nó quando já está em execução nele e não é programado no nó quando ainda não está em execução nele.
    • 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.

    Por exemplo, o recurso Deployment 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: 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 sua carga de trabalho de contêiner:

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

    Substitua as seguintes variáveis:

    • NAMESPACE: o namespace do projeto da sua carga de trabalho de contêiner.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig do cluster do Kubernetes.

O GDC 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

Verifique se os pods designados estão sendo executados no pool de nós rotulado.

  • Liste os pods no namespace especificado:

    kubectl get pods -o=wide -n NAMESPACE \
        --kubeconfig KUBERNETES_CLUSTER_KUBECONFIG
    

    Substitua as seguintes variáveis:

    • NAMESPACE: o namespace do projeto da sua carga de trabalho de contêiner.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig do cluster do Kubernetes.

    A saída será assim:

    pod/kube-abc-12tyuj
    pod/kube-abc-39oplef
    pod/kube-abc-95rzkap
    

    Confirme se as cargas de trabalho estão sendo executadas no pool de nós dedicado.

A seguir