Skip to main content

Cómo proteger un pod de Kubernetes con Regula y Open Policy Agent

Escrito por

13 de octubre de 2021

0 minutos de lectura

Fugue lanzó recientemente la compatibilidad con Kubernetes en Regula, nuestro motor de políticas de código abierto para verificar infraestructura como código. Regula no solo puede revisar tus archivos de Terraform y CloudFormation en busca de incumplimientos de seguridad y conformidad, ¡ahora también puede revisar manifiestos YAML de Kubernetes!

En esta publicación del blog, mostraremos cómo ejecutar Regula en un manifiesto de Kubernetes para detectar un pod inseguro y luego protegerlo. Como beneficio adicional, la versión final del manifiesto cumplirá con CIS Kubernetes Benchmark v1.6.1, un conjunto de recomendaciones para proteger entornos de Kubernetes.

¿Listo? ¡Vamos!

Primeros pasos

Primero, instala Regula. Si usas Homebrew, puedes ejecutar los siguientes comandos:

brew tap fugue/regula
brew install regula

También puedes instalar un binario precompilado para tu plataforma o, si lo prefieres, ejecutar Regula con Docker.

Para escribir esta publicación, usamos Regula v1.5.0.

Luego, visita nuestro gist de GitHub y selecciona el botón Download ZIP; después, extrae los archivos. Son dos:

  • pod.yaml: un manifiesto de Kubernetes inseguro que no cumple con los requisitos

  • pod-compliant.yaml: una versión protegida del mismo manifiesto que sí cumple con los requisitos

A medida que expliquemos cómo corregir cada incumplimiento, puedes seguir los pasos y editar manualmente pod.yaml, o simplemente consultar la versión protegida pod-compliant.yaml.

Revisión del manifiesto

Nuestro manifiesto declara un pod sencillo llamado hello, con un único contenedor BusyBox, también llamado hello:

apiVersion: v1
kind: Pod
metadata:
  name: hello
spec:
  containers:
    - name: hello
      image: busybox
      command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']

No parece inseguro, ¿verdad? Pero ejecutemos Regula para asegurarnos.

Ejecución de Regula

En la terminal, cambia al directorio que contiene los archivos que descargaste. Ejecutaremos Regula en pod.yaml con la opción --format compact para ahorrar espacio:

regula run pod.yaml --format compact

Este es el resultado:

Salida de la terminal que muestra seis hallazgos de seguridad de severidad media en pods de Kubernetes, incluidos contenedores que se ejecutan como root, la capacidad NET_RAW y la falta de un contexto de seguridad.

¡Vaya! Definitivamente, nuestro pod no es tan seguro como podría ser. Regula encontró 6 problemas.

No te preocupes: ¡podemos corregirlos todos! Revisemos cada incumplimiento para resolverlo.

Corrección de los incumplimientos

Tokens de cuentas de servicio

El incumplimiento: “Service account ‘automountServiceAccountToken’ should be set to ‘false’ [Medium]”

Control de CIS Kubernetes v1.6.1: 5.1.6, “Ensure that Service Account Tokens are only mounted where necessary”

Por qué es importante: Los tokens de cuentas de servicio se usan para autenticar las solicitudes que los procesos dentro del clúster envían al servidor de la API de Kubernetes. De forma predeterminada, los tokens de cuentas de servicio se montan automáticamente en todos los pods. Sin embargo, si un atacante logra comprometer un solo pod, podría usar su token de cuenta de servicio para lanzar un ataque de escalamiento de privilegios y tomar el control de todo el clúster.

Por eso, si una carga de trabajo no necesita comunicarse con el servidor de la API, es mejor evitar el montaje automático de un token de cuenta de servicio. Esto concuerda con el principio de seguridad de privilegios mínimos.

Cómo corregirlo: En la especificación del pod, configura automountServiceAccountToken como false:

spec:
  automountServiceAccountToken: false

Consulta la línea 10 de pod-compliant.yaml.

Usuario root

El incumplimiento: “Pods should not run containers as the root user [Medium]”

Control de CIS Kubernetes v1.6.1: 5.2.6, “Minimize the admission of root containers”

Por qué es importante: Ejecutar como root cuando no es necesario casi siempre es una mala idea. Si un contenedor se ejecuta como root, un atacante puede obtener privilegios de root en el sistema host si logra escapar del contenedor.

Cómo corregirlo: En la especificación del pod, configura runAsUser con cualquier ID de usuario distinto de cero, ya que 0 corresponde a root:

spec:
  securityContext:
    runAsUser: 1001

Consulta las líneas 8-9 de pod-compliant.yaml.

Asegúrate de que el usuario especificado aquí esté definido en la imagen de Docker. A menudo, se crea un usuario que no es root ejecutando el comando useradd de Linux en el Dockerfile y, luego, se especifica el ID de usuario mediante el comando USER.

Capacidades de Linux

Los dos incumplimientos siguientes están estrechamente relacionados y, en nuestro ejemplo, se pueden resolver de la misma manera.

El incumplimiento: “Pods should not run containers with the NET_RAW capability [Medium]”

Control de CIS Kubernetes v1.6.1: 5.2.7, “Minimize the admission of containers with the NET_RAW capability”

El incumplimiento: “Pods should not run containers with default capabilities assigned [Medium]”

Control de CIS Kubernetes v1.6.1: 5.2.9, “Minimize the admission of containers with capabilities assigned”

Por qué es importante: Cuando se ejecuta un contenedor de Linux, se le asigna un conjunto predeterminado de capacidades que otorgan privilegios específicos de root a los procesos. La capacidad NET_RAW es especialmente peligrosa, porque un atacante puede usarla para espiar el tráfico de red o generar tráfico IP con direcciones falsificadas.

Muchos servicios no necesitan todas las capacidades predeterminadas, así que conviene eliminarlas primero y volver a agregar solo las necesarias. En este ejemplo no agregaremos ninguna, pero podrías hacerlo con add: ["FOO"].

Cómo corregirlo: Configura un securityContext para el contenedor y especifica capabilities con drop: ["ALL"] para corregir ambos incumplimientos a la vez (o drop: ["NET_RAW"] para corregir solo el 5.2.7, si lo prefieres):

spec:
  containers:
    - name: hello
      securityContext:
        capabilities:
          drop: ["ALL"]  

Consulta las líneas 15-17 de pod-compliant.yaml.

Perfil de seccomp

El incumplimiento: “Pod seccomp profile should be set to ‘docker/default’ [Medium]”

Control de CIS Kubernetes v1.6.1: 5.7.2, “Ensure that the seccomp profile is set to docker/default in your pod definitions”

Por qué es importante: En Linux, el modo de computación segura (seccomp) restringe las llamadas al sistema (syscalls) permitidas. Los entornos de ejecución de contenedores, como Docker, suelen proporcionar un perfil de seccomp predeterminado que deshabilita varias llamadas al sistema y mejora la seguridad.

Ten en cuenta que el perfil docker/default quedó obsoleto en Kubernetes 1.11; por eso, aunque CIS Kubernetes v1.6.1 indique lo contrario, es mejor usar runtime/default.

Cómo corregirlo: Hay varias formas de hacerlo, según tu versión de Kubernetes. En las versiones anteriores a la 1.19, puedes usar la anotación seccomp.security.alpha.kubernetes.io/pod en los metadatos del pod:

metadata:
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: "runtime/default"

Consulta las líneas 5-6 de pod-compliant.yaml.

Contexto de seguridad

El incumplimiento: “Pods and containers should apply a security context [Medium]”

Control de CIS Kubernetes v1.6.1: 5.7.3, “Apply Security Context to Your Pods and Containers”

Por qué es importante: Un contexto de seguridad para un pod o contenedor define varios parámetros de seguridad relacionados con el control de acceso, las capacidades de Linux y los privilegios. Conviene configurar los parámetros pertinentes para tu caso de uso específico.

Cómo corregirlo: Puedes configurar un contexto de seguridad en el nivel del pod o del contenedor. Si hay configuraciones definidas en ambos niveles y se superponen, las configuraciones del contenedor anulan las del pod.

Antes configuramos un securityContext en el nivel del pod para evitar que se ejecute como root y, en el nivel del contenedor, para eliminar todas las capacidades; así que ya corregimos este incumplimiento.

Consulta las líneas 8-9 y 15-17 de pod-compliant.yaml.

Volver a ejecutar Regula

Ahora que corregimos los 6 incumplimientos, veamos qué dice Regula sobre nuestro pod, que ahora es seguro. Este es el manifiesto actualizado, que te dejamos listo en pod-compliant.yaml:

apiVersion: v1
kind: Pod
metadata:
  name: hello
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: "runtime/default" 
spec:
  securityContext:
    runAsUser: 1001
  automountServiceAccountToken: false
  containers:
    - name: hello
      image: busybox
      command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      securityContext:
        capabilities:
          drop: ["ALL"]

Si estuviste editando pod.yaml durante el proceso, ejecuta el mismo comando que antes:

regula run pod.yaml --format compact

Si no estuviste editando pod.yaml (¡no te juzgamos!), simplemente ejecuta Regula en el manifiesto pod-compliant.yaml:

regula run pod-compliant.yaml --format compact

Este es el resultado:

No problems found. Nailed it.

¡Listo! Corregimos con éxito todos los problemas que Regula encontró en nuestro pod inseguro. ¡Buen trabajo!

¿Qué sigue?

Ahora que aprendiste a usar Regula para proteger un manifiesto de Kubernetes, consulta algunas prácticas recomendadas para la seguridad de Kubernetes.

Puedes obtener más información sobre Regula en regula.dev. Allí encontrarás una lista de todas nuestras reglas de Kubernetes. También puedes aprender a eximir un resultado de regla o incluso a deshabilitar una regla por completo si no es pertinente para tu organización.

Seguridad de IaC diseñada para desarrolladores

Snyk protege tu infraestructura como código desde el ciclo de vida del desarrollo de software hasta el runtime en la nube con un motor unificado de políticas como código, para que todos los equipos puedan desarrollar, implementar y operar de forma segura.