É a primeira pergunta que ouço sempre. Tanto AppArmor quanto SELinux são módulos LSM que oferecem MAC, mas adotam abordagens distintas:
- AppArmor usa path-based access control — perfis referenciam caminhos do sistema de arquivos (
/etc/passwd, /var/log/nginx/*). Curva de aprendizado mais curta, sintaxe legível, ideal para quem precisa de hardening rápido em workloads específicos.
- SELinux usa label-based access control — cada arquivo, processo e socket recebe um rótulo de contexto. Mais granular e robusto contra renomeações maliciosas, mas exige um investimento de tempo bem maior (e paciência, muita).
Para servidores web, bancos de dados, containers e CI/CD, o AppArmor entrega 80% do benefício de segurança com 20% do esforço. Em ambientes regulados (governo, defesa, PCI DSS de alto risco), SELinux ainda é a escolha preferida — e justa.
Verificando o status do AppArmor
Antes de sair criando perfis, confirme que o kernel tem AppArmor habilitado e o serviço está ativo. Pular essa etapa é receita garantida para ficar uma hora debugando perfil que nem está sendo carregado.
# Verificar se o LSM está carregado no kernel
cat /sys/kernel/security/lsm
# Saída esperada (Ubuntu 24.04): lockdown,capability,landlock,yama,apparmor,bpf
# Status do serviço systemd
sudo systemctl status apparmor
# Listar perfis carregados, em modo enforce e complain
sudo aa-status
O comando aa-status retorna algo como:
apparmor module is loaded.
57 profiles are loaded.
42 profiles are in enforce mode.
15 profiles are in complain mode.
0 profiles are in kill mode.
0 profiles are in unconfined mode.
12 processes have profiles defined.
12 processes are in enforce mode.
Instalação e ferramentas essenciais
No Ubuntu 24.04 LTS, o AppArmor já vem instalado e habilitado por padrão (uma das poucas coisas que a Canonical acerta de cara, na minha opinião). No Debian 12, é provável que você precise instalar pacotes adicionais:
# Debian 12
sudo apt update
sudo apt install -y apparmor apparmor-utils apparmor-profiles \
apparmor-profiles-extra auditd
# Habilitar no boot via parâmetro de kernel (caso não esteja)
sudo sed -i 's/GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 apparmor=1 security=apparmor"/' /etc/default/grub
sudo update-grub
sudo reboot
O pacote apparmor-utils fornece as ferramentas que você vai usar no dia a dia:
aa-genprof — gera perfil interativamente observando o programa em execução
aa-logprof — refina perfis com base em violações registradas
aa-complain / aa-enforce — alterna o modo de um perfil
aa-disable / aa-enable — desativa ou ativa um perfil
aa-unconfined — lista processos com socket aberto que não estão confinados (esse aqui é ouro)
Modos de operação: complain vs enforce
Cada perfil pode operar em três modos principais:
- Enforce — bloqueia ativamente operações não permitidas e registra a violação no syslog.
- Complain — permite as operações, mas registra cada uma. Essencial durante a fase de aprendizado de um perfil novo.
- Audit — registra todas as operações permitidas pelo perfil. Útil para forense, mas prepare-se para um volume considerável de logs.
O fluxo recomendado para perfis novos é simples: comece em complain, exercite todas as funcionalidades do programa, refine com aa-logprof, e só depois alterne para enforce. Pular a fase de complain é o caminho mais curto para receber call de plantão às 3h da manhã.
# Colocar perfil do nginx em modo complain
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
# Após validação, retornar a enforce
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
Anatomia de um perfil AppArmor
Os perfis ficam em /etc/apparmor.d/. Vamos analisar um exemplo prático para um daemon hipotético /usr/bin/myapp:
#include <tunables/global>
/usr/bin/myapp {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/openssl>
capability net_bind_service,
capability setuid,
capability setgid,
network inet stream,
network inet6 stream,
/usr/bin/myapp mr,
/etc/myapp/** r,
/var/lib/myapp/** rwk,
/var/log/myapp/*.log w,
/run/myapp.pid rwk,
/tmp/myapp-* rwk,
owner /home/*/.config/myapp/** r,
deny /etc/shadow rwklx,
deny /root/** rwklx,
deny @{HOME}/.ssh/** rwklx,
}
Alguns pontos que vale destacar:
- Abstractions são fragmentos reutilizáveis em
/etc/apparmor.d/abstractions/. base permite acesso a libs essenciais, nameservice habilita resolução DNS, openssl libera arquivos de certificados padrão.
- Capabilities seguem o modelo de capacidades do Linux. Conceda apenas as estritamente necessárias — e duvide de qualquer sugestão de ferramenta que peça
sys_admin sem justificativa.
- Permissões de arquivo:
r (leitura), w (escrita), k (lock), m (mmap exec), x (execute), l (link). O sufixo r em mr permite mapear o binário em memória executável.
- Globs:
* casa um nível, ** casa recursivamente, {a,b} casa alternativas.
- Regras deny sobrescrevem permissões herdadas — é defesa em profundidade pura.
Criando um perfil com aa-genprof
Suponha que você acabou de instalar o redis-server sem perfil oficial. Crie um do zero — vou usar esse exemplo porque é o cenário que mais vejo na vida real:
# Em um terminal, inicie a ferramenta
sudo aa-genprof /usr/bin/redis-server
# Em outro terminal, exercite o serviço
sudo systemctl restart redis-server
redis-cli SET foo bar
redis-cli GET foo
redis-cli SAVE
sudo systemctl reload redis-server
De volta ao terminal do aa-genprof, pressione S para escanear logs. Para cada violação, a ferramenta pergunta como tratar:
- A — Allow (permite a operação especificamente)
- D — Deny (nega explicitamente)
- I — Inherit (executa sob o mesmo perfil pai)
- P — Profile (transição para outro perfil)
- U — Unconfined (sem confinamento — perigoso, evite a menos que tenha uma razão muito boa)
- G — Glob (transforma path em glob:
/var/log/redis/*.log)
Ao final, pressione S para salvar e F para finalizar. O perfil será criado em /etc/apparmor.d/usr.bin.redis-server e carregado em modo enforce.
Refinando perfis com aa-logprof
Em produção, cargas de trabalho variam. Usuários acessam funcionalidades raramente exercitadas, jobs de backup rodam à meia-noite, alguma rota legada acorda uma vez por mês. Por isso, vale processar os logs periodicamente:
# Procurar violações nas últimas 24h
sudo journalctl --since "24 hours ago" | grep -i "apparmor.*DENIED"
# Refinar perfis interativamente com base nos logs
sudo aa-logprof
# Recarregar todos os perfis após edições manuais
sudo systemctl reload apparmor
Exemplo de violação no journalctl:
kernel: audit: type=1400 audit(1735689600.123:42):
apparmor="DENIED" operation="open"
profile="/usr/sbin/nginx" name="/var/cache/nginx/proxy/abc"
pid=1234 comm="nginx" requested_mask="wc" denied_mask="wc"
fsuid=33 ouid=33
Hardening de serviços críticos
Nginx com perfil restritivo
O perfil padrão do Nginx no Debian/Ubuntu (/etc/apparmor.d/usr.sbin.nginx) costuma vir desativado — o motivo histórico é não quebrar configurações exóticas. Ative e endureça:
# Habilitar perfil
sudo ln -s /etc/apparmor.d/usr.sbin.nginx /etc/apparmor.d/disable/ 2>/dev/null || true
sudo rm -f /etc/apparmor.d/disable/usr.sbin.nginx
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
sudo aa-enforce /usr/sbin/nginx
Adições recomendadas para hardening adicional:
# Editar /etc/apparmor.d/local/usr.sbin.nginx
deny /etc/passwd r,
deny /etc/shadow rwklx,
deny /root/** rwklx,
deny /home/*/.ssh/** rwklx,
deny /var/lib/mysql/** rwklx,
deny @{PROC}/sys/kernel/** w,
# Restringir uploads a um diretório específico
/srv/uploads/** rw,
deny /srv/uploads/**.php* x,
deny /srv/uploads/**.sh* x,
OpenSSH com sshd confinado
O OpenSSH não vem com perfil padrão na maioria das distros, e isso é proposital — questões de compatibilidade com PAM e ChrootDirectory. Se você opera SSH apenas com chaves e sem subsistemas exóticos, dá para adicionar um perfil mínimo. Mas use com cautela e, por favor, teste em ambiente não produtivo primeiro. Já vi muito SSH virar tijolo por causa disso.
Integração com systemd
O systemd suporta nativamente o carregamento de perfis AppArmor por unit, oferecendo confinamento granular sem precisar editar arquivos em /etc/apparmor.d/ diretamente:
[Service]
Type=simple
ExecStart=/usr/bin/myapp
AppArmorProfile=myapp-strict
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
RestrictNamespaces=true
RestrictRealtime=true
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM
A diretiva AppArmorProfile= aceita um prefixo - para tornar o carregamento opcional. Combine AppArmor com as proteções nativas do systemd para defesa em camadas — uma coisa não exclui a outra, e juntas elas cobrem ângulos diferentes.
AppArmor e Docker
O Docker carrega automaticamente o perfil docker-default em todos os containers. Você pode confirmar:
docker run --rm alpine cat /proc/self/attr/current
# Saída: docker-default (enforce)
Para containers que precisam de restrições adicionais (e workloads expostos à internet quase sempre precisam), crie um perfil customizado:
#include <tunables/global>
profile docker-nginx-strict flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet udp,
capability chown,
capability dac_override,
capability setuid,
capability setgid,
capability net_bind_service,
deny @{PROC}/* w,
deny @{PROC}/sys/[^k]*/** wklx,
deny /sys/[^f]*/** wklx,
deny /sys/f[^s]*/** wklx,
deny /sys/fs/c[^g]*/** wklx,
deny /sys/firmware/** rwklx,
deny /sys/kernel/security/** rwklx,
/usr/sbin/nginx ix,
/var/log/nginx/** w,
/etc/nginx/** r,
/usr/share/nginx/** r,
}
Carregue e use:
sudo apparmor_parser -r -W /etc/apparmor.d/docker-nginx-strict
docker run --security-opt apparmor=docker-nginx-strict -d nginx:alpine
Em Kubernetes, especifique o perfil via securityContext no PodSpec (campo appArmorProfile a partir do Kubernetes 1.30, GA na 1.31). Se você ainda usa as anotações antigas, é hora de migrar.
Auditoria e monitoramento
Para integrar AppArmor à sua pipeline de SIEM ou stack de observabilidade, configure o auditd:
# /etc/audit/rules.d/apparmor.rules
-w /etc/apparmor.d/ -p wa -k apparmor_config
-a always,exit -F arch=b64 -S all -F key=apparmor_audit
# Recarregar
sudo augenrules --load
sudo systemctl restart auditd
# Pesquisar eventos AppArmor
sudo ausearch -m AVC -ts today
sudo aureport --avc
Para exportar para Elasticsearch ou Loki, use auditbeat ou promtail:
# filebeat/auditbeat módulo apparmor
- module: system
audit:
enabled: true
syslog:
paths: ["/var/log/syslog", "/var/log/audit/audit.log"]
Resolvendo problemas comuns
Perfil bloqueando funcionalidade legítima
Quando uma feature para de funcionar logo depois de você habilitar enforce, alterne temporariamente para complain, exercite a feature e refine. Não tente resolver "no escuro" — os logs vão te dizer exatamente o que está sendo bloqueado.
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
# ... reproduza o problema ...
sudo aa-logprof
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
Erro: Profile already loaded
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.nginx
sudo apparmor_parser -a /etc/apparmor.d/usr.sbin.nginx
Container Docker recusa iniciar
Se um container falha com permission denied em paths esperados, verifique se o perfil customizado define flags=(attach_disconnected,mediate_deleted). Sem isso, eventos durante a inicialização do container podem ser bloqueados (e o erro nem sempre é óbvio).
Checklist de hardening AppArmor para produção
- Confirme que
aa-status mostra todos os perfis críticos em enforce.
- Habilite perfis para:
nginx, apache2, mysqld, postgres, redis-server, bind9, chronyd, cups.
- Adicione regras
deny explícitas para /etc/shadow, /root/**, /.ssh/** em todos os perfis de serviços expostos à rede.
- Combine
AppArmorProfile= com diretivas de hardening do systemd (ProtectSystem, NoNewPrivileges, SystemCallFilter).
- Para Docker, crie perfis customizados além do
docker-default para workloads críticos ou multi-tenant.
- Centralize logs
apparmor=DENIED em SIEM e configure alertas para violações em produção.
- Inclua testes de perfil no pipeline CI/CD — execute
aa-complain em staging, capture violações novas e bloqueie deploy se houver.
- Documente cada exceção (
capability, path com escrita) com comentário justificando — seu eu do futuro vai agradecer.
Perguntas Frequentes (FAQ)
AppArmor e SELinux podem ser usados juntos no mesmo sistema?
Não. Apenas um LSM principal de tipo MAC pode estar ativo por vez no kernel Linux. Você escolhe entre AppArmor e SELinux durante a instalação ou via parâmetros de kernel. Outros LSMs como Yama, Landlock e BPF-LSM podem ser empilhados em conjunto com AppArmor ou SELinux.
O AppArmor protege contra exploits de kernel?
Parcialmente. AppArmor mitiga exploits que dependem de operações de userspace (escrever em /etc, executar binários inesperados, acessar sockets), mas não protege contra exploits que comprometem o próprio kernel. Combine AppArmor com kernel hardening (kernel.kptr_restrict, kernel.unprivileged_userns_clone=0), módulos como Lockdown, e patches de segurança atualizados.
Como saber quais processos estão sem proteção AppArmor?
Execute sudo aa-unconfined --paranoid para listar todos os processos com sockets de rede abertos que não estão confinados por nenhum perfil. Use a saída como ponto de partida para priorizar quais serviços ganhar perfil primeiro.
AppArmor afeta a performance dos serviços?
O overhead típico fica abaixo de 1-2% em workloads de produção, imperceptível na maioria dos casos. Perfis com muitas regras de glob recursivas (**) em paths quentes podem aumentar essa sobrecarga. Use perf ou bpftrace para medir antes e depois em workloads sensíveis a latência.
É possível usar AppArmor em containers rootless ou Podman?
Sim, mas com limitações. Containers rootless não podem carregar perfis novos no kernel — o perfil precisa ser pré-carregado pelo administrador. O Podman aceita --security-opt apparmor=<profile> da mesma forma que o Docker, e o systemd-nspawn suporta --apparmor= em arquivos de configuração de máquina.
Conclusão
O AppArmor entrega controle de acesso mandatório com curva de aprendizado acessível e impacto mínimo em performance. Em 2026, com superfície de ataque crescente em containers, microserviços e cadeias de suprimentos, deixar processos críticos sem confinamento MAC é uma falha de hardening difícil de justificar para qualquer auditor.
Comece com perfis em modo complain, refine iterativamente com aa-logprof e mova para enforce assim que ganhar confiança. Em poucos sprints, sua frota terá uma camada adicional de defesa que para a maioria dos exploits no momento exato em que tentam tocar disco ou abrir um socket inesperado — e isso, sinceramente, é dos melhores ROIs de segurança que existem hoje.