Mitiga incidentes de seguridad


En este documento se describen las mitigaciones y respuestas comunes a posibles incidentes de seguridad en los clústeres y contenedores de Google Kubernetes Engine (GKE).

Las sugerencias en la sección Endurecimiento de la seguridad del clúster pueden mejorar la seguridad de tus cargas de trabajo de GKE. Sin embargo, se pueden producir incidentes de seguridad incluso cuando existen medidas para protegerlas.

Detecta incidentes

A fin de detectar posibles incidentes, te recomendamos que configures un proceso que recopile y supervise los registros de tu carga de trabajo. Luego, configura alertas según los eventos anormales detectados en los registros. Las alertas notifican a tu equipo de seguridad si se detecta algo inusual, y, a continuación, ellos pueden revisar el incidente potencial.

Genera alertas a partir de registros

Puedes personalizar alertas según métricas o acciones específicas. Por ejemplo, las alertas sobre el uso elevado de CPU en tus nodos de GKE pueden indicar que existe una vulneración de criptominería.

Las alertas se deben generar en la ubicación en que se agregan los registros y las métricas. Por ejemplo, puedes usar el Registro de auditoría de GKE en combinación con las alertas basadas en registros en Cloud Logging.

Para obtener más información sobre las consultas relacionadas con la seguridad, consulta la documentación de registro de auditoría.

Responde a un incidente de seguridad

Una vez que recibas una alerta sobre un incidente, toma las medidas pertinentes. Si puedes, corrige la vulnerabilidad; si no conoces la causa raíz de la vulnerabilidad o no tienes una solución preparada, aplica medidas de mitigación.

Las mitigaciones que podrías tomar dependen de la gravedad del incidente y de tu certeza de que identificaste el problema.

En esta guía se abordan las acciones que puedes realizar después de detectar un incidente en una carga de trabajo que se ejecuta en GKE. En orden ascendente de gravedad, podrías hacer lo siguiente:

Estas mitigaciones se describen en las secciones siguientes.

Antes de comenzar

Los métodos utilizados en este tema usan la siguiente información:

  • El nombre de los pods que crees que fueron vulnerados o POD_NAME
  • El nombre de la VM del host que ejecuta el contenedor o los pods, o NODE_NAME

Además, antes de tomar cualquiera de estas medidas, considera si el atacante reaccionará negativamente si se da cuenta que lo descubriste. El atacante puede decidir borrar datos o destruir cargas de trabajo. Si el riesgo es demasiado alto, considera mitigaciones más drásticas, como borrar una carga de trabajo antes de realizar una investigación más exhaustiva.

Haz una instantánea del disco de la VM

Crear una instantánea del disco de la VM permite realizar una investigación forense después de que la carga de trabajo se vuelva a implementar o se borre. Las instantáneas se pueden crear mientras los discos están conectados a instancias en ejecución.

  1. Para crear una instantánea de tu disco persistente, primero busca los discos conectados a tu VM. Ejecuta el siguiente comando y observa el campo source:

    gcloud compute instances describe NODE_NAME --zone COMPUTE_ZONE \
        --format="flattened([disks])"
    
  2. Busca las líneas que contengan disks[NUMBER].source. La salida es similar a lo siguiente:

    disks[0].source: https://www.googleapis.com/compute/v1/projects/PROJECT_NAME/zones/COMPUTE_ZONE/disks/DISK_NAME
    

    El nombre del disco es la parte del nombre de la fuente después de la barra final. Por ejemplo, el nombre del disco es gke-cluster-pool-1-abcdeffff-zgt8.

  3. Para completar la instantánea, ejecuta el siguiente comando:

    gcloud compute disks snapshot DISK_NAME
    

Para obtener más información, consulta Crea instantáneas de disco persistente en la documentación de Compute Engine.

Inspecciona la VM mientras se ejecuta la carga de trabajo

También debes considerar qué tipo de acceso puede tener un atacante antes de tomar medidas. Si sospechas que se vulneró un contenedor y te preocupa informar al atacante, puedes conectarte al contenedor para inspeccionarlo. Las inspecciones son útiles para realizar una investigación rápida antes tomar medidas más disruptivas. La inspección también es el enfoque menos perjudicial para la carga de trabajo, pero no detiene el incidente.

Como alternativa, para evitar el acceso a una máquina con una credencial privilegiada, puedes analizar tus cargas de trabajo mediante la configuración de análisis forense en tiempo real (como GRR Rapid Response), agentes en nodo o filtros de red.

Reduce el acceso antes de inspeccionar la VM activa

Si acordonas, purgas y limitas el acceso de red a la VM que aloja un contenedor comprometido, puedes aislar parcialmente el contenedor comprometido del resto de tu clúster. Limitar el acceso a la VM reduce el riesgo, pero no evita que un atacante se desplace lateralmente en tu entorno si aprovecha una vulnerabilidad crítica.

Acordona el nodo y purga de él las otras cargas de trabajo

Acordonar y purgar un nodo traslada las cargas de trabajo ubicadas en el contenedor vulnerado a otras VM de tu clúster. Acordonar y purgar reduce la capacidad de un atacante de afectar otras cargas de trabajo en el mismo nodo, pero no necesariamente se evita que inspeccione el estado persistente de una carga de trabajo (por ejemplo, si inspecciona el contenido de la imagen del contenedor).

  1. Usa kubectl para acordonar el nodo y asegurarte de que no haya otros pods programados en él:

    kubectl cordon NODE_NAME
    

    Después de acordonar el nodo, púrgalo de otros pods.

  2. Etiqueta el Pod que estás poniendo en cuarentena:

    kubectl label pods POD_NAME quarantine=true
    

    Reemplaza POD_NAME por el nombre del Pod que deseas poner en cuarentena.

  3. Purga el nodo de los pods que no están etiquetados con quarantine:

    kubectl drain NODE_NAME --pod-selector='!quarantine'
    

Restringe el acceso de red al nodo

Recomendamos bloquear el acceso de tráfico interno y externo a la VM del host. A continuación, permite que las conexiones entrantes de una VM específica en tu red o VPC se conecten a la VM en cuarentena.

El primer paso es abandonar la VM del Grupo de instancias administrado que la posee. Abandonar la VM impide que el nodo se marque como en mal estado y se repare automáticamente (se vuelva a crear) antes de que se complete la investigación.

Para abandonar la VM, ejecuta el siguiente comando:

gcloud compute instance-groups managed abandon-instances INSTANCE_GROUP_NAME \
    --instances=NODE_NAME

Usa un firewall en la VM

Crear un firewall entre el contenedor afectado y otras cargas de trabajo en la misma red ayuda a evitar que un atacante se desplace a otras partes de tu entorno mientras realizas más análisis. Como ya purgaste la VM de otros contenedores, esto solo afecta al contenedor en cuarentena.

Las siguientes instrucciones sobre la creación de firewall de la VM evitan lo siguiente:

  • Nuevas conexiones de salida a otras VM en tu clúster con una regla de salida
  • Conexiones entrantes a la VM comprometida mediante una regla de entrada

A fin de proteger la VM de tus otras instancias, sigue estos pasos para el nodo que aloja el pod que deseas poner en cuarentena:

  1. Etiqueta la instancia a fin de poder aplicar una nueva regla de firewall.

    gcloud compute instances add-tags NODE_NAME \
        --zone COMPUTE_ZONE \
        --tags quarantine
    
  2. Crea una regla de firewall para denegar todo el tráfico de TCP de salida de las instancias con la etiqueta quarantine:

    gcloud compute firewall-rules create quarantine-egress-deny \
        --network NETWORK_NAME \
        --action deny \
        --direction egress \
        --rules tcp \
        --destination-ranges 0.0.0.0/0 \
        --priority 0 \
        --target-tags quarantine
    
  3. Crea una regla de firewall para denegar todo el tráfico de TCP de entrada a instancias con la etiqueta quarantine. Asigna a esta regla de entrada una priority de 1, que te permite anularla con otra regla que permita SSH desde una VM especificada.

    gcloud compute firewall-rules create quarantine-ingress-deny \
        --network NETWORK_NAME \
        --action deny \
        --direction ingress \
        --rules tcp \
        --source-ranges 0.0.0.0/0 \
        --priority 1 \
        --target-tags quarantine
    

Quita la dirección IP externa de la VM

Si quitas la dirección IP externa de la VM, se interrumpen todas las conexiones de red existentes fuera de tu VPC.

Para quitar la dirección externa de una VM, realiza los siguientes pasos.

  1. Busca y borra la configuración de acceso que asocia la IP externa con la VM. En primer lugar, busca la configuración de acceso mediante la descripción de la VM:

    gcloud compute instances describe NODE_NAME \
        --zone COMPUTE_ZONE --format="flattened([networkInterfaces])"
    

    Busca las líneas que contienen name y natIP. Son similares a las siguientes:

    networkInterfaces[0].accessConfigs[0].name:              ACCESS_CONFIG_NAME
    networkInterfaces[0].accessConfigs[0].natIP:             EXTERNAL_IP_ADDRESS
    
  2. Busca el valor de natIP que coincida con la IP externa que deseas quitar. Ten en cuenta el nombre de la configuración de acceso.

  3. Para quitar la IP externa, ejecuta el siguiente comando:

    gcloud compute instances delete-access-config NODE_NAME \
        --access-config-name "ACCESS_CONFIG_NAME"
    

Crea una conexión SSH a la VM del host mediante una VM intermedia

Después de quitar la IP externa de la VM del host, no puedes crear una conexión SSH fuera de tu VPC; debes acceder desde otra VM de la misma red. En el resto de esta sección, nos referiremos a esto como la VM intermedia.

Requisitos previos

  • Una VM intermedia con acceso a la subred de la VM del host; si aún no la tienes, crea una para este fin
  • La dirección IP interna de la VM intermedia
  • Una clave pública SSH de la VM intermedia. Para obtener más información, consulta Administra llaves SSH

Conéctate a la VM del host

  1. Agrega la clave pública de la VM intermedia a la VM del host. Para obtener más información, consulta cómo agregar y quitar llaves SSH en la documentación de Compute Engine.
  2. Agrega una etiqueta a la VM intermedia.

    gcloud compute instances add-tags INTERMEDIATE_NODE_NAME \
      --zone COMPUTE_ZONE \
      --tags intermediate
    
  3. Agrega una regla de permiso de entrada para anular la regla de denegación que agregaste antes. Para agregar la regla, ejecuta el siguiente comando:

    gcloud compute firewall-rules create quarantine-ingress-allow \
        --network NETWORK_NAME \
        --action allow \
        --direction ingress \
        --rules tcp:22 \
        --source-tags intermediate \
        --priority 0 \
        --target-tags quarantine
    

    Esta regla permite el tráfico entrante en el puerto 22 (SSH) de las VM de tu red con la etiqueta intermediate. Además, anula la regla de denegación con una priority de 0.

  4. Conéctate a la VM en cuarentena con su IP interna:

    ssh -i KEY_PATH USER@QUARANTINED_VM_INTERNAL_IP
    

    Reemplaza lo siguiente:

    • KEY_PATH: Es la ruta de acceso a la llave privada SSH.
    • USER: La dirección de correo electrónico de tu cuenta de Google Cloud
    • QUARANTINED_VM_INTERNAL_IP: Es la dirección IP interna.

Vuelve a implementar el contenedor

Cuando implementas de nuevo un contenedor, inicias una copia nueva de este y borras el contenedor afectado.

Para volver a implementar un contenedor, borra el pod que lo aloja. Si el pod es administrado por una construcción de Kubernetes de nivel superior (por ejemplo, una Implementación o DaemonSet), borrar el pod programa un pod nuevo. Este pod ejecuta contenedores nuevos.

Volver a realizar la implementación se recomienda en los siguientes casos:

  • Ya conoces la causa de la vulnerabilidad.
  • Crees que a un atacante le costaría mucho tiempo o esfuerzo volver a comprometer tu contenedor.
  • Crees que el contenedor podría volver a comprometerse con rapidez y no quieres que se desconecte, por lo que planeas colocarlo en una zona de pruebas para limitar el impacto.

Cuando vuelvas a implementar la carga de trabajo, si la posibilidad de otro compromiso es alta, considera colocar la carga de trabajo en un entorno de zona de pruebas, como GKE Sandbox. Las zonas de pruebas limitan el acceso al kernel del nodo host si el atacante vuelve a comprometer el contenedor.

Para volver a implementar un contenedor en Kubernetes, borra el pod que lo contiene.

kubectl delete pods POD_NAME --grace-period=10

Si los contenedores del pod borrado siguen ejecutándose, puedes borrar la carga de trabajo.

Para volver a implementar el contenedor dentro de una zona de pruebas, sigue las instrucciones en Endurece el aislamiento de la carga de trabajo con GKE Sandbox.

Borra una carga de trabajo

Si borras una carga de trabajo, como una Implementación o un DaemonSet, se borrarán todos sus pods miembros. Todos los contenedores dentro de esos pods dejarán de ejecutarse. Borrar una carga de trabajo puede recomendarse en los siguientes casos:

  • Deseas detener un ataque en curso.
  • Estás dispuesto a realizar la carga de trabajo sin conexión.
  • Detener el ataque de inmediato es más importante que el tiempo de actividad de la aplicación o el análisis forense.

Para borrar una carga de trabajo, usa kubectl delete CONTROLLER_TYPE. Por ejemplo, para borrar una Implementación, ejecuta el siguiente comando:

kubectl delete deployments DEPLOYMENT

Si cuando borras la carga de trabajo no se borran todos los pods o contenedores asociados, puedes borrar de forma manual los contenedores con la herramienta de CLI del entorno de ejecución del contenedor, normalmente docker. Si tus nodos ejecutan containerd, usa crictl.

Docker

Para detener el contenedor mediante el entorno de ejecución del contenedor de Docker, puedes usar docker stop o docker kill.

A fin de detener el contenedor, docker stop envía una señal SIGTERM al proceso raíz y espera 10 segundos para salir del proceso de forma predeterminada. Si el proceso no finaliza en ese período, se envía una señal SIGKILL. Puedes especificar este período de gracia con la opción --time.

docker stop --time TIME_IN_SECONDS CONTAINER

docker kill es el método más rápido para detener un contenedor. Envía la señal SIGKILL de inmediato.

docker kill CONTAINER

También puedes detener y quitar un contenedor en un comando con docker rm -f

docker rm -f CONTAINER

containerd

Si usas el entorno de ejecución de containerd en GKE, detienes o quitas contenedores con crictl.

Para detener un contenedor en containerd, ejecuta el siguiente comando:

crictl stop CONTAINER

Para quitar un contenedor en containerd, ejecuta el siguiente comando:

crictl rm -f CONTAINER

Borra la VM del host

Si no puedes borrar o quitar el contenedor, puedes borrar la máquina virtual que aloja el contenedor afectado.

Si el pod aún es visible, puedes encontrar el nombre de la VM del host con el siguiente comando:

kubectl get pods --all-namespaces \
  -o=custom-columns=POD_NAME:.metadata.name,INSTANCE_NAME:.spec.nodeName \
  --field-selector=metadata.name=POD_NAME

Para borrar la VM del host, ejecuta el siguiente comando de gcloud:

gcloud compute instance-groups managed delete-instances INSTANCE_GROUP_NAME \
    --instances=NODE_NAME

Abandonar la instancia del grupo de instancias administrado reduce el tamaño del grupo en una VM. Puedes volver a agregar una instancia de forma manual al grupo con el siguiente comando:

gcloud compute instance-groups managed resize INSTANCE_GROUP_NAME \
    --size=SIZE

¿Qué sigue?