Compartir a través de


Protección del acceso de contenedores a los recursos para cargas de trabajo de Azure Kubernetes Service (AKS) mediante características de seguridad integradas de Linux

En este artículo, aprenderá a proteger el acceso de contenedores a los recursos de las cargas de trabajo de Azure Kubernetes Service (AKS) mediante los espacios de nombres de usuario, AppArmor y las características de seguridad integradas de Linux.

Información general sobre la seguridad del acceso al contenedor

Por el mismo motivo que debería conceder a los usuarios o a los grupos el menor número de privilegios necesarios, también debería limitar los contenedores a solo las acciones y procesos necesarios. Para minimizar el riesgo de ataques, evite configurar las aplicaciones y los contenedores que requieren elevación de privilegios o acceso a raíz.

Puede usar contextos de seguridad de pod de Kubernetes integrados para definir más permisos, como el usuario o grupo para ejecutarse como, las funcionalidades de Linux que se van a exponer o establecer allowPrivilegeEscalation: false en el manifiesto de pod. Para más recomendaciones, consulte Protección del acceso del pod a los recursos.

Para mejorar el aislamiento del host y reducir el movimiento lateral en Linux, puede usar espacios de nombres de usuario. Para un control aún más detallado de las acciones de los contenedores, puede usar las características de seguridad incorporadas de Linux como AppArmor y seccomp. Estas características le ayudan a limitar las acciones que los contenedores pueden realizar mediante la definición de características de seguridad de Linux en el nivel de nodo y su implementación a través de un manifiesto de pod.

Las características de seguridad integradas de Linux solo están disponibles en los pods y los nodos de Linux.

Nota:

Actualmente, los entornos de Kubernetes no están completamente seguros ante el uso de varios inquilinos hostiles. Otras características de seguridad, como Microsoft Defender para contenedores, AppArmor, seccomp, espacios de nombres de usuario, Pod Security Admission o Control de acceso basado en roles de Kubernetes (RBAC) para nodos, bloquean eficazmente los exploits.

Para una verdadera seguridad al ejecutar cargas de trabajo multiinquilino hostiles, solo debe confiar en un hipervisor. El dominio de seguridad de Kubernetes se convierte en todo el clúster, no en un nodo específico.

En el caso de estos tipos de cargas de trabajo multiinquilino hostiles, debe usar clústeres que estén físicamente aislados.

Requisitos previos para espacios de nombres de usuario

Limitaciones de los espacios de nombres de usuario

Información general sobre los espacios de nombres de usuario

Los pods de Linux se ejecutan con varios espacios de nombres de forma predeterminada: espacios de nombres de red para aislar la identidad de red y un espacio de nombres PID para aislar los procesos. Un espacio de nombres de usuario (user_namespace) aísla a los usuarios dentro del contenedor de los usuarios del host. También limita el ámbito de las funcionalidades y las interacciones del pod con el resto del sistema.

Los uid y los gid dentro del contenedor se asignan a usuarios sin privilegios en el host, por lo que toda la interacción con el resto del host se produce como esos uid y gid sin privilegios. Por ejemplo, la raíz dentro del contenedor (UID 0) se puede asignar al usuario 65536 en el host. Kubernetes crea la asignación para garantizar que no se superpone con otros pods mediante espacios de nombres de usuario en el sistema.

La implementación de Kubernetes tiene algunas ventajas clave. Para obtener más información, consulte la documentación de Espacios de Nombres de Usuario de Kubernetes.

Habilitar espacios de nombres de usuario

  1. Cree un archivo denominado mypod.yaml y cópielo en el siguiente código manifiesto. Para usar espacios de nombres de usuario, YAML debe tener el campo hostUsers: false.

    apiVersion: v1
    kind: Pod
    metadata:
      name: userns
    spec:
      hostUsers: false
      containers:
      - name: shell
        command: ["sleep", "infinity"]
        image: debian
    
  2. Implemente la aplicación mediante el comando kubectl apply y especifique el nombre del manifiesto de YAML.

    kubectl apply -f mypod.yaml
    
  3. Compruebe el estado de los pods implementados con el comando kubectl get pods.

    kubectl get pods
    
  4. Ejecute en el pod usando el comando kubectl exec.

    kubectl exec -ti userns -- bash
    
  5. Dentro del pod, compruebe /proc/self/uid_map con el comando siguiente:

    cat /proc/self/uid_map
    

    La salida debe tener 65536 en la última columna. Por ejemplo:

    0  833617920      65536
    

    Esta salida indica que la raíz dentro del contenedor (UID 0) se asigna al usuario 65536 en el host.

Vulnerabilidades y exposiciones comunes (CVEs) mitigadas por espacios de nombres de usuario

En la tabla siguiente se describen algunas vulnerabilidades y exposiciones comunes (ECV) que se mitigan parcialmente o totalmente mediante user_namespaces:

CVE Puntuación de gravedad Nivel de gravedad
CVE-2019-5736 8.6 High
CVE 2024-21262 8.6 High
CVE 2022-0492 7,8 High
CVE-2021-25741 8.1 / 8.8 Alto/Alto
CVE-2017-1002101 9.6 / 8.8 Crítico/Alto

Tenga en cuenta que esta lista no es exhaustiva. Para más información, consulte Kubernetes v1.33: Espacios de nombres de usuario habilitados de forma predeterminada.

Requisitos previos de AppArmor

Nota:

Azure Linux 3.0 admite AppArmor a partir del lanzamiento de VHD del 7 de noviembre de 2025.

Introducción a AppArmor

Para limitar las acciones de los contenedores, puede usar el módulo de seguridad del kernel de Linux denominado AppArmor. AppArmor está disponible como parte del sistema operativo (SO) del nodo de AKS subyacente y está habilitado de forma predeterminada. Puede crear perfiles de AppArmor que restrinjan las acciones de lectura, escritura o ejecución, o funciones del sistema como el montaje de sistemas de archivos. Los perfiles de AppArmor predeterminados restringen el acceso a diferentes ubicaciones de /proc y /sys, y proporcionan un medio para aislar lógicamente los contenedores desde el nodo subyacente. AppArmor funciona para cualquier aplicación que se ejecuta en Linux, no solo para los pods de Kubernetes.

Nota:

Antes de Kubernetes v1.30, AppArmor se especificó mediante anotaciones. A partir de la versión 1.30, AppArmor se especifica a través del campo securityContext de la especificación del pod. Para más información, consulte la documentación de AppArmor de Kubernetes.

Perfiles de AppArmor en uso en un clúster AKS para limitar las acciones del contenedor

Asegurar los pods con AppArmor

Puede especificar perfiles de AppArmor en el nivel de pod o contenedor. El perfil de AppArmor del contenedor tiene prioridad sobre el perfil de AppArmor del pod. Si no se especifica ninguno, el contenedor se ejecuta sin restricciones. Para más información sobre los perfiles de AppArmor, consulte la documentación de Kubernetes sobre la protección de un pod con AppArmor.

Configuración de un perfil personalizado de AppArmor

En el ejemplo siguiente se crea un perfil que impide la escritura en archivos desde un contenedor.

  1. Acceda mediante SSH a un nodo de AKS.

  2. Cree un archivo denominado deny-write.profile y pegue el siguiente contenido:

    #include <tunables/global>
    
    profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
      #include <abstractions/base>
    
      file,
    
      # Deny all file writes.
      deny /** w,
    }
    
  3. Cargue el perfil de AppArmor en el nodo.

    # This example assumes that node names match host names, and are reachable via SSH.
    NODES=($( kubectl get node -o jsonpath='{.items[*].status.addresses[?(.type == "Hostname")].address}' ))
    
    for NODE in ${NODES[*]}; do ssh $NODE 'sudo apparmor_parser -q <<EOF
    #include <tunables/global>
    
    profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
      #include <abstractions/base>
    
      file,
    
      # Deny all file writes.
      deny /** w,
    }
    EOF'
    done
    

Despliega un pod con el perfil personalizado de AppArmor

  1. Implemente un pod "Hello AppArmor" con el perfil de denegación de escritura.

    apiVersion: v1
    kind: Pod
    metadata:
      name: hello-apparmor
    spec:
      securityContext:
        appArmorProfile:
          type: Localhost
          localhostProfile: k8s-apparmor-example-deny-write
      containers:
      - name: hello
        image: busybox:1.28
        command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
    
  2. Aplique el manifiesto del pod mediante el comando kubectl apply.

    kubectl apply -f hello-apparmor.yaml
    
  3. Ejecute el comando exec en el pod y compruebe que el contenedor se está ejecutando con el perfil de AppArmor.

    kubectl exec hello-apparmor -- cat /proc/1/attr/current
    

    La salida debe mostrar el perfil de AppArmor en uso. Por ejemplo:

    k8s-apparmor-example-deny-write (enforce)
    

Requisitos previos de Seccomp

Registro de la marca de característica KubeletDefaultSeccompProfilePreview

Importante

Las características en versión preliminar de AKS están disponibles como opción de participación y autoservicio. Las versiones preliminares se proporcionan "tal cual" y "como están disponibles", y están excluidas de los Acuerdos de nivel de servicio y la garantía limitada. Las versiones preliminares de AKS reciben cobertura parcial del soporte al cliente en la medida de lo posible. Por lo tanto, estas características no están diseñadas para su uso en producción. Para más información, consulte los siguientes artículos de soporte:

  1. Registre la marca de características de KubeletDefaultSeccompProfilePreview mediante el comando az feature register.

    az feature register --namespace "Microsoft.ContainerService" --name "KubeletDefaultSeccompProfilePreview"
    

    Tarda unos minutos en que el estado muestre Registrado.

  2. Comprobar el estado del registro mediante el comando az feature show.

    az feature show --namespace "Microsoft.ContainerService" --name "KubeletDefaultSeccompProfilePreview"
    
  3. Cuando aparezca el estado Registrado, actualice el registro del proveedor de recursos Microsoft.ContainerService mediante el comando az provider register.

    az provider register --namespace Microsoft.ContainerService
    

Limitaciones de Seccomp

  • AKS solo admite los perfiles de seccomp predeterminados (RuntimeDefault y Unconfined). No se admiten perfiles de seccomp personalizados.
  • SeccompDefault no es un parámetro admitido para los grupos de nodos de Windows.

Introducción a los perfiles de seccomp predeterminados (versión preliminar)

Aunque AppArmor funciona para cualquier aplicación Linux, seccomp (o informática segura) funciona en el nivel de proceso. Seccomp también es un módulo de seguridad de kernel de Linux. El containerd tiempo de ejecución usado por los nodos de AKS proporciona compatibilidad nativa con seccomp. Con seccomp, puede limitar las llamadas del sistema de un contenedor. Seccomp establece una capa adicional de protección contra vulnerabilidades comunes de llamadas del sistema explotadas por actores malintencionados y permite especificar un perfil predeterminado para todas las cargas de trabajo del nodo.

Puede aplicar perfiles de seccomp predeterminados mediante configuraciones de nodo personalizadas al crear un nuevo grupo de nodos de Linux. AKS admite los RuntimeDefault valores y Unconfined . Algunas cargas de trabajo pueden requerir un número menor de restricciones de syscall que otras. Esto significa que pueden producir errores durante el tiempo de ejecución con el perfil RuntimeDefault. Para mitigar este error, puede especificar el perfil Unconfined. Si la carga de trabajo requiere un perfil personalizado, consulte Configuración de un perfil de seccomp personalizado.

Restringir las llamadas al sistema de contenedores con seccomp

  1. Siga los pasos para aplicar un perfil de seccomp en la configuración de kubelet especificando "seccompDefault": "RuntimeDefault".
  2. Conéctese al host.
  3. Compruebe que la configuración se aplicó a los nodos.

Resolución de errores de carga de trabajo con seccomp

Cuando SeccompDefault está habilitado, el perfil de seccomp predeterminado del entorno de ejecución del contenedor se usa de forma predeterminada para todas las cargas de trabajo programadas en el nodo, lo que podría provocar un error en las cargas de trabajo debido a llamadas de syscall bloqueadas. Si se produce un error de carga de trabajo, es posible que vea errores como:

  • La tarea se cierra inesperadamente después de activar la función, con el error "permiso denegado".
  • Los mensajes de error de Seccomp también se pueden ver en auditado o syslog reemplazando SCMP_ACT_ERRNO por SCMP_ACT_LOG en el perfil predeterminado.

Si experimenta estos errores, se recomienda cambiar el perfil de seccomp a Unconfined. Unconfined no aplica restricciones a las llamadas sys, lo que permite ejecutar todas las llamadas del sistema.

Resumen de perfiles de seccomp personalizados

Con un perfil de seccomp personalizado, tiene un control más pormenorizado sobre las llamadas al sistema restringidas para los contenedores. Puede crear sus propios perfiles de seccomp mediante:

  • Usar filtros para especificar qué acciones se van a permitir o denegar.
  • La anotación dentro de un manifiesto YAML de pod para asociarlo al filtro de seccomp.

Nota:

Para obtener ayuda con la solución de problemas del perfil de seccomp, consulte Solución de problemas de configuración de perfiles de seccomp en Azure Kubernetes Service (AKS).

Configuración de un perfil de seccomp personalizado

Para ver seccomp en acción, cree un filtro que evite el cambio de permisos en un archivo.

  1. Acceda mediante SSH a un nodo de AKS.

  2. Cree un filtro de seccomp denominado /var/lib/kubelet/seccomp/prevent-chmod.

  3. Copie y pegue el siguiente contenido:

    {
      "defaultAction": "SCMP_ACT_ALLOW",
      "syscalls": [
        {
          "name": "chmod",
          "action": "SCMP_ACT_ERRNO"
        },
        {
          "name": "fchmodat",
          "action": "SCMP_ACT_ERRNO"
        },
        {
          "name": "chmodat",
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    }
    

    En la versión 1.19 y versiones posteriores, debe configurar:

    {
      "defaultAction": "SCMP_ACT_ALLOW",
      "syscalls": [
        {
          "names": ["chmod","fchmodat","chmodat"],
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    }
    
  4. En la máquina local, cree un manifiesto de pod denominado aks-seccomp.yaml y pegue el contenido siguiente. Este manifiesto define una anotación para seccomp.security.alpha.kubernetes.io y hace referencia al filtro prevent-chmod existente.

    apiVersion: v1
    kind: Pod
    metadata:
      name: chmod-prevented
      annotations:
        seccomp.security.alpha.kubernetes.io/pod: localhost/prevent-chmod
    spec:
      containers:
      - name: chmod
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command:
          - "chmod"
        args:
         - "777"
         - /etc/hostname
      restartPolicy: Never
    

    En la versión 1.19 y versiones posteriores, debe configurar:

    apiVersion: v1
    kind: Pod
    metadata:
      name: chmod-prevented
    spec:
      securityContext:
        seccompProfile:
          type: Localhost
          localhostProfile: prevent-chmod
      containers:
      - name: chmod
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command:
          - "chmod"
        args:
         - "777"
         - /etc/hostname
      restartPolicy: Never
    
  5. Implemente el pod de ejemplo mediante el kubectl apply comando :

    kubectl apply -f ./aks-seccomp.yaml
    
  6. Vea el estado del pod mediante el kubectl get pods comando .

    kubectl get pods
    

    En la salida, debería ver que el pod notifica un error. El filtro seccomp impide que se ejecute el comando chmod, tal como se muestra en la salida del ejemplo:

    NAME                      READY     STATUS    RESTARTS   AGE
    chmod-prevented           0/1       Error     0          7s
    

Opciones de perfil de seguridad de Seccomp

Los perfiles de seguridad de Seccomp son un conjunto de llamadas syscall definidas permitidas o restringidas. La mayoría de los entornos de ejecución de contenedor tienen un perfil de seccomp predeterminado similar si no es el mismo que el que usa Docker. Para obtener más información sobre los perfiles disponibles, consulte los perfiles de seccomp predeterminados de Docker o contenedor .

AKS usa el perfil de seccomp predeterminado containerd para RuntimeDefault cuando configuras seccomp mediante la configuración de nodo personalizada.

Llamadas de syscall significativas bloqueadas por perfil predeterminado

Tanto Docker como containerd mantienen listas de permitidos de llamadas seguras al sistema. Cuando se realizan cambios en Docker y containerd, AKS actualiza la configuración predeterminada para que esté alineada. Las actualizaciones de esta lista pueden provocar un error en la carga de trabajo. Para obtener actualizaciones de versión, consulte las notas de la versión de AKS.

En la tabla siguiente se enumeran las llamadas al sistema importantes que están bloqueadas porque no están en la lista de permitidos. Esta lista no es exhaustiva. Si la carga de trabajo requiere alguna de las syscalls bloqueadas, no use el perfil de seccomp RuntimeDefault.

Llamada syscall bloqueada Descripción
acct Syscall de contabilidad, que podría permitir a los contenedores deshabilitar sus propios límites de recursos o la contabilidad de procesos. También está cerrado por CAP_SYS_PACCT.
add_key Impedir que los contenedores usen el keyring de kernel, que no tiene espacio de nombres.
bpf Deniegue la carga de programas bpf potencialmente persistentes en kernel, que ya está controlada por CAP_SYS_ADMIN.
clock_adjtime La hora y la fecha no tienen espacio de nombres. También está cerrado por CAP_SYS_TIME.
clock_settime La hora y la fecha no tienen espacio de nombres. También está cerrado por CAP_SYS_TIME.
clone Denegar la clonación de nuevos espacios de nombres. También se ha cerrado por marcas CAP_SYS_ADMIN for CLONE_*, excepto CLONE_NEWUSER.
create_module Denegar la manipulación y las funciones en los módulos de kernel. Obsoleto. También está cerrado por CAP_SYS_MODULE.
delete_module Denegar la manipulación y las funciones en los módulos de kernel. También está cerrado por CAP_SYS_MODULE.
finit_module Denegar la manipulación y las funciones en los módulos de kernel. También está cerrado por CAP_SYS_MODULE.
get_kernel_syms Denegar la recuperación de símbolos de módulo y kernel exportados. Obsoleto.
get_mempolicy Syscall que modifica la memoria del kernel y la configuración de NUMA. Ya está cerrado por CAP_SYS_NICE.
init_module Denegar la manipulación y las funciones en los módulos de kernel. También está cerrado por CAP_SYS_MODULE.
ioperm Impedir que los contenedores modifiquen los niveles de privilegios de E/S del kernel. Ya está cerrado por CAP_SYS_RAWIO.
iopl Impedir que los contenedores modifiquen los niveles de privilegios de E/S del kernel. Ya está cerrado por CAP_SYS_RAWIO.
kcmp Restrinja las funcionalidades de inspección de procesos, ya bloqueadas quitando CAP_SYS_PTRACE.
kexec_file_load Syscall hermana de kexec_load que hace lo mismo, argumentos ligeramente diferentes. También está cerrado por CAP_SYS_BOOT.
kexec_load Denegar la carga de un nuevo kernel para su ejecución posterior. También está cerrado por CAP_SYS_BOOT.
keyctl Impedir que los contenedores usen el keyring de kernel, que no tiene espacio de nombres.
lookup_dcookie Seguimiento o generación de perfiles de syscall, que podría filtrar información sobre el host. También está cerrado por CAP_SYS_ADMIN.
mbind Syscall que modifica la memoria del kernel y la configuración de NUMA. Ya está cerrado por CAP_SYS_NICE.
mount Deniegue el montaje, ya cerrado por CAP_SYS_ADMIN.
move_pages Syscall que modifica la memoria del kernel y la configuración de NUMA.
nfsservctl Denegar la interacción con el demonio nfs del kernel. Obsoleto desde Linux 3.1.
open_by_handle_at Causa de un error de contenedor antiguo. También está cerrado por CAP_DAC_READ_SEARCH.
perf_event_open Seguimiento o generación de perfiles de syscall, que podría filtrar información sobre el host.
personality Impedir que el contenedor habilite la emulación de BSD. No es intrínsecamente peligroso, pero poco probado, potencial para las vulnerabilidades de kernel.
pivot_root Denegar pivot_root, debe ser una operación con privilegios.
process_vm_readv Restrinja las funcionalidades de inspección de procesos, ya bloqueadas quitando CAP_SYS_PTRACE.
process_vm_writev Restrinja las funcionalidades de inspección de procesos, ya bloqueadas quitando CAP_SYS_PTRACE.
ptrace Llamada syscall de seguimiento y generación de perfiles. Bloqueado en las versiones del kernel de Linux anteriores a la versión 4.8 para evitar la omisión de seccomp. Los procesos arbitrarios de seguimiento o generación de perfiles ya se bloquean al eliminar CAP_SYS_PTRACE, ya que podría filtrar información en el host.
query_module Denegar la manipulación y las funciones en los módulos de kernel. Obsoleto.
quotactl Syscall de cuota, que podría permitir a los contenedores deshabilitar sus propios límites de recursos o la contabilidad de procesos. También está cerrado por CAP_SYS_ADMIN.
reboot No permita que los contenedores reinicien el host. También está cerrado por CAP_SYS_BOOT.
request_key Impedir que los contenedores usen el keyring de kernel, que no tiene espacio de nombres.
set_mempolicy Syscall que modifica la memoria del kernel y la configuración de NUMA. Ya está cerrado por CAP_SYS_NICE.
setns Denegar la asociación de un subproceso con un espacio de nombres. También está cerrado por CAP_SYS_ADMIN.
settimeofday La hora y la fecha no tienen espacio de nombres. También está cerrado por CAP_SYS_TIME.
stime La hora y la fecha no tienen espacio de nombres. También está cerrado por CAP_SYS_TIME.
swapon Denegar el inicio o detención del intercambio a archivo o dispositivo. También está cerrado por CAP_SYS_ADMIN.
swapoff Denegar el inicio o detención del intercambio a archivo o dispositivo. También está cerrado por CAP_SYS_ADMIN.
sysfs Syscall obsoleta.
_sysctl Obsoleto, reemplazado por /proc/sys.
umount Debe ser una operación con privilegios. También está cerrado por CAP_SYS_ADMIN.
umount2 Debe ser una operación con privilegios. También está cerrado por CAP_SYS_ADMIN.
unshare Denegar la clonación de nuevos espacios de nombres para procesos. También está controlado por CAP_SYS_ADMIN (excepto unshare --user).
uselib La llamada de syscall anterior relacionada con las bibliotecas compartidas, sin usar durante mucho tiempo.
userfaultfd Control de errores de página de espacio de usuarios, en gran medida necesario para la migración de procesos.
ustat Syscall obsoleta.
vm86 En la máquina virtual en modo real de kernel x86. También está cerrado por CAP_SYS_ADMIN.
vm86old En la máquina virtual en modo real de kernel x86. También está cerrado por CAP_SYS_ADMIN.

Para más información sobre cómo proteger el clúster de AKS, consulte los artículos siguientes: