Product SiteDocumentation Site

14.4. Introdução ao AppArmor

14.4.1. Princípios

AppArmor é um sistema de Controle de Acesso Mandatório (MAC - Mandatory Access Control) construído sobre a interface LSM (Linux Security Modules) do Linux. Na prática, o kernel consulta o AppArmor antes de cada chamada do sistema para saber se o processo está autorizado a fazer a operação dada. Através desse mecanismo, o AppArmor confina programas a um conjunto limitado de recursos.
O AppArmor aplica um conjunto de regras (conhecidas como “perfil”) em cada programa. O perfil aplicado pelo kernel depende do caminho ("path") de instalação do programa sendo executado. Ao contrário do SELinux (discutido em Seção 14.5, “Introdução ao SELinux”), as regras aplicadas não dependem do usuário. Todos os usuários encontram o mesmo conjunto de regras quando eles estão executando o mesmo programa (mas as permissões tradicionais do usuário ainda se aplicam e podem resultar em um comportamento diferente!).
Os perfis AppArmor são armazenados em /etc/apparmor.d/ e eles contém uma lista de regras de controle de acesso em recursos que cada programa pode fazer uso. Os perfis são compilados e carregados no núcleo pelo comando apparmor_parser. Cada perfil pode ser carregado tanto em modo de aplicação ("enforcing") quanto em modo de registro ("complaining"). O primeiro aplica a política e reporta as tentativas de violação, enquanto que o último não aplica a política mas mantém os registros de chamadas de sistema que deveriam ter sido negadas.

14.4.2. Habilitando o AppArmor e gerenciando os perfis AppArmor

O suporte ao AppArmor é construído nos kernel padrões fornecidos pelo Debian. Habilitar o AppArmor é, assim, uma simples questão de instalar alguns pacotes e adicionar alguns parâmetros à linha de comando do kernel:
# apt install apparmor apparmor-profiles apparmor-utils
[...]
# perl -pi -e 's,GRUB_CMDLINE_LINUX="(.*)"$,GRUB_CMDLINE_LINUX="$1 apparmor=1 security=apparmor",' /etc/default/grub
# update-grub
Após uma reinicialização, o AppArmor está agora funcional e o aa-status irá confirmar isso rapidamente:
# aa-status
apparmor module is loaded.
44 profiles are loaded.
9 profiles are in enforce mode.
   /usr/bin/lxc-start
   /usr/lib/chromium-browser/chromium-browser//browser_java
[...]
35 profiles are in complain mode.
   /sbin/klogd
[...]
3 processes have profiles defined.
1 processes are in enforce mode.
   /usr/sbin/libvirtd (1295) 
2 processes are in complain mode.
   /usr/sbin/avahi-daemon (941) 
   /usr/sbin/avahi-daemon (1000) 
0 processes are unconfined but have a profile defined.
O estado de cada perfil pode ser alterado entre aplicação ("enforcing") e registro ("complaining") com chamadas a aa-enforce e aa-complain dando como parâmetro tanto o caminho para o executável como o caminho para o arquivo de política. Adicionalmente, um perfil pode ser inteiramente desabilitado com aa-disable ou posto em modo auditar ("audit") (para aceitar chamadas de sistema também) com aa-audit.
# aa-enforce /usr/sbin/avahi-daemon
Setting /usr/sbin/avahi-daemon to enforce mode.
# aa-complain /etc/apparmor.d/usr.bin.lxc-start
Setting /etc/apparmor.d/usr.bin.lxc-start to complain mode.

14.4.3. Criando um novo perfil

Mesmo sendo bem fácil criar um perfil AppArmor, a maioria dos programas não tem um. Essa seção irá mostrar a você como criar um novo perfil a partir do zero apenas usando o programa alvo e deixando o AppArmor monitorar a chamada de sistema que ele faz e os recursos que ele acessa.
Os programas mais importantes que precisam ser confinados são os programas voltados para a rede, pois são mais atrativos à ataques remotos. É por isso que o AppArmor convenientemente fornece o comando aa-unconfined para listar os programas que não tem perfil associado e que expôem um soquete de rede aberto. Com a opção --paranoid você tem todos os processos não confinados que tem ao menos uma conexão de rede ativa.
# aa-unconfined
801 /sbin/dhclient not confined
890 /sbin/rpcbind not confined
899 /sbin/rpc.statd not confined
929 /usr/sbin/sshd not confined
941 /usr/sbin/avahi-daemon confined by '/usr/sbin/avahi-daemon (complain)'
988 /usr/sbin/minissdpd not confined
1276 /usr/sbin/exim4 not confined
1485 /usr/lib/erlang/erts-6.2/bin/epmd not confined
1751 /usr/lib/erlang/erts-6.2/bin/beam.smp not confined
19592 /usr/lib/dleyna-renderer/dleyna-renderer-service not confined
No exemplo a seguir, nós iremos então tentar criar um perfil para o /sbin/dhclient. Para isso, nós iremos usar o aa-genprof dhclient. Ele irá convidar você a usar a aplicação em outra janela e quando terminar voltar ao aa-genprof para procurar por eventos AppArmor nos registros ("logs") do sistema e converter esses registros em regras de acesso. Para cada evento registrado, ele irá fazer uma ou mais sugestões de regras que você pode tanto aprovar quanto fazer edições adicionais de múltiplas maneiras:
# aa-genprof dhclient
Writing updated profile for /sbin/dhclient.
Setting /sbin/dhclient to complain mode.

Before you begin, you may wish to check if a
profile already exists for the application you
wish to confine. See the following wiki page for
more information:
http://wiki.apparmor.net/index.php/Profiles

Please start the application to be profiled in
another window and exercise its functionality now.

Once completed, select the "Scan" option below in 
order to scan the system logs for AppArmor events. 

For each AppArmor event, you will be given the 
opportunity to choose whether the access should be 
allowed or denied.

Profiling: /sbin/dhclient

[(S)can system log for AppArmor events] / (F)inish
Reading log entries from /var/log/audit/audit.log.

Profile:  /sbin/dhclient 1
Execute:  /usr/lib/NetworkManager/nm-dhcp-helper
Severity: unknown

(I)nherit / (C)hild / (P)rofile / (N)amed / (U)nconfined / (X) ix On / (D)eny / Abo(r)t / (F)inish
P
Should AppArmor sanitise the environment when
switching profiles?

Sanitising environment is more secure,
but some applications depend on the presence
of LD_PRELOAD or LD_LIBRARY_PATH.

(Y)es / [(N)o]
Y
Writing updated profile for /usr/lib/NetworkManager/nm-dhcp-helper.
Complain-mode changes:
WARN: unknown capability: CAP_net_raw

Profile:    /sbin/dhclient 2
Capability: net_raw
Severity:   unknown

[(A)llow] / (D)eny / (I)gnore / Audi(t) / Abo(r)t / (F)inish
A
Adding capability net_raw to profile.

Profile:  /sbin/dhclient 3
Path:     /etc/nsswitch.conf
Mode:     r
Severity: unknown

  1 - #include <abstractions/apache2-common> 
  2 - #include <abstractions/libvirt-qemu> 
  3 - #include <abstractions/nameservice> 
  4 - #include <abstractions/totem> 
 [5 - /etc/nsswitch.conf]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
3

Profile:  /sbin/dhclient
Path:     /etc/nsswitch.conf
Mode:     r
Severity: unknown

  1 - #include <abstractions/apache2-common> 
  2 - #include <abstractions/libvirt-qemu> 
 [3 - #include <abstractions/nameservice>]
  4 - #include <abstractions/totem> 
  5 - /etc/nsswitch.conf 
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding #include <abstractions/nameservice> to profile.

Profile:  /sbin/dhclient
Path:     /proc/7252/net/dev
Mode:     r
Severity: 6

  1 - /proc/7252/net/dev 
 [2 - /proc/*/net/dev]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /proc/*/net/dev r to profile

[...]
Profile:  /sbin/dhclient 4
Path:     /run/dhclient-eth0.pid
Mode:     w
Severity: unknown

 [1 - /run/dhclient-eth0.pid]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
N

Enter new path: /run/dhclient*.pid

Profile:  /sbin/dhclient
Path:     /run/dhclient-eth0.pid
Mode:     w
Severity: unknown

  1 - /run/dhclient-eth0.pid 
 [2 - /run/dhclient*.pid]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /run/dhclient*.pid w to profile

[...]
Profile:  /usr/lib/NetworkManager/nm-dhcp-helper 5
Path:     /proc/filesystems
Mode:     r
Severity: 6

 [1 - /proc/filesystems]
[(A)llow] / (D)eny / (I)gnore / (G)lob / Glob with (E)xtension / (N)ew / Abo(r)t / (F)inish / (M)ore
A
Adding /proc/filesystems r to profile

= Changed Local Profiles =

The following local profiles were changed. Would you like to save them?

 [1 - /sbin/dhclient]
  2 - /usr/lib/NetworkManager/nm-dhcp-helper 
(S)ave Changes / Save Selec(t)ed Profile / [(V)iew Changes] / View Changes b/w (C)lean profiles / Abo(r)t
S
Writing updated profile for /sbin/dhclient.
Writing updated profile for /usr/lib/NetworkManager/nm-dhcp-helper.

Profiling: /sbin/dhclient

[(S)can system log for AppArmor events] / (F)inish
F
Setting /sbin/dhclient to enforce mode.
Setting /usr/lib/NetworkManager/nm-dhcp-helper to enforce mode.

Reloaded AppArmor profiles in enforce mode.

Please consider contributing your new profile!
See the following wiki page for more information:
http://wiki.apparmor.net/index.php/Profiles

Finished generating profile for /sbin/dhclient.
Note que o programa não exibe de volta os caracteres de controle que você digitou, mas para clarear a explicação eu inclui eles na transcrição prévia.

1

O primeiro evento detectado é a execução de outro programa. Neste caso, você tem múltiplas escolhas: você pode rodar o programa com o perfil do processo pai (a escolha “Inherit”), você pode rodá-lo com seu próprio e dedicado perfil (as escolhas “Profile” e “Named”, diferindo apenas pela possibilidade de usar um nome de perfil arbitrário), você pode rodá-lo com um sub-perfil do processo pai (a escolha “Child”), você pode rodá-lo sem qualquer perfil (a escolha “Unconfined”) ou você pode decidir não rodá-lo de forma alguma (a escolha “Deny”).
Note que quando você opta por rodá-lo sob um perfil dedicado que não existe ainda, a ferramenta irá criar o perfil em falta para você e irá fazer sugestões de regras para esse perfil nesta mesma execução.

2

A nível do kernel, os poderes especiais do usuário root foram divididos em "recursos" ("capabilities"). Quando uma chamada de sistema requer um recurso específico, o AppArmor irá verificar se o perfil permite ao programa fazer uso desse recurso.

3

Aqui o programa busca por permissões de leitura para o /etc/nsswitch.conf. O aa-genprof detectou que essa permissão era também obtida por múltiplas "abstrações” e as oferece como escolhas alternativas. Uma abstração fornece um conjunto de regras de acesso reusável reunindo múltiplos recursos que são comumente usados juntos. Nesse caso específico, o arquivo é geralmente acessado através das funções relacionadas o serviço de nomes da biblioteca do C e nós digitamos "3" para primeiro selecionarmos a opção "#include <abstractions/nameservice>" e então "A" para dar a permissão.

4

O programa quer criar o arquivo /run/dhclient-eth0.pid. Se nós permitirmos apenas a criação desse arquivo específico, o programa não irá funcionar quando o usuário for usá-lo com outra interface de rede. Assim, nós selecionamos "Novo" (“New”) para substituir o nome de arquivo por algo mais genérico como “/run/dhclient*.pid” antes de gravar a regra com "Permitir" (“Allow”).

5

Note que essa requisição de acesso não é parte do perfil do dhclient mas do novo perfil que nós criamos quando nós permitimos o /usr/lib/NetworkManager/nm-dhcp-helper rodar com seu próprio perfil.
Após termos passado por todos os eventos registrados, o programa se oferece para salvar todos os perfis que foram criados durante sua execução. Neste caso, nós temos dois perfis que nós salvamos ao mesmo tempo com "Salvar" (“Save”) (mas você pode salvá-los individualmente também) antes de sair do programa com "Terminar" (“Finish”).
O aa-genprof é na realidade apenas um envoltório inteligente em volta do aa-logprof: ele cria um perfil vazio, carrega-o em modo de registro ("complain mode") e então roda o aa-logprof que é uma ferramenta para atualizar um perfil com base nas violações de perfil que foram registradas. Então você pode rodar novamente essa ferramenta mais tarde para aprimorar o perfil que você acabou de criar.
Se você quer que o perfil gerado seja completo, você deve usar o programa de todas as maneiras que sejam legítimas de usar. No caso do dhclient, isso significa rodá-lo via Network Manager, rodá-lo via ifupdown, rodá-lo manualmente, etc. No final, você deve obter um /etc/apparmor.d/sbin.dhclient próximo a isso:
# Last Modified: Tue Sep  8 21:40:02 2015
#include <tunables/global>

/sbin/dhclient {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  capability net_bind_service,
  capability net_raw,

  /bin/dash r,
  /etc/dhcp/* r,
  /etc/dhcp/dhclient-enter-hooks.d/* r,
  /etc/dhcp/dhclient-exit-hooks.d/* r,
  /etc/resolv.conf.* w,
  /etc/samba/dhcp.conf.* w,
  /proc/*/net/dev r,
  /proc/filesystems r,
  /run/dhclient*.pid w,
  /sbin/dhclient mr,
  /sbin/dhclient-script rCx,
  /usr/lib/NetworkManager/nm-dhcp-helper Px,
  /var/lib/NetworkManager/* r,
  /var/lib/NetworkManager/*.lease rw,
  /var/lib/dhcp/*.leases rw,

  profile /sbin/dhclient-script flags=(complain) {
    #include <abstractions/base>
    #include <abstractions/bash>

    /bin/dash rix,
    /etc/dhcp/dhclient-enter-hooks.d/* r,
    /etc/dhcp/dhclient-exit-hooks.d/* r,
    /sbin/dhclient-script r,

  }
}