Protege contenedores con AppArmor

AppArmor es un módulo de seguridad del kernel de Linux que puedes utilizar para restringir las capacidades de los procesos que se ejecutan en el sistema operativo host. Cada proceso puede tener su propio perfil de seguridad. El perfil de seguridad permite o no permite capacidades específicas como, por ejemplo, acceso a la red o permisos de ejecución/escritura/lectura de archivos.

Puedes utilizar AppArmor con los contenedores de Docker que se ejecutan en las instancias de Container-Optimized OS. Para cualquier contenedor determinado, puedes aplicar el perfil de seguridad predeterminado de AppArmor que viene con Docker, o un perfil de seguridad personalizado que proporciones.

Cómo usar el perfil de seguridad predeterminado de AppArmor de Docker

Cuando inicias un contenedor en la instancia de Container-Optimized OS, el sistema aplica de forma automática el perfil de seguridad docker-default de AppArmor. En el siguiente comando de ejemplo, se ejecuta un contenedor con el perfil de seguridad docker-default:

docker run --rm -it debian:jessie bash -i

Para probar el perfil de seguridad docker-default, puedes intentar leer el archivo /proc/sysrq-trigger con el comando cat de la siguiente manera:

root@88cef496c1a5:/# cat /proc/sysrq-trigger

El resultado debería contener un error "Permiso denegado" similar al que figura a continuación:

cat: /proc/sysrq-trigger: Permission denied

Cómo aplicar un perfil de seguridad personalizado

Para aplicar un perfil de seguridad diferente, usa la opción de línea de comandos apparmor=<profile-name> cuando ejecutes tu contenedor. En el siguiente comando de ejemplo, se ejecuta un contenedor con un perfil de seguridad llamado no-ping:

docker run --rm -i --security-opt apparmor=no-ping debian:jessie bash -i

Consulta Crea un perfil de seguridad personalizado más adelante a fin de obtener más información para crear el perfil no-ping especificado en el ejemplo.

También puedes especificar unconfined con la opción apparmor para indicar que el contenedor se ejecutará sin ningún perfil de seguridad, como en el siguiente ejemplo:

docker run --rm -it --security-opt apparmor=unconfined debian:jessie bash -i

Cómo visualizar los perfiles de seguridad activos de AppArmor

Puedes ver qué perfil de AppArmor se aplica a los procesos en tu instancia de Container-Optimized OS si inspeccionas el archivo /proc/<pid>/attr/current, en el que <pid> es el ID del proceso.

Supongamos que tienes los siguientes procesos en ejecución en tu instancia (que se muestran con el comando ps -ef | grep '[b]ash -i'):

root      1903  1897  0 21:58 pts/3    00:00:00 docker run --rm -it debian:jessie bash -i
root      1927  1913  0 21:58 pts/4    00:00:00 bash -i
root      1978  1001  0 22:01 pts/0    00:00:00 docker run --rm -it --security-opt apparmor=unconfined debian:jessie bash -i
root      2001  1988  0 22:01 pts/2    00:00:00 bash -i

Si inspeccionas /proc/1927/attr/current, deberías ver el siguiente resultado, que indica que el proceso (pid 1927) se ejecutó con el perfil de seguridad predeterminado de Docker:

# cat /proc/1927/attr/current
docker-default (enforce)

Si inspeccionas /proc/2001/attr/current, deberías ver el siguiente resultado, que indica que el proceso (pid 2001) se ejecutó sin ningún perfil de seguridad (es decir, con la opción apparmor=unconfined):

# cat /proc/2001/attr/current
unconfined

Cómo crear un perfil de seguridad personalizado

Si el proceso requiere un perfil de seguridad que diferente de docker-default, puedes escribir tu propio perfil personalizado. Para utilizar un perfil personalizado, debes crear el archivo de perfil y, a continuación, cargar el archivo en AppArmor.

Por ejemplo, supongamos que deseas un perfil de seguridad que rechace todo el tráfico de red sin procesar. La siguiente secuencia de comandos crea un archivo para un perfil de seguridad llamado no-ping en /etc/apparmor.d/no_raw_net:

cat > /etc/apparmor.d/no_raw_net <<EOF
#include <tunables/global>

profile no-ping flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  network inet tcp,
  network inet udp,
  network inet icmp,

  deny network raw,
  deny network packet,
  file,
  mount,
}
EOF

Una vez que hayas creado el archivo de perfil de seguridad, puedes usar apparmor_parser para cargar el perfil en AppArmor:

/sbin/apparmor_parser --replace --write-cache /etc/apparmor.d/no_raw_net

Una vez cargado, puedes probar el perfil no-ping de la siguiente manera:

$ docker run --rm -i --security-opt apparmor=no-ping debian:jessie ping -c3 8.8.8.8

El comando crea un contenedor con el perfil de seguridad no-ping y, además, intenta ejecutar ping desde el contenedor. El perfil de seguridad debería rechazar el tráfico, lo que genera un error como el siguiente:

ping: Lacking privilege for raw socket.

Para garantizar que el perfil de seguridad personalizado esté presente cuando se inicie la instancia de Container-Optimized OS, y siga siendo constante en todos los reinicios, puedes usar cloud-init para instalar el perfil en /etc/apparmor.d. Para ello, agrega una secuencia de comandos cloud-config a los metadatos de la instancia como valor de la clave user-data.

La siguiente secuencia de comandos de cloud-config agrega el perfil no-ping a /etc/apparmor.d:

#cloud-configs

write_files:
- path: /etc/apparmor.d/no_raw_net
  permissions: 0644
  owner: root
  content: |
    #include <tunables/global>

    profile no-ping flags=(attach_disconnected,mediate_deleted) {
      #include <abstractions/base>

      network inet tcp,
      network inet udp,
      network inet icmp,

      deny network raw,
      deny network packet,
      file,
      mount,
    }

Para asegurarte de que el archivo de servicio cargue el perfil personalizado en AppArmor y le indique a Docker que lo utilice, ejecuta los siguientes comandos en tu instancia:

ExecStartPre=/sbin/apparmor_parser -r -W /etc/apparmor.d/no_raw_net
ExecStart=/usr/bin/docker run --security-opt apparmor=no-ping ...

Una vez que hayas ejecutado los comandos, reinicia tu instancia, y luego puedes ejecutar el contenedor restringido por el perfil personalizado de AppArmor.