En este documento se describen las mitigaciones y respuestas habituales ante posibles incidentes de seguridad en tus clústeres y contenedores de Google Kubernetes Engine (GKE).
Este documento está dirigido a especialistas en seguridad que buscan orientación para responder a incidentes de seguridad de GKE. Para obtener más información sobre los roles habituales y las tareas de ejemplo a las que hacemos referencia en el contenido, consulta Roles y tareas habituales de los usuarios de GKE. Google Cloud
Las sugerencias de la sección Endurecer la seguridad del clúster pueden mejorar la seguridad de tus cargas de trabajo de GKE. Sin embargo, los incidentes de seguridad pueden producirse incluso cuando se han tomado medidas para proteger las cargas de trabajo.
Detectar incidentes
Para detectar posibles incidentes, te recomendamos que configures un proceso que recoja y monitorice los registros de tu carga de trabajo. A continuación, configura alertas basadas en eventos anómalos detectados en los registros. Las alertas avisan a tu equipo de seguridad cuando se detecta algo inusual. Tu equipo de seguridad podrá revisar el posible incidente.
Puedes personalizar las alertas en función de métricas o acciones específicas. Por ejemplo, si se activan alertas sobre el uso elevado de la CPU en tus nodos de GKE, puede que se hayan visto comprometidos para la criptominería.
Las alertas deben generarse en el lugar donde agregues los registros y las métricas. Por ejemplo, puedes usar el registro de auditoría de GKE junto con las alertas basadas en registros de Cloud Logging.
Para obtener más información sobre las consultas relevantes para la seguridad, consulta la documentación de Registro de auditoría.
Responder a un incidente de seguridad
Cuando se te haya alertado de un incidente, toma medidas. Corrige la vulnerabilidad si puedes. Si no conoce la causa principal de la vulnerabilidad o no tiene una solución preparada, aplique medidas de mitigación.
Las medidas que puedes tomar dependen de la gravedad del incidente y de la certeza de que has identificado el problema.
En esta guía se describen las acciones que puedes llevar a cabo después de detectar un incidente en una carga de trabajo que se ejecuta en GKE. Podrías hacer lo siguiente, en orden creciente de gravedad:
- Crea una instantánea del disco de la VM host. Una captura te permite realizar análisis forenses sobre el estado de la VM en el momento de la anomalía después de que se haya vuelto a implementar o se haya eliminado la carga de trabajo.
Inspecciona la VM mientras la carga de trabajo sigue ejecutándose. Conectarse a la VM host o al contenedor de carga de trabajo puede proporcionar información sobre las acciones del atacante. Te recomendamos que reduzcas el acceso antes de inspeccionar la VM activa.
Vuelve a implementar un contenedor. Al volver a desplegar, se finalizan los procesos que se están ejecutando en el contenedor afectado y se reinician.
Elimina una carga de trabajo. Si eliminas la carga de trabajo, se detendrán los procesos que se estén ejecutando en el contenedor afectado sin necesidad de reiniciarlo.
Estas medidas de mitigación se describen en las siguientes secciones.
Antes de empezar
Los métodos que se usan en este tema utilizan la siguiente información:
- El nombre de los Pods que crees que se han visto comprometidos o
POD_NAME
. - Nombre de la máquina virtual host que ejecuta el contenedor o los pods, o
NODE_NAME
.
Además, antes de tomar ninguna medida, plantéate si el atacante reaccionará de forma negativa si se descubre. El atacante puede decidir eliminar datos o destruir cargas de trabajo. Si el riesgo es demasiado alto, considera medidas de mitigación más drásticas, como eliminar una carga de trabajo antes de llevar a cabo una investigación más a fondo.
Crear una captura del disco de la VM
Crear una captura del disco de la VM permite llevar a cabo una investigación forense después de que se haya vuelto a implementar o se haya eliminado la carga de trabajo. Las capturas 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 consulta el campo
source
:gcloud compute instances describe NODE_NAME --zone COMPUTE_ZONE \ --format="flattened([disks])"
Busca las líneas que contengan
disks[NUMBER].source
. La salida es similar a la 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 origen que aparece después de la última barra. Por ejemplo, el nombre del disco es
gke-cluster-pool-1-abcdeffff-zgt8
.Para completar la creación de la instantánea, ejecuta el siguiente comando:
gcloud compute disks snapshot DISK_NAME
Para obtener más información, consulta el artículo Crear copias de seguridad de discos persistentes de la documentación de Compute Engine.
Inspeccionar la VM
Ten en cuenta el acceso que puede tener un atacante antes de tomar medidas. Si sospechas que se ha vulnerado un contenedor y te preocupa informar al atacante, puedes conectarte al contenedor e inspeccionarlo sin interrumpir tus cargas de trabajo. La inspección es útil para hacer investigaciones rápidas antes de tomar medidas más drásticas. La inspección también es el método menos intrusivo para la carga de trabajo, pero no detiene el incidente.
También puedes analizar tus cargas de trabajo sin tener que iniciar sesión en una máquina con una credencial privilegiada. Para ello, configura análisis forenses en tiempo real (como GRR Rapid Response), agentes en nodos o filtros de red.
Reducir el acceso antes de inspeccionar la VM activa
Si aislas, vacías y limitas el acceso a la red de la VM que aloja un contenedor vulnerado, puedes aislar parcialmente el contenedor vulnerado del resto del 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.
Acordonar el nodo y drenar las demás cargas de trabajo
Al acordonar y vaciar un nodo, las cargas de trabajo ubicadas en el mismo sitio que el contenedor vulnerado se trasladan a otras VMs de tu clúster. El acordonamiento y el drenaje reducen la capacidad de un atacante para influir en otras cargas de trabajo del mismo nodo. No impide necesariamente que inspeccionen el estado persistente de una carga de trabajo (por ejemplo, inspeccionando el contenido de la imagen de contenedor).
Usa
kubectl
para acordonar el nodo y asegúrate de que no se programen otros pods en él:kubectl cordon NODE_NAME
Después de acordonar el nodo, elimina los demás pods del nodo.
Etiqueta el pod que vas a poner en cuarentena:
kubectl label pods POD_NAME quarantine=true
Sustituye
POD_NAME
por el nombre del pod que quieras poner en cuarentena.Drena el nodo de los pods que no tengan la etiqueta
quarantine
:kubectl drain NODE_NAME --pod-selector='!quarantine'
Restringir el acceso de red al nodo
Recomendamos bloquear el acceso a la VM host tanto del tráfico interno como del externo. A continuación, permite que las conexiones entrantes de una VM específica de tu red o VPC se conecten a la VM en cuarentena.
El primer paso es abandonar la VM del grupo de instancias gestionadas al que pertenece. Si abandonas la VM, se evita que el nodo se marque como no operativo y se repare automáticamente (se vuelva a crear) antes de que completes la investigación.
Para abandonar la VM, ejecuta el siguiente comando:
gcloud compute instance-groups managed abandon-instances INSTANCE_GROUP_NAME \
--instances=NODE_NAME
Configurar el cortafuegos de la VM
Crear un cortafuegos entre el contenedor afectado y otras cargas de trabajo de 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 has vaciado la VM de otros contenedores, esto solo afecta al contenedor en cuarentena.
Las siguientes instrucciones sobre cómo proteger la VM con un firewall impiden lo siguiente:
- Nuevas conexiones salientes a otras VMs de tu clúster mediante una regla de salida.
- Conexiones entrantes a la VM vulnerada mediante una regla de entrada.
Para proteger la VM con un firewall de tus otras instancias, sigue estos pasos en el nodo que aloja el pod que quieres poner en cuarentena:
Etiqueta la instancia para poder aplicar una nueva regla de cortafuegos.
gcloud compute instances add-tags NODE_NAME \ --zone COMPUTE_ZONE \ --tags quarantine
Crea una regla de cortafuegos para denegar todo el tráfico 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
Crea una regla de cortafuegos para denegar todo el tráfico TCP de entrada a las instancias con la etiqueta
quarantine
. Asigna a esta regla de entrada elpriority
1
, lo que te permitirá anularla con otra regla que permita SSH desde una VM específica.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
Quitar la dirección IP externa de la VM
Si quitas la dirección IP externa de la VM, se interrumpirán las conexiones de red que haya fuera de tu VPC.
Para quitar la dirección externa de una VM, sigue estos pasos:
Busca y elimina la configuración de acceso que asocia la IP externa a la VM. Primero, busca la configuración de acceso describiendo la VM:
gcloud compute instances describe NODE_NAME \ --zone COMPUTE_ZONE --format="flattened([networkInterfaces])"
Busca las líneas que contengan
name
ynatIP
. Tienen este aspecto:networkInterfaces[0].accessConfigs[0].name: ACCESS_CONFIG_NAME networkInterfaces[0].accessConfigs[0].natIP: EXTERNAL_IP_ADDRESS
Busca el valor de
natIP
que coincida con la IP externa que quieras quitar. Anota el nombre de la configuración de acceso.Para quitar la IP externa, ejecuta el siguiente comando:
gcloud compute instances delete-access-config NODE_NAME \ --access-config-name "ACCESS_CONFIG_NAME"
Acceder a la VM host mediante SSH a través de una VM intermedia
Después de quitar la IP externa de la VM host, no podrás conectarte por SSH desde fuera de tu VPC. Accedes a ella desde otra VM de la misma red. En el resto de esta sección, nos referiremos a ella como VM intermedia.
Requisitos previos
- Una VM intermedia con acceso a la subred de la VM anfitriona. Si aún no tienes una, crea una máquina virtual para este fin.
- Dirección IP interna de la VM intermedia.
- Una clave pública SSH de la VM intermedia. Para obtener más información, consulta Gestionar claves SSH.
Conectarse a la VM host
- Añade la clave pública de la VM intermedia a la VM host. Para obtener más información, consulta el artículo Añadir y quitar claves SSH de la documentación de Compute Engine.
Añade una etiqueta a la VM intermedia.
gcloud compute instances add-tags INTERMEDIATE_NODE_NAME \ --zone COMPUTE_ZONE \ --tags intermediate
Añade una regla de permiso de entrada para anular la regla de denegación que has añadido anteriormente. Para añadir 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) desde las VMs de tu red que tengan la etiqueta
intermediate
. Anula la regla de denegación con unpriority
de0
.Conéctate a la VM en cuarentena mediante su IP interna:
ssh -i KEY_PATH USER@QUARANTINED_VM_INTERNAL_IP
Haz los cambios siguientes:
KEY_PATH
: la ruta a tu clave privada SSH.USER
: la dirección de correo de tu cuenta de Google Cloud .QUARANTINED_VM_INTERNAL_IP
: la dirección IP interna.
Volver a implementar un contenedor
Al volver a desplegar el contenedor, se inicia una copia nueva del contenedor y se elimina el contenedor vulnerado.
Para volver a implementar un contenedor, elimina el pod que lo aloja. Si el pod está gestionado por una estructura de Kubernetes de nivel superior (por ejemplo, un Deployment o un DaemonSet), al eliminar el pod se programa un nuevo pod. Este pod ejecuta contenedores nuevos.
Volver a implementar tiene sentido cuando:
- Ya conoces la causa de la vulnerabilidad.
- Crees que un atacante necesita mucho tiempo o esfuerzo para volver a vulnerar tu contenedor.
- Crees que el contenedor podría volver a verse comprometido rápidamente y no quieres desconectarlo, así que tienes previsto colocarlo en un sandbox para limitar el impacto.
Cuando vuelvas a implementar la carga de trabajo, si hay muchas probabilidades de que se produzca otra vulneración, considera la posibilidad de colocarla en un entorno aislado, como GKE Sandbox. El aislamiento en un entorno de pruebas limita el acceso al kernel del nodo host si el atacante vuelve a poner en peligro el contenedor.
Para volver a implementar un contenedor en Kubernetes, elimina el pod que lo contiene:
kubectl delete pods POD_NAME --grace-period=10
Si los contenedores del pod eliminado siguen ejecutándose, puedes eliminar la carga de trabajo.
Para volver a implementar el contenedor en un sandbox, sigue las instrucciones de Endurecer el aislamiento de cargas de trabajo con GKE Sandbox.
Eliminar una carga de trabajo
Si eliminas una carga de trabajo, como un Deployment o un DaemonSet, se eliminarán todos sus Pods miembros. Todos los contenedores de esos pods dejan de ejecutarse. Eliminar una carga de trabajo puede ser útil en los siguientes casos:
- Quieres detener un ataque en curso.
- Estás dispuesto a trabajar sin conexión.
- Detener el ataque inmediatamente es más importante que el tiempo de actividad de la aplicación o el análisis forense.
Para eliminar una carga de trabajo, usa kubectl delete CONTROLLER_TYPE
.
Por ejemplo, para eliminar un Deployment, ejecuta el siguiente comando:
kubectl delete deployments DEPLOYMENT
Si al eliminar la carga de trabajo no se eliminan todos los pods o contenedores asociados, puedes eliminar los contenedores manualmente con la herramienta de CLI de los tiempos de ejecución de contenedores, normalmente docker
. Si tus nodos ejecutan containerd, usa crictl
.
Docker
Para detener un contenedor que usa el entorno de ejecución de contenedores 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 a que el proceso finalice de forma predeterminada. Si el proceso no se ha cerrado en ese periodo, envía una señal SIGKILL
.
Puedes especificar este periodo 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
inmediatamente.
docker kill CONTAINER
También puedes detener y eliminar un contenedor con un solo comando docker rm -f
:
docker rm -f CONTAINER
containerd
Si usas el tiempo de ejecución containerd
en GKE, puedes detener o quitar 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
Eliminar la VM host
Si no puedes eliminar el contenedor, puedes eliminar la máquina virtual que lo aloja.
Si el pod sigue visible, puedes encontrar el nombre de la VM 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 eliminar la VM host, ejecuta el siguiente comando gcloud
:
gcloud compute instance-groups managed delete-instances INSTANCE_GROUP_NAME \
--instances=NODE_NAME
Si abandonas la instancia del grupo de instancias gestionado, el tamaño del grupo se reducirá en una VM. Puedes volver a añadir manualmente una instancia al grupo con el siguiente comando:
gcloud compute instance-groups managed resize INSTANCE_GROUP_NAME \
--size=SIZE
Siguientes pasos
- Realizar análisis forenses en contenedores
- Endurecer la seguridad del clúster
- Análisis forense de aplicaciones de GKE