Como aumentar a proteção do isolamento da carga de trabalho com o GKE Sandbox


Nesta página, descrevemos como usar o GKE Sandbox para proteger o kernel do host nos nós quando os contêineres no pod executam código desconhecido ou não confiável, ou quando precisam de isolamento adicional do nó.

Como ativar o GKE Sandbox

É possível ativar o GKE Sandbox em um cluster novo ou atual.

Antes de começar

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

  • Verifique se você ativou a API do Google Kubernetes Engine.
  • Ativar a API Google Kubernetes Engine
  • Verifique se o SDK do Cloud está instalado.
  • Defina as configurações padrão da ferramenta de linha de comando gcloud do seu projeto usando um dos seguintes métodos:
    • Use gcloud init se quiser orientações para definir os padrões do projeto.
    • Use gcloud config para definir individualmente a região, a zona e o ID do projeto.

    gcloud init

    1. Execute gcloud init e siga as instruções:

      gcloud init

      Se você estiver usando SSH em um servidor remoto, utilize a sinalização --console-only para impedir que o comando inicie um navegador:

      gcloud init --console-only
    2. Siga as instruções para autorizar a ferramenta gcloud a usar sua conta do Google Cloud.
    3. Crie uma nova configuração ou selecione uma atual.
    4. Escolha um projeto do Google Cloud.
    5. Escolha uma zona padrão do Compute Engine.
    6. Escolha uma região padrão do Compute Engine.

    gcloud config

    1. Defina o ID do projeto padrão:
      gcloud config set project PROJECT_ID
    2. Defina a região padrão do Compute Engine (por exemplo, us-central1):
      gcloud config set compute/region COMPUTE_REGION
    3. Defina a zona padrão do Compute Engine (por exemplo, us-central1-c):
      gcloud config set compute/zone COMPUTE_ZONE
    4. Atualize gcloud para a versão mais recente:
      gcloud components update

    Ao definir locais padrão, é possível evitar erros na ferramenta gcloud como o seguinte: One of [--zone, --region] must be supplied: Please specify location.

  • O GKE Sandbox requer a versão 1.13.5-gke.15 ou posterior do GKE para o plano de controle do cluster e os nós.
  • Verifique se a versão do SDK do Cloud é 243.0.0 ou posterior.

Em um novo cluster

Para ativar o GKE Sandbox, configure um pool de nós. O pool de nós padrão (o primeiro pool de nós do cluster, criado quando o cluster é criado) não pode usar o GKE Sandbox. Para ativar o GKE Sandbox durante a criação do cluster, é necessário adicionar um segundo pool de nós ao criar o cluster.

Console

Para visualizar os clusters, acesse o menu do Google Kubernetes Engine no Console do Cloud.

  1. Acesse a página do Google Kubernetes Engine no Console do Cloud:

    Acessar o Google Kubernetes Engine

  2. Clique em Criar.

  3. Opcional, mas recomendado: no painel de navegação, em Cluster, clique em Recursos e ative as Operações do Cloud para GKE para que as mensagens do gVisor sejam registradas.

  4. Clique em Adicionar pool de nós.

  5. No painel de navegação, em Pools de nós, expanda o novo pool de nós e clique em Nós.

  6. Defina as configurações a seguir para o pool de nós:

    1. Na lista suspensa Tipo de imagem, selecione Container-Optimized OS com Containerd (cos_containerd). Esse é o único tipo de imagem compatível com o GKE Sandbox.
    2. Em Configuração da máquina, selecione uma Série e um Tipo de máquina.

  7. No painel de navegação, abaixo do nome do pool de nós que você está configurando, clique em Segurança e marque a caixa de seleção Ativar sandbox com o gVisor.

  8. Continue configurando os pools de nós e de cluster como quiser.

  9. Clique em Criar.

gcloud

O GKE Sandbox não pode ser ativado para o pool de nós padrão e não é possível criar outros pools de nós ao mesmo tempo que você cria um novo cluster usando o comando gcloud. Em vez disso, crie seu cluster normalmente. Embora seja opcional, é recomendável ativar o Cloud Operations para GKE para que as mensagens do gVisor sejam registradas.

Em seguida, use o comando gcloud container node-pools create e defina a sinalização -- sandbox como type=gvisor. O tipo de imagem do nó precisa ser cos_containerd para o GKE Sandbox.

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --node-version=NODE_VERSION \
  --machine-type=MACHINE_TYPE \
  --image-type=cos_containerd \
  --sandbox type=gvisor

Substitua as seguintes variáveis:

  • NODE_POOL_NAME: o nome do novo pool de nós.
  • CLUSTER_NAME: o nome do cluster.
  • NODE_VERSION: a versão a ser usada no pool de nós.
  • MACHINE_TYPE: o tipo de máquina a ser usado para os nós. O GKE Sandbox não é compatível com os tipos de máquina e2-micro, e2-small e e2-medium.

Antes de 1.18.4-gke.1300, a RuntimeClass do gvisor é instanciada durante a criação do nó. Antes de qualquer carga de trabalho ser programada no nó, verifique a existência da RuntimeClass do gvisor usando o comando a seguir:

kubectl get runtimeclasses

A saída será assim:

NAME     AGE
gvisor   19s

Se você estiver executando uma versão anterior à 1.17.9-gke.1500 ou uma versão 1.18 anterior a 1.18.6-gke.600, também precisará esperar que gvisor.config.common-webhooks.networking.gke.io seja instanciado. Para verificar, use o comando a seguir:

kubectl get mutatingwebhookconfiguration gvisor.config.common-webhooks.networking.gke.io

A saída será assim:

NAME                                              CREATED AT
gvisor.config.common-webhooks.networking.gke.io   2020-04-06T17:07:17Z

Em um cluster atual

É possível ativar o GKE Sandbox em um cluster atual adicionando um novo pool de nós e ativando o recurso para esse pool de nós.

Console

Para criar um novo pool de nós com o GKE Sandbox ativado:

  1. Acesse a página do Google Kubernetes Engine no Console do Cloud.

    Acessar o Google Kubernetes Engine

  2. Clique no nome do cluster que você quer modificar.

  3. Clique em Adicionar pool de nós.

  4. Configure a página Detalhes do pool de nós como quiser.

  5. No painel de navegação, clique em Nós e defina as seguintes configurações:

    1. Na lista suspensa Tipo de imagem, selecione Container-Optimized OS com Containerd (cos_containerd). Esse é o único tipo de imagem compatível com o GKE Sandbox.
    2. Em Configuração da máquina, selecione uma Série e um Tipo de máquina.

  6. No painel de navegação, clique em Segurança e marque a caixa de seleção Ativar sandbox com o gVisor.

  7. Clique em Criar.

gcloud

Para criar um novo pool de nós com o GKE Sandbox ativado, use um comando como este:

gcloud container node-pools create NODE_POOL_NAME \
  --cluster=CLUSTER_NAME \
  --machine-type=MACHINE_TYPE \
  --image-type=cos_containerd \
  --sandbox type=gvisor

O tipo de imagem do nó precisa ser cos_containerd para o GKE Sandbox.

Antes de 1.18.4-gke.1300, a RuntimeClass do gvisor é instanciada durante a criação do nó. Antes de qualquer carga de trabalho ser programada no nó, verifique a existência da RuntimeClass do gvisor usando o comando a seguir:

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

Se você estiver executando uma versão anterior à 1.17.9-gke.1500 ou uma versão 1.18 anterior a 1.18.6-gke.600, também precisará esperar que gvisor.config.common-webhooks.networking.gke.io seja instanciado. Para verificar, use o comando a seguir:

kubectl get mutatingwebhookconfiguration gvisor.config.common-webhooks.networking.gke.io
NAME                                              CREATED AT
gvisor.config.common-webhooks.networking.gke.io   2020-04-06T17:07:17Z

Opcional: ativar operações do Cloud para o GKE

É opcional, mas recomendável, ativar as Operações do Cloud para o GKE no cluster para que as mensagens do gVisor sejam registradas. As operações do Cloud para o GKE são ativadas por padrão para novos clusters.

Use o Console do Google Cloud para ativar esses recursos em um cluster atual.

  1. Acesse a página do Google Kubernetes Engine no Console do Cloud.

    Acessar o Google Kubernetes Engine

  2. Clique no nome do cluster que você quer modificar.

  3. Em Recursos, no campo Operações do Cloud para o GKE, clique em Editar operações do Cloud para o GKE.

  4. Marque a caixa de seleção Ativar operações do Cloud para o GKE.

  5. Na lista suspensa, selecione Geração de registros e monitoramento do sistema e de cargas de trabalho.

  6. Clique em Salvar alterações.

Como trabalhar com o GKE Sandbox

Como executar um aplicativo em um sandbox

Para forçar uma implantação a ser executada em um nó com o GKE Sandbox ativado, defina spec.template.spec.runtimeClassName para gvisor, conforme mostrado por este manifesto para uma implantação:

# httpd.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      runtimeClassName: gvisor
      containers:
      - name: httpd
        image: httpd

Para criar a implantação, use o comando kubectl create:

kubectl create -f httpd.yaml

O pod é implantado em um nó em um pool de nós com o GKE Sandbox ativado. Para verificar a implantação, use o comando a seguir para encontrar o nó em que o pod está implantado:

kubectl get pods

A saída será assim:

NAME                    READY   STATUS    RESTARTS   AGE
httpd-db5899bc9-dk7lk   1/1     Running   0          24s

Na resposta, encontre o nome do pod e, em seguida, execute o comando a seguir para verificar o valor dele para RuntimeClass:

kubectl get pods POD_NAME -o jsonpath='{.spec.runtimeClassName}'

A saída é:

gvisor

Como alternativa, é possível listar a RuntimeClass de cada pod e procurar aqueles em que ela está definida como gvisor:

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

A resposta é:

POD_NAME: gvisor

Esse método para verificar se o pod está sendo executado em um sandbox é confiável, porque não depende de dados no próprio sandbox. Qualquer item do sandbox que seja reportado não é confiável, porque pode estar com erros ou ser malicioso.

Como executar um pod normal junto com pods no sandbox

Depois de ativar o GKE Sandbox em um pool de nós, é possível executar aplicativos confiáveis nesses nós sem usar um sandbox, com tolerâncias e taints de nó. Esses pods são chamados de “pods normais” para diferenciá-los dos pods em sandbox.

Os pods regulares, assim como os pods de sandbox, são impedidos de acessar outros serviços do Google Cloud ou metadados de cluster. Essa prevenção faz parte da configuração do nó. Se os pods regulares ou os de sandbox exigirem acesso aos serviços do Google Cloud, use a identidade da carga de trabalho.

O GKE Sandbox adiciona o seguinte rótulo e taint aos nós que podem executar pods no sandbox:

labels:
  sandbox.gke.io/runtime: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io/runtime
  value: gvisor

Além das configurações de afinidade e tolerância do nó no manifesto do pod, o GKE Sandbox aplica a seguinte afinidade e tolerância a todos os pods com RuntimeClass definida no gvisor:

affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: sandbox.gke.io/runtime
          operator: In
          values:
          - gvisor
tolerations:
  - effect: NoSchedule
    key: sandbox.gke.io/runtime
    operator: Equal
    value: gvisor

Para programar um pod normal em um nó com o GKE Sandbox ativado, aplique manualmente a afinidade e a tolerância do nó acima no manifesto do pod.

  • Se seu pod puder ser executado em nós com o GKE Sandbox ativado, adicione a tolerância.
  • Se seu pod precisar ser executado em nós com o GKE Sandbox ativado, adicione a afinidade e a tolerância do nó.

Por exemplo, o manifesto a seguir modifica o manifesto usado em Como executar um aplicativo em um sandbox para que ele seja executado como um pod normal em um nó com pods do sandbox removendo a runtimeClass e adicionando a tolerância e o taint acima.

# httpd-no-sandbox.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: httpd-no-sandbox
  labels:
    app: httpd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: httpd
  template:
    metadata:
      labels:
        app: httpd
    spec:
      containers:
      - name: httpd
        image: httpd
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: sandbox.gke.io/runtime
                operator: In
                values:
                - gvisor
      tolerations:
        - effect: NoSchedule
          key: sandbox.gke.io/runtime
          operator: Equal
          value: gvisor

Primeiro, verifique se o Deployment não está sendo executado em um sandbox:

kubectl get pods -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.runtimeClassName}\n{end}'

A resposta é semelhante a:

httpd-db5899bc9-dk7lk: gvisor
httpd-no-sandbox-5bf87996c6-cfmmd:

A implantação httpd criada anteriormente está sendo executada em um sandbox, porque sua runtimeClass é gvisor. A implantação httpd-no-sandbox não tem valor para runtimeClass. Por isso, ela não está sendo executada em um sandbox.

Em seguida, verifique se a implantação fora do sandbox está em execução em um nó com o GKE Sandbox executando o seguinte comando:

kubectl get pod -o jsonpath=$'{range .items[*]}{.metadata.name}: {.spec.nodeName}\n{end}'

O nome do pool de nós é incorporado ao valor de nodeName. Verifique se o pod está sendo executado em um nó em um pool de nós com o GKE Sandbox ativado.

Como verificar a proteção de metadados

Para validar a afirmação de que os metadados estão protegidos dos nós que podem executar pods no sandbox, é possível fazer um teste:

  1. Crie uma implantação em sandbox a partir do seguinte manifesto, usando kubectl apply -f. Ele usa a imagem fedora, que inclui o comando curl. O pod executa o comando /bin/sleep para garantir que a implantação seja executada por 10.000 segundos.

    # sandbox-metadata-test.yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: fedora
      labels:
        app: fedora
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: fedora
      template:
        metadata:
          labels:
            app: fedora
        spec:
          runtimeClassName: gvisor
          containers:
          - name: fedora
            image: fedora
            command: ["/bin/sleep","10000"]
    
  2. Consiga o nome do pod usando kubectl get pods e use kubectl exec para se conectar ao pod de forma interativa.

    kubectl exec -it POD_NAME /bin/sh
    

    Você está conectado a um contêiner em execução no pod, em uma sessão /bin/sh.

  3. Na sessão interativa, tente acessar um URL que retorne metadados de cluster:

    curl -s "http://metadata.google.internal/computeMetadata/v1/instance/attributes/kube-env" -H "Metadata-Flavor: Google"
    

    O comando trava e, por fim, expira, porque os pacotes são descartados silenciosamente.

  4. Pressione Ctrl+C para encerrar o comando curl e digite exit para se desconectar do pod.

  5. Remova a linha RuntimeClass do manifesto YAML e reimplante o pod usando kubectl apply -f FILENAME. O pod no sandbox é encerrado e recriado em um nó sem o GKE Sandbox.

  6. Consiga o novo nome do pod, conecte-se a ele usando kubectl exec e execute o comando curl novamente. Dessa vez, os resultados são retornados. Este exemplo de resultado está truncado.

    ALLOCATE_NODE_CIDRS: "true"
    API_SERVER_TEST_LOG_LEVEL: --v=3
    AUTOSCALER_ENV_VARS: kube_reserved=cpu=60m,memory=960Mi,ephemeral-storage=41Gi;...
    ...
    

    Digite exit para se desconectar do pod.

  7. Remova a implantação:

    kubectl delete deployment fedora
    

Como desativar o GKE Sandbox

No momento, não é possível atualizar um pool de nós para desativar o GKE Sandbox. Para desativar o GKE Sandbox em um pool de nós atual, é possível realizar uma das seguintes ações:

A seguir