I permessi in Linux rispondono alla domanda «chi può leggere questo file». AppArmor ne pone un’altra: «che cosa è consentito fare a questo programma». La differenza si vede durante un’intrusione. Una web shell gira con l’utente del server web ed eredita tutti i suoi permessi, cioè la lettura di mezzo sistema. Un profilo AppArmor limita il processo all’elenco di ciò che gli serve per lavorare, e un tentativo di leggere /etc/shadow o di avviare /bin/bash finisce con un rifiuto, indipendentemente dai permessi dell’utente.

Che cosa è già attivo

sudo aa-status

L’output risponde a tre domande: quanti profili sono caricati, quanti di essi sono in modalità enforce e complain, e quali processi girano senza alcun profilo. Su un Ubuntu tipico ci saranno alcune decine di profili, ma quasi tutti per utilità come man e tcpdump. I servizi chiave — nginx, Apache, PHP-FPM — di solito mancano dall’elenco dei processi confinati.

Tre modalità da distinguere:

  • enforce: le regole si applicano, tutto il superfluo è vietato;
  • complain: le violazioni vengono solo registrate, nulla viene bloccato. È la modalità di messa a punto;
  • unconfined: non c’è profilo, il programma gira senza restrizioni.

La parte più utile dell’output di aa-status è l’ultima: i processi in ascolto sulla rete e non limitati da nulla. È l’elenco da cui cominciare.

Gli strumenti

sudo apt install apparmor-utils

Senza quel pacchetto i comandi aa-complain, aa-enforce e aa-logprof nel sistema non esistono, benché AppArmor funzioni.

Come attivare un profilo senza fermare il servizio

L’ordine è fondamentale. Un profilo messo subito in enforce vieterà al servizio, con alta probabilità, qualcosa di necessario, e smetterà di funzionare; di norma non subito, ma in un’operazione rara come un caricamento di file o l’invio di posta.

La sequenza corretta:

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

Una settimana di funzionamento in quella modalità, coprendo tutti gli scenari eccezionali: un backup, un aggiornamento, il caricamento di file grandi. Poi l’esame di ciò che si è accumulato:

sudo aa-logprof

Il comando scorre le violazioni registrate e chiede per ciascuna se consentirla. Qui serve attenzione: consenta ciò che appartiene davvero al lavoro del servizio, e non tutto di seguito, altrimenti otterrà un profilo che consente tutto e il senso va perduto.

E solo allora:

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

Dove vedere i rifiuti

Tutte le violazioni finiscono nel journal del kernel:

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

Il secondo file esiste se auditd è installato, e con esso i record sono nettamente più dettagliati. Un record di rifiuto mostra il nome del profilo, l’operazione richiesta e il percorso a cui si accedeva; basta per capire se correggere il profilo o rallegrarsi dello scatto.

Un sintomo vale la pena ricordarlo: un servizio si comporta in modo strano — non legge una configurazione, non scrive in una cartella, non apre un socket — mentre nei suoi registri compare un errore di «permesso negato» con permessi palesemente corretti. È quasi sempre AppArmor, e la prima cosa da fare è guardare il journal del kernel.

Una misura pratica, non teorica

Un profilo per PHP-FPM o nginx si ripaga in modo concreto. Con il processo confinato, una web shell arrivata sul sito non può né leggere i file di sistema, né avviare un interprete, né scrivere fuori dalle cartelle consentite. Un sito violato resta un sito violato invece di trasformarsi in accesso all’intera macchina, ed è proprio quel passaggio a costituire la parte maggiore del danno.

Un ordine ragionevole di adozione: prima un profilo per ciò che guarda a internet (server web, PHP-FPM), poi per i database, quindi secondo necessità. Non serve attivare tutto in una volta, e un insieme universale già pronto non esiste: un profilo dipende da dove vivono i suoi file.

Che cosa verificare con regolarità

I profili tornano allo stato non confinato più spesso di quanto sembri: un aggiornamento di pacchetto può sostituire un file di profilo, un debug manuale lascia un servizio in complain, e un servizio nuovo arriva senza alcun profilo. Due cifre sono utili: quanti profili sono in enforce e quanti processi di rete sono senza restrizioni. Una variazione dell’una o dell’altra merita di essere conosciuta. Come appare riunito su una pagina lo mostra la dimostrazione qui sotto.