Isole as suas cargas de trabalho em node pools dedicados

Este documento explica como melhorar a segurança e a gestão do cluster do Kubernetes isolando as cargas de trabalho de contentores em node pools dedicados no Google Distributed Cloud (GDC) air-gapped. O isolamento das cargas de trabalho dá-lhe maior controlo sobre os seus pods e reduz o risco de ataques de escalada de privilégios no cluster do Kubernetes. Para mais informações sobre as vantagens e as limitações dos node pools dedicados, consulte Vista geral do isolamento de nós.

Existem vários fluxos de trabalho envolvidos no isolamento das cargas de trabalho de contentores, incluindo o seguinte:

  • Contamine e etiquete um node pool: aplique uma contaminação e uma etiqueta a um node pool para que repila os pods, a menos que estes estejam especificamente etiquetados para serem executados nesse node pool.

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

  • Valide o funcionamento da separação: confirme que os node pools contaminados só estão a executar os pods que etiquetou para serem executados nesses node pools.

Estes fluxos de trabalho destinam-se a públicos-alvo como administradores de TI no grupo de administradores da plataforma, responsáveis pela gestão dos node pools de um cluster do Kubernetes, e programadores de aplicações no grupo de operadores de aplicações, responsáveis pela gestão das cargas de trabalho de contentores. Para mais informações, consulte Públicos-alvo da documentação do GDC air-gapped.

Antes de começar

Para concluir as tarefas neste documento, tem de pedir as autorizações necessárias e preparar o seu ambiente.

Peça funções de IAM

Tem de ter funções específicas para receber as autorizações de que precisa para isolar as cargas de trabalho de contentores no cluster do Kubernetes. As funções de que precisa dependem de estar a trabalhar num cluster partilhado com âmbito da organização ou num cluster padrão com âmbito do projeto. Para mais informações, consulte o artigo Configurações do cluster do Kubernetes.

Funções do cluster partilhado

Contacte o administrador de IAM da organização para pedir as seguintes funções para contaminar e etiquetar um node pool num cluster partilhado:

  • Administrador do cluster do utilizador (user-cluster-admin): crie, elimine, edite ou veja os recursos de um cluster partilhado alojado no servidor da API de gestão. Esta função dá acesso aos node pools do cluster partilhado.

  • Programador do cluster do utilizador (user-cluster-developer): crie, elimine, edite ou veja um cluster partilhado. Esta função dá acesso às APIs do plano de dados alojadas no cluster partilhado.

Estas funções não estão associadas a um espaço de nomes.

Funções do cluster padrão

Contacte o administrador de IAM do projeto para pedir as seguintes funções para contaminar e etiquetar um node pool num cluster padrão:

  • Administrador do cluster (cluster-admin): crie, elimine, edite ou veja todos os recursos num cluster padrão. Esta função dá acesso às APIs do plano de dados alojadas no cluster padrão que regem os recursos do cluster.

  • Programador do cluster (cluster-developer): crie, elimine, edite ou veja um cluster padrão. Esta função dá acesso às APIs do plano de dados alojadas no cluster padrão que regem o cluster.

  • Administrador do cluster padrão (standard-cluster-admin): crie, elimine, edite ou veja os recursos de um cluster padrão alojado no servidor da API de gestão. Esta função dá acesso aos node pools do cluster padrão.

Estas funções estão associadas ao espaço de nomes do projeto.

Prepare o seu ambiente

Para executar comandos num cluster do Kubernetes através da API, certifique-se de que tem os seguintes recursos:

  • Inicie sessão e gere o ficheiro kubeconfig para o cluster do Kubernetes.

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

  • Inicie sessão e gere o ficheiro kubeconfig para o servidor da API de gestão.

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

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

Contamine e etiquete um novo node pool

Quando aplica uma contaminação ou uma etiqueta a um novo node pool, todos os nós, incluindo os nós adicionados posteriormente, recebem automaticamente as contaminações e as etiquetas especificadas. Não pode remover uma contaminação ou uma etiqueta de um node pool depois de a aplicar.

Para adicionar uma contaminação e uma etiqueta a um novo node pool, conclua os passos seguintes:

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

    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 o seguinte:

    • TAINT_KEY: a parte da chave de contaminação do par de chave-valor associado a um TAINT_EFFECT de agendamento. Por exemplo, workloadType.
    • TAINT_VALUE: a parte do valor de contaminação do par de chave-valor associado a um agendamento TAINT_EFFECT. Por exemplo, untrusted.
    • TAINT_EFFECT: um dos seguintes valores de efeito :
      • NoSchedule: os pods que não toleram esta contaminação não são agendados no nó; os pods 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 no nó se ainda não estiver a ser executado no nó.
    • LABEL_KEY: LABEL_VALUE: os pares de chave-valor para as etiquetas de nós, que correspondem aos seletores que especifica nos manifestos de cargas 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 da API zonal onde o cluster do Kubernetes está alojado.

Contamine e etiquete um node pool existente

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

Não pode remover uma contaminação ou uma etiqueta de um node pool depois de a aplicar.

Para adicionar uma contaminação e uma etiqueta a um node pool existente, conclua os passos seguintes:

  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 kubeconfig para o cluster do Kubernetes.
    • NODE_POOL_NAME: o nome do node pool dedicado.

    Anote o ID de cada nó de todos os nós no node pool a partir do resultado.

  2. Para cada nó no node pool, aplique as contaminaçõ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 node pool 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: os pods que não toleram esta contaminação não são agendados no nó; os pods 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 no nó se ainda não estiver a ser executado no nó.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig para o cluster do Kubernetes.
  3. Para cada nó no node pool, 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ó de trabalho no node pool dedicado.
    • LABEL_KEY:LABEL_VALUE: os pares de chave-valor para as etiquetas de nós, que correspondem aos seletores que especifica nos manifestos de cargas de trabalho.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig para o cluster do Kubernetes.

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

Depois de contaminar o node pool 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 cargas de trabalho para permitir que esses pods sejam agendados no node pool contaminado.

Se etiquetou o node pool dedicado, também pode adicionar uma regra de afinidade de nós para indicar ao GDC que agende apenas as cargas de trabalho nesse node pool.

Para configurar a carga de trabalho de contentores para ser executada no node pool dedicado, conclua os passos seguintes:

  1. Adicione as seguintes secções à secção .spec.template.spec do ficheiro de manifesto da carga de trabalho de contentores, 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 o seguinte:

    • TAINT_KEY: a chave de contaminação que aplicou ao node pool dedicado.
    • TAINT_VALUE: o valor de contaminação que aplicou ao node pool dedicado.
    • TAINT_EFFECT: um dos seguintes valores de efeito:
      • NoSchedule: os pods que não toleram esta contaminação não são agendados no nó; os pods 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 no nó se ainda não estiver a ser executado no nó.
    • LABEL_KEY: a chave da etiqueta de nó que aplicou ao node pool dedicado.
    • LABEL_VALUE: o valor da etiqueta de nó que aplicou ao node pool dedicado.

    Por exemplo, o seguinte recurso Deployment adiciona uma tolerância para a contaminação 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 carga de trabalho de contentores:

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

    Substitua as seguintes variáveis:

    • NAMESPACE: o espaço de nomes da carga de trabalho de contentores. Para clusters partilhados, tem de ser um espaço de nomes do projeto. Para clusters padrão, pode ser qualquer espaço de nomes.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig para o cluster do Kubernetes.

O GDC recria os pods 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.

Valide o funcionamento da separação

Valide se os pods que designou estão a ser executados no node pool etiquetado.

  • Liste os pods no espaço de nomes indicado:

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

    Substitua as seguintes variáveis:

    • NAMESPACE: o espaço de nomes da carga de trabalho de contentores. Para clusters partilhados, tem de ser um espaço de nomes do projeto. Para clusters padrão, pode ser qualquer espaço de nomes.
    • KUBERNETES_CLUSTER_KUBECONFIG: o caminho kubeconfig para o cluster do Kubernetes.

    O resultado é semelhante ao seguinte:

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

    Confirme que as cargas de trabalho estão a ser executadas no node pool dedicado.

O que se segue?