Como proteger contêineres com o AppArmor

O AppArmor é um módulo de segurança do kernel do Linux que pode ser usado para restringir a capacidade dos processos em execução no sistema operacional do host. Cada processo pode ter um perfil de segurança próprio. O perfil de segurança permite ou impede recursos específicos, como acesso à rede ou permissões para ler/gravar/executar arquivos.

Use o AppArmor com os contêineres do Docker em execução nas instâncias do Container-Optimized OS. Em qualquer contêiner específico, você pode aplicar o perfil de segurança padrão do AppArmor fornecido com o Docker ou um perfil de segurança personalizado fornecido por você.

Usar o perfil de segurança padrão do AppArmor para o Docker

Quando você inicia um contêiner na instância do Container-Optimized OS, o sistema aplica automaticamente o perfil de segurança docker-default do AppArmy. O comando de exemplo a seguir executa um contêiner com o perfil de segurança docker-default:

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

Para testar o perfil de segurança docker-default, tente ler o arquivo /proc/sysrq-trigger com o comando cat da seguinte maneira:

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

A saída precisa conter um erro de "Permissão negada", semelhante ao seguinte:

cat: /proc/sysrq-trigger: Permission denied

Como aplicar um perfil de segurança personalizado

Para aplicar um perfil de segurança diferente, use a opção de linha de comando apparmor=<profile-name> ao executar o contêiner. O exemplo de comando a seguir executa um contêiner com um perfil de segurança denominado no-ping:

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

Consulte Como criar um perfil de segurança personalizado mais adiante neste tópico para mais informações sobre como criar o perfil no-ping especificado no exemplo.

Você também pode especificar unconfined com a opção apparmor para indicar que o contêiner será executado sem nenhum perfil de segurança, como no exemplo a seguir:

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

Visualizar os perfis de segurança do AppArmor ativos

Você pode ver qual perfil do AppArmy, se houver, se aplica aos processos na instância do Container-Optimized OS inspecionando o arquivo /proc/<pid>/attr/current, em que <pid> é o código do processo.

Suponha que você tenha os seguintes processos em execução na instância (mostrados pelo 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

Se você inspecionar /proc/1927/attr/current, verá a seguinte saída indicando que o processo (pid 1927) foi executado com o perfil de segurança padrão do Docker:

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

Se você inspecionar /proc/2001/attr/current, verá a seguinte saída indicando que o processo (pid 2001) foi executado com nenhum perfil de segurança (ou seja, com a opção apparmor=unconfined):

# cat /proc/2001/attr/current
unconfined

Criar um perfil de segurança personalizado

Se o processo exigir um perfil de segurança diferente de docker-default, você poderá criar seu próprio perfil personalizado. Para usar um perfil personalizado, você precisa criar o arquivo do perfil e enviá-lo para o AppArmor.

Por exemplo, suponha que você quer um perfil de segurança que negue todo tráfego de rede bruto. O script a seguir cria um arquivo para um perfil de segurança chamado no-ping em /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

Depois de criar o arquivo de perfil de segurança, use apparmor_parser para carregar o perfil no AppArmy:

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

Depois de carregado, você pode testar o perfil no-ping da seguinte maneira:

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

O comando cria um contêiner com o perfil de segurança no-ping e tenta executar ping a partir do contêiner. O perfil de segurança nega o tráfego, o que resulta em um erro como o seguinte:

ping: Lacking privilege for raw socket.

Para garantir que seu perfil de segurança personalizado esteja presente quando a instância do Container-Optimized OS for inicializada e permanecer persistente durante as reinicializações, use cloud-init para instalar o perfil em /etc/apparmor.d. Para fazer isso, adicione um script cloud-config aos metadados da instância como o valor da chave user-data.

O script cloud-config a seguir adiciona o 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 garantir que o arquivo do seu serviço carregue seu perfil personalizado no AppArmor e informe ao Docker para usá-lo, execute os seguintes comandos na sua instância:

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

Depois de executar os comandos, reinicialize a instância e execute o contêiner protegido pelo seu perfil personalizado do AppArmor.