As permissões no Linux respondem à pergunta «quem pode ler este ficheiro». O AppArmor coloca outra: «o que é permitido a este programa fazer». A diferença vê-se durante uma intrusão. Uma web shell corre com o utilizador do servidor web e herda todas as suas permissões, ou seja, a leitura de meio sistema. Um perfil do AppArmor limita o processo à lista do que lhe faz falta para trabalhar, e uma tentativa de ler /etc/shadow ou de iniciar /bin/bash termina com uma recusa, independentemente das permissões do utilizador.

O que já está ativo

sudo aa-status

A saída responde a três perguntas: quantos perfis estão carregados, quantos deles estão em modo enforce e complain, e que processos correm sem perfil nenhum. Num Ubuntu típico haverá algumas dezenas de perfis, mas quase todos para utilitários como o man e o tcpdump. Os serviços centrais — nginx, Apache, PHP-FPM — costumam faltar na lista dos processos confinados.

Três modos a distinguir:

  • enforce: as regras aplicam-se, tudo o que é supérfluo fica proibido;
  • complain: as infrações apenas são registadas, nada é bloqueado. É o modo de afinação;
  • unconfined: não há perfil, o programa corre sem restrições.

A parte mais útil da saída do aa-status é a última: os processos à escuta na rede e não limitados por nada. É essa a lista por onde começar.

As ferramentas

sudo apt install apparmor-utils

Sem esse pacote os comandos aa-complain, aa-enforce e aa-logprof não existem no sistema, embora o AppArmor funcione.

Como ativar um perfil sem parar o serviço

A ordem é fundamental. Um perfil posto logo em enforce proibirá ao serviço, com alta probabilidade, algo necessário, e ele deixará de funcionar; normalmente não de imediato, mas numa operação rara como um carregamento de ficheiro ou o envio de correio.

A sequência correta:

sudo aa-complain /etc/apparmor.d/usr.sbin.nginx

Uma semana de funcionamento nesse modo, cobrindo todos os cenários excecionais: uma cópia de segurança, uma atualização, o carregamento de ficheiros grandes. Depois, o exame do que se acumulou:

sudo aa-logprof

O comando percorre as infrações registadas e pergunta por cada uma se deve ser permitida. Aqui é precisa atenção: permita o que pertence mesmo ao trabalho do serviço, e não tudo em seguida, ou ficará com um perfil que permite tudo e o sentido perde-se.

E só então:

sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx

Onde ver as recusas

Todas as infrações vão parar ao diário do núcleo:

sudo journalctl -k | grep -i apparmor
sudo grep 'apparmor="DENIED"' /var/log/audit/audit.log

O segundo ficheiro existe se o auditd estiver instalado, e com ele os registos são bastante mais detalhados. Um registo de recusa mostra o nome do perfil, a operação pedida e o caminho acedido; isso basta para saber se há que corrigir o perfil ou alegrar-se com o disparo.

Um sintoma vale a pena guardar: um serviço comporta-se de forma estranha — não lê uma configuração, não escreve numa pasta, não abre um socket — enquanto nos seus próprios registos aparece um erro de «permissão negada» com permissões manifestamente corretas. Isso é quase sempre o AppArmor, e o primeiro passo é ver o diário do núcleo.

Uma medida prática, não teórica

Um perfil para o PHP-FPM ou o nginx compensa de forma concreta. Com o processo confinado, uma web shell que chegue ao sítio não pode ler ficheiros de sistema, nem iniciar um interpretador, nem escrever fora das pastas permitidas. Um sítio comprometido continua a ser um sítio comprometido em vez de se transformar em acesso a toda a máquina, e é precisamente essa passagem que constitui a maior parte do prejuízo.

Uma ordem razoável de adoção: primeiro um perfil para o que olha para a internet (servidor web, PHP-FPM), depois para as bases de dados, a seguir conforme necessário. Não é preciso ativar tudo de uma vez, e um conjunto universal pronto não existe: um perfil depende de onde vivem os seus ficheiros.

O que verificar com regularidade

Os perfis voltam ao estado não confinado mais vezes do que parece: uma atualização de pacote pode substituir um ficheiro de perfil, uma depuração manual deixa um serviço em complain, e um serviço novo chega sem perfil nenhum. Dois números são úteis: quantos perfis estão em enforce e quantos processos de rede estão sem restrições. Uma variação de qualquer um deles merece ser conhecida. Como fica reunido numa página mostra-o a demonstração abaixo.