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

Os pools de nós dedicados no Google Distributed Cloud (GDC) com isolamento físico permitem isolar as cargas de trabalho de contêiner para fortalecer a segurança do cluster do Kubernetes e controlar o posicionamento dos pods. Essa separação ajuda a reduzir o risco de ataques de escalonamento de privilégios. Para configurar pools dedicados, aplique taints e rótulos, faça a correspondência deles com tolerâncias de carga de trabalho e regras de afinidade de nó e verifique a programação.

Este documento é destinado a administradores de TI no grupo de administradores de plataforma que gerenciam clusters do Kubernetes e desenvolvedores no grupo de operadores de aplicativos que executam contêineres. Para mais informações, consulte Visão geral do isolamento de nós e Públicos-alvo da documentação do GDC com isolamento físico.

Antes de começar

Para concluir as tarefas neste documento, solicite as permissões necessárias e prepare seu ambiente.

Solicitar papéis do IAM

Você precisa ter papéis específicos para receber as permissões necessárias para isolar as cargas de trabalho de contêiner no cluster do Kubernetes. Os papéis necessários dependem de você estar trabalhando em um cluster compartilhado com escopo de organização ou em um cluster padrão com escopo de projeto. Para mais informações, consulte Configurações de cluster do Kubernetes.

Papéis de cluster compartilhados

Entre em contato com o admin. da organização do IAM para solicitar os seguintes papéis para aplicar taints e rótulos a um pool de nós em um cluster compartilhado:

  • Administrador de cluster de usuário (user-cluster-admin): criar, excluir, editar ou visualizar os recursos de um cluster compartilhado hospedado no servidor da API de gerenciamento. Esse papel fornece acesso aos pools de nós do cluster compartilhado.

  • Desenvolvedor de cluster de usuário (user-cluster-developer): criar, excluir, editar ou visualizar um cluster compartilhado. Esse papel fornece acesso às APIs do plano de dados hospedadas no cluster compartilhado.

Esses papéis não estão vinculados a um namespace.

Papéis de cluster padrão

Entre em contato com o administrador do projeto do IAM para solicitar os seguintes papéis para aplicar taint e rótulo a um pool de nós em um cluster padrão:

  • Administrador de cluster (cluster-admin): criar, excluir, editar ou visualizar todos os recursos em um cluster padrão. Esse papel fornece acesso às APIs do plano de dados hospedadas no cluster padrão que controlam os recursos do cluster.

  • Desenvolvedor de cluster (cluster-developer): criar, excluir, editar ou visualizar um cluster padrão. Esse papel fornece acesso às APIs do plano de dados hospedadas no cluster padrão que o governam.

  • Administrador de cluster padrão (standard-cluster-admin): criar, excluir, editar ou visualizar os recursos de um cluster padrão hospedado no servidor da API de gerenciamento. Esse papel fornece acesso aos pools de nós do cluster padrão.

Esses papéis estão vinculados ao namespace do projeto.

Preparar o ambiente

Para executar comandos em um cluster do Kubernetes usando a API, verifique se você tem os seguintes recursos:

  • Faça login e gere o arquivo kubeconfig para o cluster do Kubernetes.

  • Use o caminho do kubeconfig do cluster do Kubernetes para substituir KUBERNETES_CLUSTER_KUBECONFIG nestas instruções.

  • Faça login e gere o arquivo kubeconfig para o servidor de API de gerenciamento.

  • Use o caminho kubeconfig do servidor de API de gerenciamento para substituir MANAGEMENT_API_SERVER nestas instruções.

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

Atribuir um taint e um rótulo a um novo pool de nós

Quando você atribui um taint ou um rótulo a um novo pool de nós, todos os nós, incluindo os adicionados posteriormente, recebem automaticamente os taints e rótulos especificados. Não é possível remover um taint ou rótulo de um pool de nós depois que ele é aplicado.

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

  1. Edite a seção nodePools do recurso personalizado Cluster diretamente 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: os 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 em um nó.
      • NoExecute: o pod será removido do nó se já estiver em execução nele e não será programado no nó se ainda não estiver 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 de API zonal em que o cluster do Kubernetes está hospedado.

Atribuir um taint e um rótulo a um pool de nós atual

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

Não é possível remover um taint ou rótulo de um pool de nós depois que ele é aplicado.

Para adicionar um taint e um rótulo a um pool de nós, 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 do kubeconfig para o cluster do Kubernetes.
    • NODE_POOL_NAME: o nome do pool de nós dedicado.

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

  2. Para cada nó no pool de nós, aplique os taints:

    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: os 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 em um nó.
      • NoExecute: o pod será removido do nó se já estiver em execução nele e não será programado no nó se ainda não estiver em execução nele.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o cluster do Kubernetes.
  3. Para cada nó no pool de nós, aplique os rótulos que correspondem aos seletores que você definirá nas cargas de trabalho do 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 trabalhos.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o 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ê rotulou o 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 a carga de trabalho do 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:

    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:

    • 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: os 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 em um nó.
      • NoExecute: o pod será removido do nó se já estiver em execução nele e não será programado no nó se ainda não estiver 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 rótulo 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 carga de trabalho do contêiner:

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

    Substitua as seguintes variáveis:

    • NAMESPACE: o namespace da carga de trabalho do contêiner. Para clusters compartilhados, precisa ser um namespace de projeto. Para clusters padrão, pode ser qualquer namespace.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o 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 em execução no pool de nós rotulado.

  • Liste os pods no namespace fornecido:

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

    Substitua as seguintes variáveis:

    • NAMESPACE: o namespace da carga de trabalho do contêiner. Para clusters compartilhados, precisa ser um namespace de projeto. Para clusters padrão, pode ser qualquer namespace.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho do kubeconfig para o 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 em execução no pool de nós dedicado.

A seguir