Ejecuta cargas de trabajo no confiables con GKE Sandbox

En esta página, se describe cómo usar GKE Sandbox para proteger el kernel del host en tus nodos cuando los contenedores del pod ejecutan un código desconocido o que no es de confianza. Por ejemplo, los clústeres de múltiples instancias, como los proveedores de software como servicio (SaaS), suelen ejecutar código desconocido enviado por sus usuarios.

GKE Sandbox usa gVisor, un proyecto de código abierto. En este tema, se explica gVisor en líneas generales, pero puedes obtener más detalles en la documentación oficial de gVisor.

Descripción general

GKE Sandbox proporciona una capa adicional de seguridad para evitar que el código no confiable afecte al kernel del host en los nodos de clústeres. Antes de analizar cómo funciona GKE Sandbox, es útil comprender la naturaleza de los riesgos potenciales que ayuda a mitigar.

Un entorno de ejecución de contenedor como docker o containerd proporciona cierto grado de aislamiento entre los procesos del contenedor y el kernel que se ejecuta en el nodo. Sin embargo, el entorno de ejecución del contenedor a menudo se ejecuta como un usuario privilegiado en el nodo y tiene acceso a la mayoría de las llamadas del sistema al kernel del host.

Amenazas potenciales

Los clústeres de múltiples instancias y aquellos cuyos contenedores ejecutan cargas de trabajo que no son de confianza están más expuestos a vulnerabilidades de seguridad que otros clústeres. Los ejemplos incluyen proveedores de SaaS, proveedores de hosting web y otras organizaciones que permiten a sus usuarios subir y ejecutar código. Una falla en el entorno de ejecución del contenedor o en el kernel del host podría permitir que un proceso que se ejecuta dentro de un contenedor “escape” de este y afecte al kernel del nodo, lo que podría provocar la caída del nodo.

También existe la posibilidad de que una instancia maliciosa acceda a los datos de otro usuario o los filtre en la memoria o en el disco mediante la explotación de ese defecto.

Por último, una carga de trabajo que no sea de confianza podría acceder a otros servicios de Google Cloud Platform o metadatos del clúster.

Cómo GKE Sandbox mitiga estas amenazas

gVisor es una reimplementación de espacio de usuario de la API del kernel de Linux que no necesita privilegios elevados. En conjunto con un entorno de ejecución de contenedor como containerd, el kernel del espacio de usuario vuelve a implementar la mayoría de las llamadas al sistema y las entrega en nombre del kernel del host. El acceso directo al kernel del host es limitado. Consulta la guía de arquitectura de gVisor para obtener información detallada sobre cómo funciona. Desde el punto de vista del contenedor, gVisor es casi transparente y no requiere ningún cambio en la aplicación en contenedores.

Cuando habilitas GKE Sandbox en un grupo de nodos, se crea una zona de pruebas para cada pod que se ejecuta en un nodo en ese grupo de nodos. Además, los nodos que ejecutan pods de zona de pruebas no pueden acceder a otros servicios de GCP o metadatos de clúster.

Cada zona de pruebas usa su propio kernel de espacio de usuario. Con esto en mente, puedes tomar decisiones sobre cómo agrupar tus contenedores en pods, según el nivel de aislamiento que necesites y las características de tus aplicaciones.

GKE Sandbox es adecuado especialmente para los siguientes tipos de aplicaciones. Consulta las limitaciones para obtener más información que te ayude a decidir qué aplicaciones poner en zona de pruebas.

  • Aplicaciones no confiables o de terceros que usen entornos de ejecución, como Rust, Java, Python, PHP, Node.js o Golang
  • Cachés, proxies o frontends de servidores web
  • Aplicaciones que procesan medios o datos externos mediante CPU
  • Cargas de trabajo de aprendizaje automático con CPU
  • Aplicaciones que consumen mucha memoria o CPU

Recomendaciones de seguridad adicionales

Cuando uses GKE Sandbox, te sugerimos que también sigas estas recomendaciones:

  • A menos que tus nodos usen solo una CPU virtual única, te recomendamos que inhabilites los hipersubprocesos para mitigar las vulnerabilidades de muestreo de datos microarquitectónicos (MDS) anunciadas por Intel. Para obtener más información, consulta el boletín de seguridad.

  • Se recomienda que especifiques límites de recursos en todos los contenedores que se ejecutan en una zona de pruebas. Esto protege contra el riesgo de una aplicación defectuosa o maliciosa que prive al nodo de recursos y tenga un impacto negativo en otras aplicaciones o procesos del sistema que se ejecutan en el nodo.

Limitaciones

GKE Sandbox funciona bien con muchas aplicaciones, pero no con todas. En esta sección, se proporciona más información sobre las limitaciones actuales de GKE Sandbox.

Configuración de grupos de nodos

  • No puedes habilitar GKE Sandbox en el grupo de nodos predeterminado.
  • Cuando usas GKE Sandbox, tu clúster debe tener al menos dos grupos de nodos. Siempre debes tener al menos un grupo de nodos en el que GKE Sandbox esté inhabilitado. Este grupo de nodos debe contener al menos un nodo, incluso si todas tus cargas de trabajo están en la zona de pruebas.

Acceso a metadatos de clúster

  • Los nodos que ejecutan pods de zona de pruebas no pueden acceder a los metadatos del clúster en el nivel del sistema operativo del nodo.
  • Puedes ejecutar pods regulares en un nodo con GKE Sandbox habilitado. Sin embargo, de forma predeterminada, esos pods regulares no pueden acceder a los servicios de GCP o los metadatos del clúster. Usa Workload Identity para otorgar a los pods acceso a los servicios de GCP.

Funciones

De forma predeterminada, el contenedor no puede abrir sockets sin procesar para reducir la posibilidad de ataques maliciosos. Algunas herramientas relacionadas con la red, como ping y tcpdump, crean sockets sin procesar como parte de su funcionalidad principal. Para habilitar los sockets sin procesar, debes agregar de forma explícita la capacidad NET_RAW al contexto de seguridad del contenedor:

spec:
  containers:
  - name: my-container
    securityContext:
      capabilities:
        add: ["NET_RAW"]

Características incompatibles

En la actualidad, no es posible usar GKE Sandbox junto con las siguientes características de Kubernetes:

Características de la carga de trabajo

La imposición de una capa adicional de indirección para acceder al kernel del nodo tiene compensaciones de rendimiento. GKE Sandbox proporciona el beneficio más tangible en grandes clústeres de múltiples instancias en los que el aislamiento es importante. Ten en cuenta los siguientes lineamientos cuando pruebes tus cargas de trabajo con GKE Sandbox.

Llamadas al sistema

Las cargas de trabajo que generan un gran volumen de llamadas al sistema de baja sobrecarga, como una gran cantidad de pequeñas operaciones de E/S, pueden requerir más recursos del sistema cuando se ejecutan en una zona de pruebas, por lo que es posible que necesites usar nodos más potentes o agregar nodos adicionales a tu clúster.

Acceso directo a hardware o virtualización

Si tu carga de trabajo necesita algunos de los siguientes elementos, es posible que GKE Sandbox no sea una buena opción porque impide el acceso directo al kernel del host en el nodo:

  • Acceso directo al hardware del nodo
  • Funciones de virtualización a nivel del kernel
  • Contenedores privilegiados

Habilita GKE Sandbox

Puedes habilitar GKE Sandbox en un clúster nuevo o en un clúster existente.

Antes de comenzar

Sigue estos pasos a fin de prepararte para esta tarea:

  • Asegúrate de que habilitaste la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Asegúrate de que instalaste el SDK de Cloud.
  • Establece tu ID del proyecto predeterminado:
    gcloud config set project [PROJECT_ID]
  • Si trabajas con clústeres zonales, establece tu zona de procesamiento predeterminada:
    gcloud config set compute/zone [COMPUTE_ZONE]
  • Si trabajas con clústeres regionales, establece tu región de procesamiento predeterminada:
    gcloud config set compute/region [COMPUTE_REGION]
  • Actualiza gcloud a la versión más reciente:
    gcloud components update
  • GKE Sandbox requiere la versión de GKE v1.12.7-gke.17 o superior, o v1.13.5-gke.15 o superior, para los nodos y la instancia principal del clúster.
  • Asegúrate de que el comando gcloud sea de versión 243.0.0 o superior.

En un clúster nuevo

Para habilitar GKE Sandbox, configura un grupo de nodos. El grupo de nodos predeterminado (el primer grupo de nodos en tu clúster, creado junto con este) no puede usar GKE Sandbox. Para habilitar GKE Sandbox durante la creación del clúster, debes agregar un segundo grupo de nodos durante la creación.

Console

Para ver tus clústeres, visita el menú de Google Kubernetes Engine en GCP Console.

  1. Dirígete al menú Google Kubernetes Engine en GCP Console.

    Ir al menú Google Kubernetes Engine

  2. Haz clic en Crear clúster.

  3. Elige la plantilla Clúster estándar o elige una plantilla adecuada para tu carga de trabajo.

  4. Esta acción es opcional, pero se recomienda: habilita Stackdriver Logging y Stackdriver Monitoring para que se registren los mensajes de gVisor.

  5. Haz clic en Agregar grupo de nodos.

  6. Configura el grupo de nodos según tus requisitos. Haz clic en Más opciones de grupo de nodos para el grupo de nodos. Establece esta configuración:

    • Para la versión del nodo, selecciona v1.12.6-gke.8 o superior.
    • Para la imagen del nodo, selecciona Container-Optimized OS con Containerd (cos_containerd) (Beta).
    • Habilita Habilitar zona de pruebas con gVisor (Beta).
    • Si los nodos del grupo de nodos usan más de una CPU virtual, haz clic en Agregar etiqueta. Establece la clave en cloud.google.com/gke-smt-disabled y el valor en true. Luego, sigue las instrucciones para inhabilitar los hipersubprocesos del boletín de seguridad.

    Establece otras opciones de configuración del grupo de nodos según sea necesario.

  7. Guarda la configuración del grupo de nodos y continúa con la configuración de tu clúster.

gcloud

GKE Sandbox no se puede habilitar para el grupo de nodos predeterminado y no es posible crear grupos de nodos adicionales al mismo tiempo que creas un clúster nuevo con el comando gcloud. En su lugar, crea tu clúster como lo harías en condiciones normales. Es opcional, pero se recomienda que agregues la marca --enable-stackdriver-kubernetes para habilitar Stackdriver Logging y Stackdriver Monitoring. Los mensajes de gVisor se registran.

Luego, usa el comando gcloud beta container node-pools create y establece la marca --sandbox en type=gvisor. Reemplaza los valores entre corchetes con los tuyos y recuerda especificar una versión de nodo v1.12.6-gke.8 o superior.

gcloud beta container node-pools create [NODE_POOL_NAME] \
  --cluster=[CLUSTER_NAME] \
  --node-version=[NODE_VERSION] \
  --image-type=cos_containerd \
  --sandbox type=gvisor \
  --enable-autoupgrade

Se genera una instancia para la RuntimeClass gvisor durante la creación del nodo, antes de que se programen las cargas de trabajo en este. Puedes comprobar la existencia de la RuntimeClass gvisor con el siguiente comando:

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

En un clúster existente

Puedes habilitar GKE Sandbox en un clúster existente si agregas un grupo de nodos nuevo y habilitas la característica para este, o si modificas un grupo de nodos existente no predeterminado.

Console

  1. Dirígete al menú Google Kubernetes Engine en GCP Console.

    Ir al menú Google Kubernetes Engine

  2. Haz clic en el botón Editar del clúster, que tiene forma de lápiz.

  3. Si es necesario, agrega un grupo de nodos adicional. Para ello, haz clic en Agregar grupo de nodos. Para editar un grupo de nodos existente, haz clic en su botón Editar. No habilites Zona de pruebas con gVisor (Beta) en el grupo de nodos predeterminado.

  4. Habilita Zona de pruebas con gVisor (Beta) y, luego, haz clic en Listo.

  5. Si es necesario, realiza cambios de configuración adicionales en el clúster y, luego, haz clic en Guardar.

gcloud

Para crear un grupo de nodos nuevo con GKE Sandbox habilitado, usa un comando como el siguiente:

gcloud beta container node-pools create [NODE_POOL_NAME] \
  --cluster=[CLUSTER_NAME] \
  --image-type=cos_containerd \
  --sandbox type=gvisor \
  --enable-autoupgrade

Para habilitar GKE Sandbox en un grupo de nodos existente, usa un comando como el siguiente. No habilites --sandbox type=gvisor en el grupo de nodos predeterminado.

 gcloud beta container node-pools update [NODE_POOL_NAME] \
  --sandbox type=gvisor

Se genera una instancia para la RuntimeClass gvisor durante la creación del nodo, antes de que se programen las cargas de trabajo en este. Puedes comprobar la existencia de la RuntimeClass gvisor con el siguiente comando:

kubectl get runtimeclasses
NAME     AGE
gvisor   19s

Opcional: habilita Stackdriver Logging y Stackdriver Monitoring

Es opcional, pero se recomienda que habilites Stackdriver Logging y Stackdriver Monitoring en el clúster para que se registren los mensajes de gVisor. Debes usar Google Cloud Platform Console para habilitar estas características en un clúster existente.

  1. Dirígete al menú Google Kubernetes Engine en GCP Console.

    Ir al menú Google Kubernetes Engine

  2. Haz clic en el botón Editar del clúster, que tiene forma de lápiz.

  3. Habilita Stackdriver Logging y Stackdriver Monitoring.

  4. Si es necesario, realiza cambios de configuración adicionales en el clúster y, luego, haz clic en Guardar.

Trabaja con GKE Sandbox

Ejecuta una aplicación en una zona de pruebas

Para hacer que una implementación se ejecute en un nodo con GKE Sandbox habilitado, debes establecer su spec.template.spec.runtimeClassName en gvisor, como se muestra en este manifiesto para una implementación:

# 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 crear la implementación, usa el comando kubectl create:

kubectl create -f httpd.yaml

El pod se implementa en un nodo de un grupo de nodos con GKE Sandbox habilitado. Para verificar esto, usa el comando kubectl get pods a fin de encontrar el nodo en el que se implementa el pod:

kubectl get pods

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

Busca el nombre del pod en el resultado y ejecuta el siguiente comando a fin de verificar su valor para RuntimeClass:

kubectl get pods [NAME-OF-POD] -o jsonpath='{.spec.runtimeClassName}'

gvisor

También puedes enumerar la RuntimeClass de cada pod y buscar las que están configuradas como gvisor:

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

[NAME-OF-POD]: gvisor

Este método para verificar que el pod se ejecute en una zona de pruebas es confiable, ya que no depende de ningún dato dentro de la zona de pruebas. Todo lo que se informe desde la zona de pruebas no es confiable, ya que podría ser defectuoso o malicioso.

Ejecuta un pod regular junto con pods de zona de pruebas

Después de habilitar GKE Sandbox en un grupo de nodos, puedes ejecutar aplicaciones confiables en esos nodos sin usar una zona de pruebas mediante tolerancias y taints de nodo. Estos pods se denominan “pods regulares” para distinguirlos de los pods de zona de pruebas.

Los pods regulares, al igual que los pods de zona de pruebas, no pueden acceder a otros servicios de GCP o metadatos de clúster. Esta prevención es parte de la configuración del nodo. Si tus pods regulares o de zona de pruebas requieren acceso a los servicios de GCP, usa Workload Identity.

GKE Sandbox agrega la siguiente etiqueta y taint a los nodos que pueden ejecutar pods de zona de pruebas:

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

Además de cualquier configuración de tolerancia y afinidad de nodo en tu manifiesto de pod, GKE Sandbox aplica la siguiente tolerancia y afinidad de nodo a todos los pods con RuntimeClass establecido en 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 un pod regular en un nodo con GKE Sandbox habilitado, aplica de forma manual la tolerancia y la afinidad de nodo anteriores en el manifiesto de tu pod.

  • Si el pod puede ejecutarse en nodos con GKE Sandbox habilitado, agrega la tolerancia.
  • Si tu pod debe ejecutarse en nodos con GKE Sandbox habilitado, agrega la tolerancia y la afinidad de nodo.

Por ejemplo, con el siguiente manifiesto se modifica el manifiesto usado en Ejecuta una aplicación en una zona de pruebas a fin de que se ejecute como un pod regular en un nodo con pods de zona de pruebas, para esto, se quita la runtimeClass y se agrega el taint y la tolerancia anteriores.

# 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

Primero, verifica que la implementación no se ejecute en una zona de pruebas:

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

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

La implementación httpd creada antes se ejecuta en una zona de pruebas, porque su runtimeClass es gvisor. La implementación httpd-no-sandbox no tiene valor para runtimeClass, por lo que no está en ejecución en una zona de pruebas.

A continuación, comprueba que la implementación sin zona de pruebas se ejecute en un nodo con GKE Sandbox mediante la ejecución del siguiente comando:

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

El nombre del grupo de nodos está incorporado en el valor de nodeName. Verifica que el pod se ejecute en un nodo de un grupo de nodos con GKE Sandbox habilitado.

Verifica la protección de metadatos

Para validar la afirmación de que los metadatos están protegidos de los nodos que pueden ejecutar pods de zona de pruebas, puedes realizar una prueba:

  1. Crea una implementación de zona de pruebas del siguiente manifiesto con kubectl apply -f. Usa la imagen fedora, que incluye el comando curl. El pod ejecuta el comando /bin/sleep para garantizar que la implementación se ejecute durante 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. Obtén el nombre del pod mediante kubectl get pods y, luego, usa kubectl exec para conectarte al pod de manera interactiva.

    kubectl exec -it [POD-NAME] /bin/sh
    

    Estás conectado a un contenedor que se ejecuta en el pod, en una sesión /bin/sh.

  3. Dentro de la sesión interactiva, intenta acceder a una URL que muestre metadatos de clúster:

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

    El comando se cuelga y, por último, se agota el tiempo de espera, porque los paquetes se descartan en silencio.

  4. Presiona Ctrl+C para terminar el comando curl y escribe exit a fin de desconectarte del pod.

  5. Quita la línea RuntimeClass del manifiesto YAML y vuelve a implementar el pod mediante kubectl apply -f [FILENAME]. El pod de zona de pruebas se termina y se vuelve a crear en un nodo sin GKE Sandbox.

  6. Obtén el nombre de pod nuevo, conéctate a él mediante kubectl exec y vuelve a ejecutar el comando curl. Esta vez, se muestran resultados. Este resultado de ejemplo 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;...
    ...
    

    Escribe exit para desconectarte del pod.

  7. Quita la implementación:

    kubectl delete deployment fedora
    

Inhabilita GKE Sandbox

En la actualidad, no es posible actualizar un grupo de nodos para inhabilitar GKE Sandbox. Para inhabilitar GKE Sandbox en un grupo de nodos existente, puedes realizar uno de los procedimientos siguientes:

  • Borra los pods de zona de pruebas. De lo contrario, después de inhabilitar GKE Sandbox, esos pods se ejecutarán como pods regulares si no hay nodos disponibles que tengan habilitado GKE Sandbox. Luego, borra el grupo de nodos en el que estaba habilitado GKE Sandbox, o
  • Cambia el tamaño del grupo de nodos a cero nodos, o
  • Vuelve a crear los pods sin especificar un valor para RuntimeClassName.

Qué sigue

¿Te ha resultado útil esta página? Enviar comentarios:

Enviar comentarios sobre...

Documentación de Kubernetes Engine