Condividi tramite


Accesso ai contenitori di sicurezza alle risorse tramite funzionalità di sicurezza Linux predefinite

Questo articolo illustra come proteggere l'accesso dei contenitori alle risorse per i carichi di lavoro servizio Azure Kubernetes (servizio Azure Kubernetes).

Panoramica

Allo stesso modo in cui è necessario concedere agli utenti o ai gruppi i privilegi minimi necessari, è anche necessario limitare i contenitori solo alle azioni e ai processi necessari. Per ridurre al minimo il rischio di attacco, evitare di configurare applicazioni e contenitori che richiedono privilegi di escalation o accesso radice.

È possibile usare contesti di sicurezza dei pod Kubernetes predefiniti per definire altre autorizzazioni, ad esempio l'utente o il gruppo da eseguire come, le funzionalità linux da esporre o impostare allowPrivilegeEscalation: false nel manifesto del pod. Per altre procedure consigliate, vedere Proteggere l'accesso dei pod alle risorse.

Per un controllo ancora più granulare delle azioni dei contenitori, è possibile usare funzionalità di sicurezza Linux predefinite, ad esempio AppArmor e seccomp.

  1. Definire le funzionalità di sicurezza di Linux a livello di nodo.
  2. Implementare le funzionalità tramite un manifesto del pod.

Le funzionalità di sicurezza Linux predefinite sono disponibili solo nei nodi e nei pod Linux.

Nota

Attualmente, gli ambienti Kubernetes non sono completamente sicuri per l'utilizzo multi-tenant ostile. Funzionalità di sicurezza aggiuntive, ad esempio Microsoft Defender per contenitori, AppArmor, seccomp, ammissione di sicurezza dei pod o Controllo degli accessi in base al ruolo di Kubernetes per i nodi, bloccano in modo efficiente gli exploit.

Per una vera sicurezza quando si eseguono carichi di lavoro multi-tenant ostili, considerare attendibile solo un hypervisor. Il dominio di sicurezza per Kubernetes diventa l'intero cluster, non un singolo nodo.

Per questi tipi di carichi di lavoro multi-tenant ostili è consigliabile usare cluster fisicamente isolati.

AppArmor

Per limitare le azioni del contenitore, è possibile usare il modulo di sicurezza del kernel AppArmor Linux. AppArmor è disponibile come parte del sistema operativo del nodo del servizio Azure Kubernetes sottostante ed è abilitato per impostazione predefinita. È possibile creare profili AppArmor che limitano le azioni di lettura, scrittura o esecuzione o funzioni di sistema come il montaggio di file system. I profili AppArmor predefiniti limitano l'accesso a varie /proc posizioni e /sys forniscono un mezzo per isolare logicamente i contenitori dal nodo sottostante. AppArmor funziona non solo per i pod Kubernetes ma per qualsiasi applicazione in esecuzione su Linux.

Profili AppArmor in uso in un cluster del servizio Azure Kubernetes per limitare le azioni dei contenitori

Per una dimostrazione di AppArmor in azione, l'esempio seguente crea un profilo che impedisce la scrittura nei file.

  1. Connettersi tramite SSH a un nodo del servizio Azure Kubernetes.

  2. Creare un file denominato deny-write.profile.

  3. Copiare e incollare il contenuto seguente:

    #include <tunables/global>
    profile k8s-apparmor-example-deny-write flags=(attach_disconnected) {
      #include <abstractions/base>
    
      file,
      # Deny all file writes.
      deny /** w,
    }
    

Per aggiungere profili AppArmor occorre usare il comando apparmor_parser.

  1. Aggiungere il profilo ad AppArmor.

  2. Specificare il nome del profilo creato nel passaggio precedente:

    sudo apparmor_parser deny-write.profile
    

    Se il profilo viene analizzato correttamente e applicato ad AppArmor, non verrà visualizzato alcun output e si tornerà al prompt dei comandi.

  3. Dal computer locale creare un manifesto del pod denominato aks-apparmor.yaml. Questo manifesto:

    • Definisce un'annotazione per container.apparmor.security.beta.kubernetes.
    • Fa riferimento al profilo di deny-write creato nei passaggi precedenti.
    apiVersion: v1
    kind: Pod
    metadata:
      name: hello-apparmor
      annotations:
        container.apparmor.security.beta.kubernetes.io/hello: localhost/k8s-apparmor-example-deny-write
    spec:
      containers:
      - name: hello
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command: [ "sh", "-c", "echo 'Hello AppArmor!' && sleep 1h" ]
    
  4. Con il pod distribuito, eseguire il comando seguente e verificare che il pod hello-apparmor mostri uno stato di In esecuzione:

    kubectl get pods
    
    NAME             READY   STATUS    RESTARTS   AGE
    aks-ssh          1/1     Running   0          4m2s
    hello-apparmor   0/1     Running   0          50s
    

Per altre informazioni su AppArmor, vedere AppArmor nella documentazione di Kubernetes.

Secure computing (seccomp)

Mentre AppArmor funziona con qualsiasi applicazione Linux, seccomp (secure computing, elaborazione sicura) funziona a livello di processo. Seccomp è anche un modulo di sicurezza del kernel Linux ed è supportato in modo nativo dal runtime usato dai nodi del containerd servizio Azure Kubernetes. Con seccomp è possibile limitare le chiamate di sistema di un contenitore. Seccomp stabilisce un ulteriore livello di protezione da vulnerabilità comuni delle chiamate di sistema sfruttate da attori malintenzionati e consente di specificare un profilo predefinito per tutti i carichi di lavoro nel nodo.

Configurare un profilo seccomp predefinito (anteprima)

È possibile applicare profili seccomp predefiniti usando configurazioni di nodo personalizzate durante la creazione di un nuovo pool di nodi Linux. Sono supportati due valori nel servizio Azure Kubernetes: RuntimeDefault e Unconfined. Alcuni carichi di lavoro potrebbero richiedere un numero inferiore di restrizioni per le chiamate di sistema rispetto ad altri. Ciò significa che possono avere esito negativo durante il runtime con il profilo 'RuntimeDefault'. Per attenuare un errore di questo tipo, è possibile specificare il Unconfined profilo. Se il carico di lavoro richiede un profilo personalizzato, vedere Configurare un profilo seccomp personalizzato.

Limiti

  • SeccompDefault non è un parametro supportato per i pool di nodi windows.
  • SeccompDefault è disponibile a partire dall'API 2024-09-02-preview.

Importante

Le funzionalità di anteprima del servizio Azure Kubernetes sono disponibili in modalità self-service e opzionale. Le anteprime vengono fornite "così come sono" e "come disponibili" e sono escluse dai contratti di servizio e dalla garanzia limitata. Le anteprime del servizio Azure Kubernetes sono parzialmente coperte dal supporto clienti con la massima diligenza possibile. Di conseguenza, queste funzionalità non sono destinate all'uso in produzione. Per altre informazioni, vedere gli articoli di supporto seguenti:

Registrare il flag di funzionalità KubeletDefaultSeccompProfilePreview

  1. Registrare il flag di funzionalità KubeletDefaultSeccompProfilePreview usando il comando az feature register.

    az feature register --namespace "Microsoft.ContainerService" --name "KubeletDefaultSeccompProfilePreview"
    

    Sono necessari alcuni minuti per visualizzare lo stato Registered.

  2. Verificare lo stato della registrazione usando il comando az feature show.

    az feature show --namespace "Microsoft.ContainerService" --name "KubeletDefaultSeccompProfilePreview"
    
  3. Quando lo stato riflette Registrato, aggiornare la registrazione del provider di risorse Microsoft.ContainerService usando il comando az provider register.

    az provider register --namespace Microsoft.ContainerService
    

Limitare le chiamate di sistema del contenitore con seccomp

1. Seguire i passaggi per applicare un profilo seccomp nella configurazione di kubelet specificando "seccompDefault": "RuntimeDefault".

RuntimeDefault usa il profilo seccomp predefinito di containerd, limitando determinate chiamate di sistema per migliorare la sicurezza. Le chiamate di sistema con restrizioni avranno esito negativo. Per altre informazioni, vedere il profilo seccomp predefinito containerD.

2. Verificare che la configurazione sia stata applicata.

È possibile verificare che le impostazioni vengano applicate ai nodi connettendosi all'host e verificando che nel file system siano state apportate modifiche alla configurazione.

3. Risolvere gli errori del carico di lavoro.

Quando SeccompDefault è abilitato, il profilo seccomp predefinito del runtime del contenitore viene usato per impostazione predefinita per tutti i carichi di lavoro pianificati nel nodo. Ciò potrebbe causare un errore dei carichi di lavoro a causa di chiamate di sistema bloccate. Se si è verificato un errore del carico di lavoro, è possibile che vengano visualizzati errori come:

  • Il carico di lavoro è esistente in modo imprevisto dopo l'abilitazione della funzionalità, con errore "autorizzazione negata".
  • I messaggi di errore seccomp possono essere visualizzati anche in auditd o syslog sostituendo SCMP_ACT_ERRNO con SCMP_ACT_LOG nel profilo predefinito.

Se si verificano gli errori precedenti, è consigliabile modificare il profilo seccomp in Unconfined. Unconfined non applica restrizioni alle chiamate di sistema, consentendo tutte le chiamate di sistema, riducendo così la sicurezza.

Configurare un profilo seccomp personalizzato

Con un profilo seccomp personalizzato, è possibile avere un controllo più granulare sulle chiamate di sistema con restrizioni. Allineare alla procedura consigliata di concedere al contenitore l'autorizzazione minima solo per l'esecuzione da:

  • Definizione con filtra le azioni da consentire o negare.
  • Annotazione all'interno di un manifesto YAML del pod da associare al filtro seccomp.

Per una dimostrazione di seccomp in azione, creare un filtro che impedisce di cambiare le autorizzazioni su un file.

  1. Connettersi tramite SSH a un nodo del servizio Azure Kubernetes.

  2. Creare un filtro seccomp denominato /var/lib/kubelet/seccomp/prevent-chmod.

  3. Copiare e incollare il contenuto seguente:

    {
      "defaultAction": "SCMP_ACT_ALLOW",
      "syscalls": [
        {
          "name": "chmod",
          "action": "SCMP_ACT_ERRNO"
        },
        {
          "name": "fchmodat",
          "action": "SCMP_ACT_ERRNO"
        },
        {
          "name": "chmodat",
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    }
    

    Nella versione 1.19 e successive è necessario configurare:

    {
      "defaultAction": "SCMP_ACT_ALLOW",
      "syscalls": [
        {
          "names": ["chmod","fchmodat","chmodat"],
          "action": "SCMP_ACT_ERRNO"
        }
      ]
    }
    
  4. Dal computer locale creare un manifesto pod denominato aks-seccomp.yaml e incollare il contenuto seguente. Questo manifesto:

    • Definisce un'annotazione per seccomp.security.alpha.kubernetes.io.
    • Fa riferimento al filtro di prevent-chmod creato nel passaggio precedente.
    apiVersion: v1
    kind: Pod
    metadata:
      name: chmod-prevented
      annotations:
        seccomp.security.alpha.kubernetes.io/pod: localhost/prevent-chmod
    spec:
      containers:
      - name: chmod
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command:
          - "chmod"
        args:
         - "777"
         - /etc/hostname
      restartPolicy: Never
    

    Nella versione 1.19 e successive è necessario configurare:

    apiVersion: v1
    kind: Pod
    metadata:
      name: chmod-prevented
    spec:
      securityContext:
        seccompProfile:
          type: Localhost
          localhostProfile: prevent-chmod
      containers:
      - name: chmod
        image: mcr.microsoft.com/dotnet/runtime-deps:6.0
        command:
          - "chmod"
        args:
         - "777"
         - /etc/hostname
      restartPolicy: Never
    
  5. Distribuire il pod di esempio usando il comando kubectl apply:

    kubectl apply -f ./aks-seccomp.yaml
    
  6. Visualizzare lo stato del pod usando il comando kubectl get pods.

    • Il pod segnala un errore.
    • Il chmod comando non può essere eseguito dal filtro seccomp, come illustrato nell'output di esempio:
    kubectl get pods
    
    NAME                      READY     STATUS    RESTARTS   AGE
    chmod-prevented           0/1       Error     0          7s
    

Opzioni del profilo di sicurezza Seccomp

I profili di sicurezza Seccomp sono un set di chiamate di sistema definite consentite o limitate. La maggior parte dei runtime di contenitori ha un profilo seccomp predefinito simile se non uguale a quello usato da Docker. Per altre informazioni sui profili disponibili, vedere Profili seccomp predefiniti Docker o containerD .

Il servizio Azure Kubernetes usa il profilo seccomp predefinito containerD per RuntimeDefault quando si configura seccomp usando la configurazione personalizzata dei nodi.

Syscall significativi bloccati dal profilo predefinito

Sia Docker che containerD mantengono elenchi consentiti di chiamate syscall sicure. Questa tabella elenca le chiamate di sistema significative (ma non tutte) bloccate in modo efficace perché non sono presenti nell'elenco elementi consentiti. Se una delle chiamate di sistema bloccate è richiesta dal carico di lavoro, non usare il RuntimeDefault profilo seccomp.

Quando vengono apportate modifiche a Docker e containerD, il servizio Azure Kubernetes aggiorna la configurazione predefinita in modo che corrisponda. Gli aggiornamenti a questo elenco possono causare un errore del carico di lavoro. Per gli aggiornamenti delle versioni, vedere Note sulla versione del servizio Azure Kubernetes.

Syscall bloccato Descrizione
acct Syscall contabilità che potrebbe consentire ai contenitori di disabilitare i propri limiti di risorse o di elaborare la contabilità. Gestito anche da CAP_SYS_PACCT.
add_key Impedire ai contenitori di usare il keyring del kernel, che non è spazio dei nomi.
bpf Negare il caricamento di programmi bpf potenzialmente persistenti nel kernel, già controllata da CAP_SYS_ADMIN.
clock_adjtime L'ora e la data non sono spazi dei nomi. Gestito anche da CAP_SYS_TIME.
clock_settime L'ora e la data non sono spazi dei nomi. Gestito anche da CAP_SYS_TIME.
clone Negare la clonazione di nuovi spazi dei nomi. Anche gated by CAP_SYS_ADMIN for CLONE_* flags, ad eccezione CLONE_NEWUSERdi .
create_module Nega manipolazione e funzioni nei moduli del kernel. Obsoleta. Gestito anche da CAP_SYS_MODULE.
delete_module Nega manipolazione e funzioni nei moduli del kernel. Gestito anche da CAP_SYS_MODULE.
finit_module Nega manipolazione e funzioni nei moduli del kernel. Gestito anche da CAP_SYS_MODULE.
get_kernel_syms Nega il recupero dei simboli del kernel e del modulo esportati. Obsoleta.
get_mempolicy Syscall che modifica le impostazioni di memoria del kernel e NUMA. Già controllata da CAP_SYS_NICE.
init_module Nega manipolazione e funzioni nei moduli del kernel. Gestito anche da CAP_SYS_MODULE.
ioperm Impedire ai contenitori di modificare i livelli dei privilegi di I/O del kernel. Già controllata da CAP_SYS_RAWIO.
iopl Impedire ai contenitori di modificare i livelli dei privilegi di I/O del kernel. Già controllata da CAP_SYS_RAWIO.
kcmp Limitare le funzionalità di ispezione dei processi, già bloccate eliminando CAP_SYS_PTRACE.
kexec_file_load Sorella syscall di kexec_load che fa la stessa cosa, argomenti leggermente diversi. Gestito anche da CAP_SYS_BOOT.
kexec_load Negare il caricamento di un nuovo kernel per un'esecuzione successiva. Gestito anche da CAP_SYS_BOOT.
keyctl Impedire ai contenitori di usare il keyring del kernel, che non è spazio dei nomi.
lookup_dcookie Chiamare syscall di traccia/profilatura, che potrebbe causare perdite di informazioni sull'host. Gestito anche da CAP_SYS_ADMIN.
mbind Syscall che modifica le impostazioni di memoria del kernel e NUMA. Già controllata da CAP_SYS_NICE.
mount Nega montaggio, già gestito da CAP_SYS_ADMIN.
move_pages Syscall che modifica le impostazioni di memoria del kernel e NUMA.
nfsservctl Negare l'interazione con il daemon nfs del kernel. Obsoleto a partire da Linux 3.1.
open_by_handle_at Causa di un'interruzione del contenitore precedente. Gestito anche da CAP_DAC_READ_SEARCH.
perf_event_open Chiamare syscall di traccia/profilatura, che potrebbe causare perdite di informazioni sull'host.
personality Impedire al contenitore di abilitare l'emulazione BSD. Non intrinsecamente pericoloso, ma scarsamente testato, potenziale per glivulni del kernel.
pivot_root Negare pivot_root, deve essere un'operazione con privilegi.
process_vm_readv Limitare le funzionalità di ispezione dei processi, già bloccate eliminando CAP_SYS_PTRACE.
process_vm_writev Limitare le funzionalità di ispezione dei processi, già bloccate eliminando CAP_SYS_PTRACE.
ptrace Chiamare syscall di traccia/profilatura. Bloccato nelle versioni del kernel Linux precedenti alla 4.8 per evitare il bypass seccomp. I processi arbitrari di traccia/profilatura sono già bloccati eliminando CAP_SYS_PTRACE, perché potrebbero perdere informazioni sull'host.
query_module Nega manipolazione e funzioni nei moduli del kernel. Obsoleta.
quotactl Quota syscall che potrebbe consentire ai contenitori di disabilitare i propri limiti di risorse o di elaborare la contabilità. Gestito anche da CAP_SYS_ADMIN.
reboot Non consentire ai contenitori di riavviare l'host. Gestito anche da CAP_SYS_BOOT.
request_key Impedire ai contenitori di usare il keyring del kernel, che non è spazio dei nomi.
set_mempolicy Syscall che modifica le impostazioni di memoria del kernel e NUMA. Già controllata da CAP_SYS_NICE.
setns Negare l'associazione di un thread a uno spazio dei nomi. Gestito anche da CAP_SYS_ADMIN.
settimeofday L'ora e la data non sono spazi dei nomi. Gestito anche da CAP_SYS_TIME.
stime L'ora e la data non sono spazi dei nomi. Gestito anche da CAP_SYS_TIME.
swapon Nega avvio/arresto dello scambio in file/dispositivo. Gestito anche da CAP_SYS_ADMIN.
swapoff Nega avvio/arresto dello scambio in file/dispositivo. Gestito anche da CAP_SYS_ADMIN.
sysfs Syscall obsoleto.
_sysctl Obsoleto, sostituito da /proc/sys.
umount Deve essere un'operazione con privilegi. Gestito anche da CAP_SYS_ADMIN.
umount2 Deve essere un'operazione con privilegi. Gestito anche da CAP_SYS_ADMIN.
unshare Negare la clonazione di nuovi spazi dei nomi per i processi. Gestito anche da CAP_SYS_ADMIN, ad eccezione di unshare --user.
uselib Chiamata di sistema precedente correlata alle librerie condivise, inutilizzata per molto tempo.
userfaultfd Gestione degli errori delle pagine nello spazio utente, in gran parte necessaria per la migrazione dei processi.
ustat Syscall obsoleto.
vm86 Nella macchina virtuale in modalità reale x86 del kernel. Gestito anche da CAP_SYS_ADMIN.
vm86old Nella macchina virtuale in modalità reale x86 del kernel. Gestito anche da CAP_SYS_ADMIN.

Passaggi successivi

Per le procedure consigliate associate, vedere Procedure consigliate per la sicurezza e gli aggiornamenti del cluster nel servizio Azure Kubernetes e Procedure consigliate per la sicurezza dei pod nel servizio Azure Kubernetes.