Aísla tus cargas de trabajo en grupos de nodos dedicados


En esta página, se muestra cómo reducir el riesgo de ataques de elevación de privilegios en tu clúster cuando le indicas a Google Kubernetes Engine (GKE) que programe tus cargas de trabajo en un grupo de nodos dedicado y separado de las cargas de trabajo administradas por GKE con privilegios. Esta página se aplica a los clústeres estándar sin aprovisionamiento automático de nodos. Para separar las cargas de trabajo en clústeres de Autopilot y en clústeres de estándar con aprovisionamiento automático de nodos habilitado, consulta Configura la separación de cargas de trabajo en GKE.

Descripción general

Los clústeres de GKE usan cargas de trabajo administradas por GKE con privilegios para habilitar funciones y características específicas del clúster, como la recopilación de métricas. Estas cargas de trabajo tienen permisos especiales para ejecutarse de forma correcta en el clúster.

Las cargas de trabajo que implementas en tus nodos pueden tener el potencial de verse comprometidas por una entidad maliciosa. Ejecutar estas cargas de trabajo junto con cargas de trabajo administradas por GKE significa que un atacante que sale de un contenedor vulnerado puede usar las credenciales de la carga de trabajo con privilegios en el nodo para escalar privilegios en tu clúster.

Evita interrupciones de contenedores

Tu defensa principal deben ser las aplicaciones. GKE tiene varias funciones que puedes usar para endurecer los clústeres y Pods. En la mayoría de los casos, recomendamos usar GKE Sandbox para aislar las cargas de trabajo. GKE Sandbox se basa en el proyecto de código abierto gVisor y, luego, implementa la API del kernel de Linux en el espacio del usuario. Cada Pod se ejecuta en un kernel dedicado que aísla las aplicaciones de las zonas de pruebas para evitar el acceso a las llamadas privilegiadas del sistema en el kernel del host. Las cargas de trabajo que se ejecutan en GKE Sandbox se programan automáticamente en nodos separados, aislados de otras cargas de trabajo.

También debes seguir las recomendaciones que aparecen en Endurece la seguridad de tu clúster.

Evita ataques de elevación de privilegios

Si no puedes usar GKE Sandbox y deseas una capa adicional de aislamiento, además de otras medidas de endurecimiento, puedes usar los taints de nodos y la afinidad de nodos para programar tus cargas de trabajo en un grupo de nodos dedicado. Un taint de nodo le indica a GKE que evite programar cargas de trabajo sin una tolerancia correspondiente (como las cargas de trabajo administradas por GKE) en esos nodos. La afinidad de nodos en tus propias cargas de trabajo le indica a GKE que programe tus Pods en los nodos dedicados.

Limitaciones del aislamiento de nodos

  • Los atacantes aún pueden iniciar ataques de denegación del servicio (DoS) desde el nodo vulnerado.
  • Los nodos vulnerados aún pueden leer muchos recursos, incluidos todos los Pods y los espacios de nombres en el clúster.
  • Los nodos vulnerados pueden acceder a los objetos Secret y a las credenciales que usan todos los Pods que se ejecutan en ese nodo.
  • El uso de un grupo de nodos separado para aislar las cargas de trabajo puede afectar la rentabilidad, el ajuste de escala automático y el uso de recursos.
  • Los nodos vulnerados aún pueden omitir las políticas de red de salida.
  • Algunas cargas de trabajo administradas por GKE deben ejecutarse en cada nodo del clúster y están configuradas para tolerar todos los taints.
  • Si implementas DaemonSets que tienen permisos elevados y pueden tolerar cualquier taint, esos Pods pueden ser una ruta para la elevación de privilegios desde un nodo vulnerado.

Cómo funciona el aislamiento de nodos

A fin de implementar el aislamiento de nodos para las cargas de trabajo, debes hacer lo siguiente:

  1. Aplica un taint y una etiqueta a un grupo de nodos para las cargas de trabajo.
  2. Actualiza tus cargas de trabajo con la regla correspondiente de tolerancia y afinidad de nodos.

En esta guía, se da por sentado que comienzas con un grupo de nodos en el clúster. No es obligatorio usar la afinidad de nodos además de los taints de nodo, pero te lo recomendamos porque te beneficiarás de un mayor control sobre la programación.

Antes de comenzar

Antes de comenzar, asegúrate de haber realizado las siguientes tareas:

  • Habilita la API de Google Kubernetes Engine.
  • Habilitar la API de Google Kubernetes Engine
  • Si deseas usar Google Cloud CLI para esta tarea, instala y, luego, inicializa gcloud CLI. Si ya instalaste gcloud CLI, ejecuta gcloud components update para obtener la versión más reciente.
  • Elige un nombre específico para el taint de nodo y la etiqueta de nodo que deseas usar para los grupos de nodos dedicados. Para este ejemplo, usamos workloadType=untrusted.

Aplica un taint y una etiqueta a un grupo de nodos para las cargas de trabajo

Crea un grupo de nodos nuevo para tus cargas de trabajo y aplica un taint de nodo y una etiqueta de nodo. Cuando aplicas un taint o una etiqueta a nivel del grupo de nodos, cualquier nodo nuevo, como los creados por el ajuste de escala automático, obtendrá automáticamente los taints y las etiquetas especificados.

También puedes agregar taints de nodos y etiquetas de nodos a los grupos de nodos existentes. Si usas el efecto NoExecute, GKE expulsa los Pods que se ejecutan en esos nodos que no tienen una tolerancia para el taint nuevo.

Para agregar un taint y una etiqueta a un grupo de nodos nuevo, ejecuta el siguiente comando:

gcloud container node-pools create POOL_NAME \
    --cluster CLUSTER_NAME \
    --node-taints TAINT_KEY=TAINT_VALUE:TAINT_EFFECT \
    --node-labels LABEL_KEY=LABEL_VALUE

Reemplaza lo siguiente:

  • POOL_NAME: el nombre del grupo de nodos nuevo para las cargas de trabajo.
  • CLUSTER_NAME: Es el nombre del clúster de GKE.
  • TAINT_KEY=TAINT_VALUE: un par clave-valor asociado con una programación de TAINT_EFFECT. Por ejemplo, workloadType=untrusted.
  • TAINT_EFFECT: uno de los siguientes valores de efectos: NoSchedule, PreferNoSchedule o NoExecute. NoExecute proporciona una garantía de expulsión mejor que NoSchedule.
  • LABEL_KEY=LABEL_VALUE: Son los pares clave-valor para las etiquetas de nodo, que corresponden a los selectores que especificas en los manifiestos de cargas de trabajo.

Agrega una regla de tolerancia y afinidad de nodos a tus cargas de trabajo

Después de aplicar un taint al grupo de nodos dedicado, ninguna carga de trabajo puede programarlo, a menos que tenga una tolerancia correspondiente al taint que agregaste. Agrega la tolerancia a la especificación de tus cargas de trabajo para permitir que esos Pods se programen en tu grupo de nodos con taints.

Si etiquetaste el grupo de nodos dedicado, también puedes agregar una regla de afinidad de nodos para indicar a GKE que solo programe las cargas de trabajo en ese grupo de nodos.

En el siguiente ejemplo, se agrega una tolerancia para el taint workloadType=untrusted:NoExecute y una regla de afinidad de nodos para la etiqueta de nodo 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: TAINT_KEY
        operator: Equal
        value: TAINT_VALUE
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: LABEL_KEY
                operator: In
                values:
                - "LABEL_VALUE"
      containers:
      - name: sleep
        image: ubuntu
        command: ["/bin/sleep", "inf"]

Reemplaza lo siguiente:

  • TAINT_KEY: La clave de taint que aplicaste al grupo de nodos dedicado.
  • TAINT_VALUE: El valor de taint que aplicaste a tu grupo de nodos dedicado.
  • LABEL_KEY: Es la clave de etiqueta de nodo que aplicaste a tu grupo de nodos dedicado.
  • LABEL_VALUE: Es el valor de la etiqueta de nodo que aplicaste a tu grupo de nodos dedicado.

Cuando actualizas el objeto Deployment con kubectl apply, GKE vuelve a crear los Pods afectados. La regla de afinidad de nodos fuerza a los Pods al grupo de nodos dedicado que creaste. La tolerancia solo permite que se coloquen esos Pods en los nodos.

Verifica que la separación funcione

Para verificar que la programación funcione correctamente, ejecuta el siguiente comando y verifica si tus cargas de trabajo están en el grupo de nodos dedicado:

kubectl get pods -o=wide

Recomendaciones y prácticas recomendadas

Después de configurar el aislamiento de nodos, te recomendamos que hagas lo siguiente:

  • Restringe grupos de nodos específicos a cargas de trabajo administradas por GKE solo mediante la adición del taint components.gke.io/gke-managed-components. Agregar este taint evita que tus propios Pods se programen en esos nodos, lo que mejora el aislamiento.
  • Cuando crees grupos de nodos nuevos, evita que la mayoría de las cargas de trabajo administradas por GKE se ejecuten en esos nodos; para ello, agrega tu propio taint a esos grupos.
  • Cuando implementes cargas de trabajo nuevas en el clúster, como cuando se instalan herramientas de terceros, audita los permisos que requieren los Pods. Cuando sea posible, evita implementar cargas de trabajo que usen permisos elevados en los nodos compartidos.

¿Qué sigue?