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, verifique se você realizou as tarefas a seguir:

Defina as configurações padrão da gcloud usando um dos métodos a seguir:

  • Use gcloud init se quiser orientações para definir os padrões.
  • Use gcloud config para definir individualmente a região, a zona e o ID do projeto.

Como usar o gcloud init

Se você receber o erro One of [--zone, --region] must be supplied: Please specify location, conclua esta seção.

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

Como usar o gcloud config

  • Defina o ID do projeto padrão:
    gcloud config set project project-id
  • Se você estiver trabalhando com clusters zonais, defina a zona do Compute padrão:
    gcloud config set compute/zone compute-zone
  • Se você estiver trabalhando com clusters regionais, defina a região do Compute padrão:
    gcloud config set compute/region compute-region
  • Atualize gcloud para a versão mais recente:
    gcloud components update
  • O GKE Sandbox exige o GKE v1.12.7-gke.17 ou superior, ou v1.13.5-gke.15 ou superior, para os nós e mestre do cluster.
  • Certifique-se de que o comando gcloud seja da versão 243.0.0 ou superior.

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 o menu do Google Kubernetes Engine no Console do Cloud.

    Acessar o menu do Google Kubernetes Engine

  2. Clique no botão Criar cluster.

  3. Opcional, mas recomendado : ative o Stackdriver Logging e o Stackdriver Monitoring para que as mensagens do gVisor sejam registradas.

  4. Clique em Adicionar pool de nós.

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

    • Na seção Nós, para tipo de imagem, selecione SO do Container-Optimized com Containerd (cos_containerd) (Beta).
    • Na seção Segurança, marque a caixa de seleção Ativar sandbox com o gVisor.

    Defina outras configurações do pool de nós conforme necessário.

  6. Salve as configurações do pool de nós e continue configurando o cluster.

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. É opcional, mas recomendável, ativar o Stackdriver Logging e o Stackdriver Monitoring adicionando a sinalização --enable-stackdriver-kubernetes. As mensagens do gVisor são registradas.

Em seguida, use o comando gcloud container node-pools create e defina a sinalização --sandbox como type=gvisor. Substitua os valores entre colchetes pelos seus e lembre-se de especificar uma versão de nó de v1.12.6-gke.8 ou superior.

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 \

A RuntimeClass do gvisor é instanciada durante a criação do nó, antes de qualquer carga de trabalho ser programada no nó. É possível verificar a existência de RuntimeClass do gvisor usando o comando a seguir:

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

Também é preciso aguardar 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

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 ou modificando um pool de nós não padrão atual.

Console

  1. Acesse o menu do Google Kubernetes Engine no Console do Cloud.

    Acessar o menu do Google Kubernetes Engine

  2. Clique no botão de edição do cluster, que tem a forma de um lápis.

  3. Se necessário, adicione outro pool de nós clicando em Adicionar pool de nós. Para editar um pool de nós atual, clique no botão "Editar" do pool de nós. Não ative o Sandbox com o gVisor no pool de nós padrão.

  4. Ative o Sandbox com o gVisor e clique em Concluir.

  5. Se necessário, faça outras alterações de configuração no cluster e clique em Salvar.

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

Para ativar o GKE Sandbox em um pool de nós atual, use um comando como este. Não ative --sandbox type=gvisor no pool de nós padrão.

 gcloud container node-pools update node-pool-name \
  --sandbox type=gvisor

A RuntimeClass do gvisor é instanciada durante a criação do nó, antes de qualquer carga de trabalho ser programada no nó. É possível verificar a existência de RuntimeClass do gvisor usando o comando a seguir:

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

Também é preciso aguardar 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 o Stackdriver Logging e o Stackdriver Monitoring

É opcional, mas recomendável, ativar o Stackdriver Logging e o Stackdriver Monitoring no cluster para que as mensagens do gVisor sejam registradas. Você precisa usar o Console do Google Cloud para ativar esses recursos em um cluster atual.

  1. Acesse o menu do Google Kubernetes Engine no Console do Cloud.

    Acessar o menu do Google Kubernetes Engine

  2. Clique no botão de edição do cluster, que tem a forma de um lápis.

  3. Ative o Stackdriver Logging e o Stackdriver Monitoring.

  4. Se necessário, faça outras alterações de configuração no cluster e clique em Salvar.

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 resposta é semelhante a:

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: gvisor
taints:
- effect: NoSchedule
  key: sandbox.gke.io
  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:

  • Exclua os pods que estavam previamente em sandbox. Caso contrário, após a desativação do GKE Sandbox, esses pods serão executados como pods normais se nenhum nó disponível estiver ativado no GKE Sandbox. Em seguida, exclua o pool de nós em que o GKE Sandbox estava ativado. Ou
  • Redimensione o pool de nós para zero nós . Ou
  • Recrie os pods sem especificar um valor para RuntimeClassName.

A seguir