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

Este documento explica como melhorar a segurança e o gerenciamento do cluster do Kubernetes isolando cargas de trabalho de contêiner em pools de nós dedicados no Google Distributed Cloud (GDC) com isolamento físico. 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 limitações dos pools de nós dedicados, consulte Visão geral do isolamento de nós.

Há vários fluxos de trabalho envolvidos na isolamento das cargas de trabalho de contêiner, incluindo o seguinte:

  • 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 serem executados lá.

  • Adicionar uma tolerância e uma regra de afinidade de nó: aplique tolerâncias e regras aos pods para forçá-los a serem executados apenas no pool de nós designado.

  • Verificar se a separação funciona: confirme se os pools de nós com taint estão executando apenas os pods que você identificou 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êiner. Para mais informações, consulte Públicos-alvo da documentação do GDC com isolamento físico.

Antes de começar

Para concluir as tarefas neste documento, peça as permissões necessárias e prepare o ambiente.

Solicitar papéis do IAM

Você precisa de papéis específicos para receber as permissões necessárias para isolar 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 na organização ou em um cluster padrão com escopo no projeto. Para mais informações, consulte Configurações de cluster do Kubernetes.

Papéis de cluster compartilhado

Entre em contato com o administrador do IAM da organização para solicitar os seguintes papéis para atribuir um taint e um identificador a um pool de nós em um cluster compartilhado:

  • Administrador do cluster de usuário (user-cluster-admin): crie, exclua, edite ou visualize 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): crie, exclua, edite ou visualize 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 IAM do projeto para solicitar os seguintes papéis para atribuir um taint e um identificador a um pool de nós em um cluster padrão:

  • Administrador do cluster (cluster-admin): crie, exclua, edite ou visualize todos os recursos em um cluster padrão. Esse papel fornece acesso às APIs do plano de dados hospedadas no cluster padrão que regem os recursos do cluster.

  • Desenvolvedor de cluster (cluster-developer): crie, exclua, edite ou visualize um cluster padrão. Esse papel fornece acesso às APIs do plano de dados hospedadas no cluster padrão que regem o cluster.

  • Administrador do cluster padrão (standard-cluster-admin): crie, exclua, edite ou visualize 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 do cluster do Kubernetes.

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

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

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

  • 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.

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. Não é possível remover um taint ou identificador de um pool de nós depois que ele é aplicado.

Para adicionar um taint e um identificador 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 do taint do par de chave-valor associado a um TAINT_EFFECT. Por exemplo, workloadType.
    • TAINT_VALUE: a parte do valor do taint do par de chave-valor associado a um TAINT_EFFECT. 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 programar 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 identificadores de nós, que correspondem aos seletores especificados nos manifestos das cargas de trabalhos.
  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 kubeconfig do servidor da API zonal em que o cluster do Kubernetes está hospedado.

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

Para aplicar um taint ou identificador a um pool de nós atual, é necessário 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 identificador de um pool de nós depois que ele é aplicado.

Para adicionar um taint e um identificador 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 dedicado.

    Anote cada ID de nó de todos os nós 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. 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 programar 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 identificadores 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 identificadores de nós, que correspondem aos seletores especificados nos manifestos das cargas de trabalhos.
    • 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ê identificou 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 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 de 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: 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 programar 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 identificador do nó que você aplicou ao pool de nós dedicado.

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

    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 de 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 de contêiner. Para clusters compartilhados, esse precisa ser um namespace do projeto. Para clusters padrão, pode ser qualquer namespace.
    • 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 em execução no pool de nós identificado.

  • 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 de contêiner. Para clusters compartilhados, esse precisa ser um namespace do projeto. Para clusters padrão, pode ser qualquer namespace.
    • 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 em execução no pool de nós dedicado.

A seguir