Applica criteri di sicurezza personalizzati a livello di pod utilizzando Gatekeeper


Questa pagina mostra come utilizzare il controller di ammissione Gatekeeper per applicare controlli di sicurezza a livello di pod ai cluster Google Kubernetes Engine (GKE).

Panoramica

Gatekeeper è un controller di ammissione che convalida le richieste di creazione e aggiornamento di pod sui cluster Kubernetes, utilizzando Open Policy Agent (OPA).

L'uso di Gatekeeper consente agli amministratori di definire criteri mediante un vincolo, ovvero un insieme di condizioni che consentono o negano i comportamenti di deployment in Kubernetes. Puoi quindi applicare questi criteri su un cluster utilizzando un ConstraintTemplate. Questo documento fornisce esempi per limitare le funzionalità di sicurezza dei carichi di lavoro al fine di garantire l'applicazione, il test e l'audit dei criteri di sicurezza utilizzando Gatekeeper.

Il gatekeeper può inoltre:

  • Implementazione dei criteri: applica i criteri in modo graduale e limitato per limitare il rischio di interrompere i carichi di lavoro.
  • Modifiche ai criteri di prova: fornisci meccanismi per testare l'impatto dei criteri e l'intervallo prima dell'applicazione.
  • Controlla i criteri esistenti: assicurati che l'applicazione dei controlli di sicurezza a carichi di lavoro nuovi ed esistenti (controlli di controllo).

Concetti

Gatekeeper introduce due concetti per fornire agli amministratori mezzi potenti e flessibili per controllare il cluster: i vincoli e i modelli di vincolo, entrambi concetti ereditati dal framework dei vincoli Open Policy Agent.

I vincoli sono la rappresentazione del criterio di sicurezza, in quanto definiscono i requisiti e l'intervallo di applicazione. I modelli di vincolo sono istruzioni riutilizzabili (scritte in Rego) che applicano logica per valutare campi specifici negli oggetti Kubernetes, in base ai requisiti definiti nei vincoli.

Ad esempio, potresti avere un vincolo che dichiara i profili seccomp consentiti che possono essere applicati ai pod in uno spazio dei nomi specifico e un modello di vincolo paragonabile che fornisce la logica per l'estrazione di questi valori e l'applicazione della gestione.

Il seguente modello di vincolo, dal repository Gatekeeper, verifica l'esistenza di securityContext.privileged nella specifica di un pod:

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8spspprivilegedcontainer
spec:
  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8spspprivileged

        violation[{"msg": msg, "details": {}}] {
            c := input_containers[_]
            c.securityContext.privileged
            msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
        }
        input_containers[c] {
            c := input.review.object.spec.containers[_]
        }
        input_containers[c] {
            c := input.review.object.spec.initContainers[_]
        }

Per estendere il modello di vincolo precedente, il seguente vincolo definisce l'ambito (kinds) per l'applicazione specifica di questo modello di vincolo in modalità dryrun:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: psp-privileged-container
spec:
  enforcementAction: dryrun
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]

Con Gatekeeper, puoi creare i tuoi vincoli e modelli di vincolo per soddisfare le tue esigenze specifiche. Puoi inoltre utilizzare un insieme standard di vincoli e modelli di vincoli nel repository Gatekeeper che sono stati definiti per consentire l'adozione e l'applicazione della sicurezza rapide. Ogni vincolo è anche accompagnato da configurazioni di pod di esempio.

Google Cloud fornisce una versione gestita e ufficialmente supportata del Gatekeeper open source denominata Policy Controller. Google non supporta ufficialmente il progetto Gatekeeper open source.

Prima di iniziare

Prima di iniziare, assicurati di aver eseguito le seguenti attività:

  • Abilita l'API Google Kubernetes Engine.
  • Abilita l'API Google Kubernetes Engine
  • Se vuoi utilizzare Google Cloud CLI per questa attività, installa e initialize gcloud CLI. Se hai già installato gcloud CLI, scarica la versione più recente eseguendo gcloud components update.

Abilita il gatekeeper su un cluster con Policy Controller

Policy Controller è un motore dei criteri basato sul progetto open source Gatekeeper. Google consiglia l'utilizzo di Policy Controller perché include funzionalità aggiuntive per aiutare ad applicare i criteri su larga scala, tra cui Policy as Code, supporto multi-cluster, l'integrazione con Cloud Logging e la possibilità di visualizzare lo stato dei criteri nella console Google Cloud. Policy Controller è disponibile con una licenza della versione Google Kubernetes Engine (GKE) Enterprise, ma puoi installare Gatekeeper sul cluster.

Per abilitare Policy Controller su un cluster, segui la guida all'installazione di Policy Controller.

Abilita vincoli e modelli di vincoli

Il gatekeeper e i relativi modelli di vincolo possono essere installati e abilitati senza influire negativamente sui carichi di lavoro esistenti o nuovi. Per questo motivo, è consigliabile applicare al cluster tutti i modelli di vincolo di sicurezza dei pod applicabili.

Inoltre, i vincoli del gatekeeper possono essere implementati per applicare controlli per oggetti specifici, come spazi dei nomi e pod.

Osserva l'esempio riportato di seguito, che limita l'ambito ai pod che si trovano nello spazio dei nomi production, definendoli nell'istruzione di corrispondenza del vincolo:

...
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
    namespaces:
      - "production"

Per ulteriori informazioni sulle opzioni disponibili per gli oggetti Constraint e ConstraintTemplate, consulta Come utilizzare Gatekeeper.

Norme per i test

L'introduzione di nuovi criteri nei cluster esistenti può avere comportamenti negativi, ad esempio limitando i carichi di lavoro esistenti. Uno dei vantaggi dell'utilizzo di Gatekeeper per la sicurezza dei pod è la possibilità di testare l'efficacia e l'impatto di un criterio senza apportare modifiche effettive, utilizzando una modalità di prova. Ciò consente di testare la configurazione dei criteri rispetto ai cluster in esecuzione senza applicazione forzata. Le violazioni delle norme vengono registrate e identificate senza interferenze.

I seguenti passaggi mostrano in che modo uno sviluppatore, un operatore o un amministratore può applicare modelli e vincoli di vincoli per determinarne l'efficacia o il potenziale impatto:

  1. Applica la configurazione gatekeeper per la replica dei dati per le funzionalità di controllo e prova:

    kubectl create -f- <<EOF
    apiVersion: config.gatekeeper.sh/v1alpha1
    kind: Config
    metadata:
      name: config
      namespace: "gatekeeper-system"
    spec:
      sync:
        syncOnly:
          - group: ""
            version: "v1"
            kind: "Namespace"
          - group: ""
            version: "v1"
            kind: "Pod"
    EOF
    
  2. Senza vincoli applicati, eseguiamo un carico di lavoro con privilegi elevati:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    
  3. Carica il modello di vincolo k8spspprivilegedcontainer menzionato sopra:

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  4. Ora creiamo un nuovo vincolo per estendere questo modello. Questa volta imposteremo enforcementAction su dryrun:

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      enforcementAction: dryrun
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  5. Con Gatekeeper che sincronizza i dati degli oggetti in esecuzione e controlla passivamente la presenza di violazioni, possiamo confermare se sono state rilevate violazioni controllando il status del vincolo:

    kubectl get k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container -o yaml
    
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
    ...
     name: psp-privileged-container
    ...
    spec:
     enforcementAction: dryrun
     match:
       kinds:
       - apiGroups:
         - ""
         kinds:
         - Pod
    status:
     auditTimestamp: "2019-12-15T22:19:54Z"
     byPod:
     - enforced: true
       id: gatekeeper-controller-manager-0
     violations:
     - enforcementAction: dryrun
       kind: Pod
       message: 'Privileged container is not allowed: nginx, securityContext: {"privileged":
         true}'
       name: nginx
       namespace: default
    
  6. Eseguiamo un altro pod con privilegi per confermare che il criterio non interferisce con i deployment:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: privpod
      labels:
        app: privpod
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    Il deployment di questo nuovo pod verrà eseguito correttamente.

  7. Per eseguire la pulizia delle risorse create in questa sezione, esegui questi comandi:

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    kubectl delete pod/nginx
    kubectl delete pod/privpod
    

Applicazione delle norme

Ora che possiamo confermare la validità e l'impatto di un criterio senza influire sui carichi di lavoro nuovi o esistenti, implementiamo un criterio con applicazione completa.

Basati sugli esempi utilizzati per convalidare i criteri riportati sopra, i passaggi seguenti mostrano in che modo uno sviluppatore, un operatore o un amministratore può applicare modelli di vincoli e vincoli per applicare un criterio:

  1. Carica il modello di vincolo k8spspprivilegedcontainer menzionato in precedenza:

    kubectl create -f- <<EOF
    apiVersion: templates.gatekeeper.sh/v1beta1
    kind: ConstraintTemplate
    metadata:
      name: k8spspprivilegedcontainer
    spec:
      crd:
        spec:
          names:
            kind: K8sPSPPrivilegedContainer
      targets:
        - target: admission.k8s.gatekeeper.sh
          rego: |
            package k8spspprivileged
    
            violation[{"msg": msg, "details": {}}] {
                c := input_containers[_]
                c.securityContext.privileged
                msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext])
            }
            input_containers[c] {
                c := input.review.object.spec.containers[_]
            }
            input_containers[c] {
                c := input.review.object.spec.initContainers[_]
            }
    EOF
    
  2. Ora creiamo un nuovo vincolo per estendere questo modello. Questa volta non imposteremo la chiave enforcementAction. Per impostazione predefinita, la chiave enforcementAction è impostata su deny:

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  3. Prova a eseguire il deployment di un container che dichiara le autorizzazioni con privilegi:

    kubectl create -f- <<EOF
    apiVersion: v1
    kind: Pod
    metadata:
      name: nginx
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        securityContext:
          privileged: true
    EOF
    

    Dovresti ricevere il seguente messaggio di errore:

    Error from server ([denied by psp-privileged-container] Privileged container is not allowed:
    nginx, securityContext: {"privileged": true}): error when creating "STDIN": admission webhook "validation.gatekeeper.sh" denied the request: [denied by psp-privileged-container]
    Privileged container is not allowed: nginx, securityContext: {"privileged": true}
    
  4. Per eseguire la pulizia, esegui questi comandi:

    kubectl delete k8spspprivilegedcontainer.constraints.gatekeeper.sh/psp-privileged-container
    kubectl delete constrainttemplate k8spspprivilegedcontainer
    

Alternative al gatekeeper

Il gatekeeper ti consente di dichiarare e applicare criteri di sicurezza personalizzati a livello di pod. Puoi anche utilizzare il controller di ammissione PodSecurity integrato di Kubernetes per applicare criteri di sicurezza predefiniti a livello di pod. Questi criteri predefiniti sono allineati ai livelli definiti dai Pod Security Standards.

Passaggi successivi

Gatekeeper offre uno strumento incredibilmente potente per applicare e convalidare la sicurezza sui cluster GKE utilizzando criteri dichiarativi. Tuttavia, l'utilizzo da parte dei gatekeeper va oltre la sicurezza e può essere utilizzato in altri aspetti dell'amministrazione e delle operazioni.