Protezione dei container con AppArmor

AppArmor è un modulo di sicurezza del kernel Linux che puoi utilizzare per limitare le funzionalità dei processi in esecuzione sul sistema operativo host. Ogni processo può avere il proprio profilo di sicurezza. Il profilo di sicurezza consente o meno funzionalità specifiche, come l'accesso alla rete o le autorizzazioni di lettura/scrittura/esecuzione dei file.

Puoi utilizzare AppArmor con i container Docker in esecuzione sulle tue istanze Container-Optimized OS. A qualsiasi container puoi applicare il profilo di sicurezza AppArmor predefinito fornito con Docker o un profilo di sicurezza personalizzato fornito da te.

Utilizzo del profilo di sicurezza AppArmor di Docker predefinito

Quando avvii un contenitore nell'istanza Container-Optimized OS, il sistema applica automaticamente il profilo di sicurezza AppArmor docker-default. Il seguente comando di esempio esegue un contenitore con il profilo di sicurezza docker-default:

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

Per testare il profilo di sicurezza docker-default, puoi provare a leggere il file /proc/sysrq-trigger con il comando cat, come segue:

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

L'output dovrebbe contenere un errore "Autorizzazione non consentita", simile al seguente:

cat: /proc/sysrq-trigger: Permission denied

Applicazione di un profilo di sicurezza personalizzato

Per applicare un profilo di sicurezza diverso, utilizza l'opzione a riga di comando apparmor=<profile-name> quando esegui il contenitore. Il seguente comando di esempio esegue un contenitore con un profilo di sicurezza chiamato no-ping:

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

Per saperne di più sulla creazione del profilo no-ping specificato nell'esempio, consulta la sezione Creare un profilo di sicurezza personalizzato più avanti in questo argomento.

Puoi anche specificare unconfined con l'opzione apparmor per indicare che il contenitore deve essere eseguito con un profilo di sicurezza nessuno, come nell'esempio seguente:

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

Visualizzazione dei profili di sicurezza AppArmor attivi

Puoi vedere quale profilo AppArmor, se presente, si applica ai processi nell'istanza COS esaminando il file /proc/<pid>/attr/current, dove <pid> è l'ID processo.

Supponiamo che nella tua istanza siano in esecuzione i seguenti processi (mostrati dal 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 esamini /proc/1927/attr/current, dovresti vedere il seguente output che indica che il processo (pid 1927) è stato eseguito con il profilo di sicurezza Docker predefinito:

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

Se esamini /proc/2001/attr/current, dovresti vedere il seguente output che indica che il processo (pid 2001) è stato eseguito con nessun profilo di sicurezza (ovvero con l'opzione apparmor=unconfined):

# cat /proc/2001/attr/current
unconfined

Creazione di un profilo di sicurezza personalizzato

Se il processo richiede un profilo di sicurezza diverso da docker-default, puoi scrivere il tuo profilo personalizzato. Per utilizzare un profilo personalizzato, devi creare il file del profilo e caricarlo in AppArmor.

Ad esempio, supponiamo che tu voglia un profilo di sicurezza che non consenta tutto il traffico di rete non elaborato. Il seguente script crea un file per un profilo di sicurezza chiamato no-ping in /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

Dopo aver creato il file del profilo di sicurezza, puoi utilizzare apparmor_parser per caricare il profilo in AppArmor:

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

Una volta caricato, puoi testare il profilo no-ping nel seguente modo:

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

Il comando crea un contenitore con il profilo di sicurezza no-ping e tenta di eseguire ping all'interno del contenitore. Il profilo di sicurezza dovrebbe non consentire il traffico, generando un errore simile al seguente:

ping: Lacking privilege for raw socket.

Per assicurarti che il profilo di sicurezza personalizzato sia presente all'avvio dell'istanza del sistema operativo ottimizzata per i contenitori e rimanga persistente dopo i riavvii, puoi utilizzare cloud-init per installarlo in /etc/apparmor.d. Per farlo, aggiungi uno script cloud-config ai metadati dell'istanza come valore della chiave user-data.

Il seguente script cloud-config aggiunge il profilo 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,
    }

Per assicurarti che il file di servizio carichi il profilo personalizzato in AppArmor e diga a Docker di utilizzarlo, esegui i seguenti comandi sull'istanza:

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

Dopo aver eseguito i comandi, riavvia l'istanza e poi puoi eseguire il contenitore limitato dal tuo profilo AppArmor personalizzato.