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 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 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êiner, 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 rotulados para serem executados 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.

  • Verificar 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 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 seu ambiente.

Solicitar papéis do IAM

Você precisa ter 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 no escopo da organização ou em um cluster padrão no escopo do projeto. Para mais informações, consulte Configurações de cluster do Kubernetes.

Funções compartilhadas do cluster

Entre em contato com o administrador do IAM da organização para solicitar as seguintes funções e rotular 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. Essa função dá acesso aos pools de nós do cluster compartilhado.

  • Desenvolvedor de cluster de usuário (user-cluster-developer): crie, exclua, edite ou veja um cluster compartilhado. Essa função fornece acesso às APIs do plano de dados hospedadas no cluster compartilhado.

Essas funções não estão vinculadas a um namespace.

Funções padrão do cluster

Entre em contato com o administrador do IAM do projeto para solicitar as seguintes funções e rotular um pool de nós em um cluster padrão:

  • Administrador do cluster (cluster-admin): crie, exclua, edite ou veja todos os recursos em um cluster padrão. Essa função dá acesso às APIs do plano de dados hospedadas no cluster padrão que governam os recursos do cluster.

  • Desenvolvedor de cluster (cluster-developer): crie, exclua, edite ou veja um cluster padrão. Essa função fornece acesso às APIs do plano de dados hospedadas no cluster padrão que governa o cluster.

  • Administrador do cluster padrão (standard-cluster-admin): crie, exclua, edite ou veja os recursos de um cluster padrão hospedado no servidor da API de gerenciamento. Essa função dá acesso aos pools de nós do cluster padrão.

Essas funções estão vinculadas 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 para o 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 uma restrição ou um 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: 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ó se já estiver em execução nele e não é 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 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 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.

Não é possível remover uma restrição ou um 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 atual, siga estas etapas:

  1. Liste os nós no pool de nós dedicados:

    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 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: 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ó se já estiver em execução nele e não é programado no nó se ainda não estiver 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 definidos 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:

    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 a programação de pods que não toleram esse taint no nó.
      • NoExecute: o pod é removido do nó se já estiver em execução nele e não é 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 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 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, 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 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 da carga de trabalho do 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 sendo executadas no pool de nós dedicado.

A seguir