Mitiga los 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 Registro de auditoría de GKE en combinación con alertas basadas en registros en Stackdriver Logging.

Si deseas obtener más información sobre cómo configurar alertas basadas en los registros de GKE, consulta Controles de seguridad y análisis forense para aplicaciones de GKE. Para ver ejemplos de 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 HOST_NODE

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.

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 [ZONE_NAME] --format="flattened([disks])"

Busca las líneas que contengan disks[NUMBER].source. A continuación, se muestra un resultado de ejemplo.

disks[0].source: https://www.googleapis.com/compute/v1/projects/[PROJECT_NAME]/zones/[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.

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. Si deseas obtener más información sobre las herramientas forenses sugeridas, consulta Controles de seguridad y análisis forense para aplicaciones de GKE.

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

    Donde POD_NAME es 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 lo 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 [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 us-central1-a --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 [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]

    Aquí KEY_PATH es la ruta a tu clave privada SSH y USER es la dirección de correo electrónico de tu cuenta de Google Cloud.

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.

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

kubectl delete pods [POD] --grace-period=10

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

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 cerrar un contenedor con el entorno de ejecución del contenedor de Docker, puedes usar docker stop o docker kill.

docker stop detiene el contenedor enviando 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 cerrar un contenedor. Envía la señal SIGKILL de inmediato.

docker kill [CONTAINER]

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

docker rm -f [CONTAINER]

containerd

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

Para cerrar 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]

Próximos pasos

Para obtener más información, consulta: