Protezione dei container con AppArmor

AppArmor è un modulo di sicurezza del kernel Linux che puoi utilizzare per limitare le capacità dei processi in esecuzione sul sistema operativo host. Ogni processo può avere il proprio profilo di sicurezza. Il profilo di sicurezza consente o non consente 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. Per ogni 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 Docker AppArmor predefinito

Quando avvii un container nell'istanza di Container-Optimized OS, il sistema applica automaticamente il profilo di sicurezza AppArmor docker-default. Il seguente comando di esempio esegue un container 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 indicato di seguito:

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

L'output deve contenere un errore "Autorizzazione negata", 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 della riga di comando apparmor=<profile-name> quando esegui il container. Il seguente comando di esempio esegue un container con un profilo di sicurezza denominato no-ping:

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

Consulta la sezione Creazione di un profilo di sicurezza personalizzato più avanti in questo argomento per ulteriori informazioni sulla creazione del profilo no-ping specificato nell'esempio.

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

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

Visualizzazione dei profili di sicurezza attivi di AppArmor

Per vedere quale profilo AppArmor, se presente, viene applicato ai processi nell'istanza di Container-Optimized OS, esamina il file /proc/<pid>/attr/current, dove <pid> è l'ID processo.

Supponi che i seguenti processi siano in esecuzione sulla tua istanza (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 senza nessun profilo di sicurezza (ossia, 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 usare 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. Lo script seguente crea un file per un profilo di sicurezza denominato no-ping all'indirizzo /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

Una volta 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

Dopo averlo 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 container con il profilo di sicurezza no-ping e tenta di eseguire ping dall'interno del container. Il profilo di sicurezza non dovrebbe 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 di Container-Optimized OS e rimanga permanente dopo i riavvii, puoi utilizzare cloud-init per installare il profilo 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 tuo profilo personalizzato in AppArmor e indichi a Docker di utilizzarlo, esegui questi 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, quindi esegui il container limitato dal profilo AppArmor personalizzato.