Benutzerdefinierte Sicherheitsrichtlinien auf Pod-Ebene mit Gatekeeper anwenden


Auf dieser Seite erfahren Sie, wie Sie mit dem Gatekeeper-Admission-Controller Sicherheitskontrollen auf Pod-Ebene auf Ihre GKE-Cluster (Google Kubernetes Engine) anwenden.

Überblick

Gatekeeper ist ein Admission-Controller, der Anfragen zum Erstellen und Aktualisieren von Pods in Kubernetes-Clustern mithilfe von Open Policy Agent (OPA) validiert.

Mit Gatekeeper können Administratoren Richtlinien mit einer Einschränkung definieren. Hierbei handelt es sich um eine Gruppe von Bedingungen, die das Deployment-Verhalten in Kubernetes zulassen oder ablehnen. Anschließend können Sie diese Richtlinien mithilfe von ConstraintTemplate für einen Cluster erzwingen. Dieses Dokument enthält Beispiele zur Beschränkung der Sicherheitsfunktionen von Arbeitslasten, um Sicherheitsrichtlinien, Tests und Audit-Logs von Gatekeeper zu erzwingen.

Gatekeeper kann auch:

  • Richtlinien einführen: Sie können Richtlinien auf allmähliche, begrenzte Weise erzwingen, um das Risiko einer Unterbrechung von Arbeitslasten zu begrenzen.
  • Richtlinienänderungen im Probelauf testen: Stellen Sie Mechanismen bereit, mit denen Sie die Auswirkungen und die Reichweite von Richtlinien vor deren Erzwingung testen können.
  • Vorhandene Richtlinien prüfen: Stellen Sie die Anwendung von Sicherheitskontrollen auf neue und bestehende Workloads sicher (Audit-Kontrollen).

Konzepte

Gatekeeper führt zwei Konzepte ein, um Administratoren ein leistungsfähiges und flexibles Mittel zur Steuerung ihres Clusters zur Verfügung zu stellen: Einschränkungen und Einschränkungsvorlagen, beides Konzepte, die vom Open Policy Agent Constraint Framework übernommen wurden.

Einschränkungen sind die Darstellung Ihrer Sicherheitsrichtlinie: Sie definieren die Anforderungen und den Bereich der Erzwingung. Einschränkungsvorlagen sind wiederverwendbare Anweisungen (geschrieben in Rego), die Logik anwenden, um bestimmte Felder in Kubernetes-Objekten anhand in Einschränkungen definierten Anforderungen auszuwerten.

Beispiel: Sie haben eine Einschränkung, die zulässige seccomp-Profile angibt, die auf Pods in einem bestimmten Namespace angewendet werden können, sowie eine vergleichbare Einschränkungsvorlage, die die Logik zum Extrahieren dieser Werte und zur Erzwingung bereitstellt.

Mit der folgenden Einschränkungsvorlage aus dem Gatekeeper-Repository wird in einer Pod-Spezifikation geprüft, ob securityContext.privileged vorhanden ist:

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[_]
        }

Um die obige Einschränkungsvorlage zu erweitern, wird mit der folgenden Einschränkung der Bereich (kinds) für die spezifische Erzwingung dieser Einschränkungsvorlage in einem dryrun-Modus definiert:

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

Mit Gatekeeper können Sie eigene Einschränkungen und Vorlagen für Beschränkungen erstellen, um Ihre speziellen Anforderungen zu erfüllen. Sie können auch im Gatekeeper-Repository einen Standardsatz von Einschränkungen und Einschränkungsvorlagen verwenden, die definiert wurden, um eine schnelle Übernahme und Sicherheitserzwingung zu ermöglichen. Zu jeder Einschränkung werden auch Beispiele für Pod-Konfigurationen hinzugefügt.

Google Cloud bietet eine verwaltete, offiziell unterstützte Version des Open-Source-Gatekeeper namens Policy Controller. Das Open-Source-Gatekeeper-Projekt wird von Google nicht offiziell unterstützt.

Hinweis

Führen Sie die folgenden Aufgaben aus, bevor Sie beginnen:

  • Aktivieren Sie die Google Kubernetes Engine API.
  • Google Kubernetes Engine API aktivieren
  • Wenn Sie die Google Cloud CLI für diese Aufgabe verwenden möchten, müssen Sie die gcloud CLI installieren und dann initialisieren. Wenn Sie die gcloud CLI bereits installiert haben, rufen Sie die neueste Version mit gcloud components update ab.

Gatekeeper in einem Cluster mit Policy Controller aktivieren

Policy Controller ist eine Richtlinien-Engine, die auf dem Open-Source-Projekt Gatekeeper basiert. Google empfiehlt die Verwendung von Policy Controller, da es zusätzliche Features enthält, um Richtlinien in großem Maßstab zu erzwingen, einschließlich Policy-as-Code, Multi-Cluster-Unterstützung, Einbindung in Cloud Logging und der Möglichkeit, {101 }Richtlinienstatus in der Google Cloud Console ansehen. Policy Controller ist mit einer GKE Enterprise Edition-Lizenz (Google Kubernetes Engine) verfügbar, aber Sie können stattdessen Gatekeeper auf Ihrem Cluster installieren.

Informationen zum Aktivieren von Policy Controller in einem Cluster finden Sie in der Installationsanleitung für Policy Controller.

Einschränkungen und Einschränkungsvorlagen aktivieren

Gatekeeper und seine Einschränkungsvorlagen können installiert und aktiviert werden, ohne vorhandene oder neue Arbeitslasten negativ zu beeinflussen. Aus diesem Grund wird empfohlen, alle anwendbaren Vorlagen zur Pod-Sicherheitseinschränkung auf den Cluster anzuwenden.

Darüber hinaus können Gatekeeper-Einschränkungen implementiert werden, um Steuerelemente für bestimmte Objekte wie Namespaces und Pods zu erzwingen.

Im folgenden Beispiel wird der Bereich auf Pods beschränkt, die sich im Namespace production befinden. Dazu werden sie in der Einschränkung „Match-Anweisung” definiert:

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

Weitere Informationen zu den verfügbaren Optionen für Constraint- und ConstraintTemplate-Objekte finden Sie unter Gatekeeper verwenden.

Richtlinien testen

Die Einführung neuer Richtlinien für vorhandene Cluster kann zu unerwünschtem Verhalten führen, z. B. durch das Begrenzen vorhandener Arbeitslasten. Einer der Vorteile der Verwendung von Gatekeeper für die Pod-Sicherheit ist die Möglichkeit, die Effektivität und den Einfluss einer Richtlinie zu testen, ohne dabei tatsächliche Änderungen vorzunehmen. Der Einsatz eines Probelaufmodus ist ebenfalls möglich. So kann die Richtlinienkonfiguration ohne Erzwingung für das Ausführen von Clustern getestet werden. Richtlinienverstöße werden protokolliert und identifiziert.

In den folgenden Schritten wird gezeigt, wie Entwickler, Operatoren oder Administratoren Einschränkungsvorlagen und Einschränkungen anwenden können, um deren Effektivität oder mögliche Auswirkungen zu ermitteln:

  1. Wenden Sie die Gatekeeper-Konfiguration an, um Daten für die Audit- und Probelauffunktionen zu replizieren:

    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. Wenn keine Einschränkungen gelten, führen wir eine Arbeitslast mit höheren Berechtigungen aus:

    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. Laden Sie die oben genannte Einschränkungsvorlage k8spspprivilegedcontainer:

    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. Erstellen wir nun eine neue Einschränkung, um diese Einschränkungsvorlage zu erweitern. Dieses Mal legen wir für enforcementAction den Wert dryrun fest:

    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. Da Gatekeeper die Daten des laufenden Objekts synchronisiert und passiv auf Verstöße prüft, können wir bestätigen, ob Verstöße gefunden wurden, indem wir den status der Einschränkung prüfen:

    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. Führen Sie einen weiteren privilegierten Pod aus, um zu prüfen, ob die Richtlinie sich nicht mit Deployments überschneidet:

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

    Dieser neue Pod wird bereitgestellt.

  7. Führen Sie die folgenden Befehle aus, um die in diesem Abschnitt erstellten Ressourcen zu bereinigen:

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

Richtlinien durchsetzen

Da wir nun überprüfen können, ob eine Richtlinie gültig und relevant ist, ohne dass sich dies auf bestehende oder neue Arbeitslasten auswirkt, werden wir jetzt eine Richtlinie mit vollständiger Erzwingung implementieren.

Anhand der Beispiele, die oben zur Validierung der Richtlinie verwendet wurden, demonstrieren die folgenden Schritte, wie ein Entwickler, Bediener oder Administrator Einschränkungsvorlagen und Einschränkungen anwenden kann, um eine Richtlinie zu erzwingen:

  1. Laden Sie die zuvor erwähnte Einschränkungsvorlage k8spspprivilegedcontainer:

    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. Erstellen wir nun eine neue Einschränkung, um diese Einschränkungsvorlage zu erweitern. Dieses Mal wird der Schlüssel enforcementAction nicht festgelegt. Standardmäßig ist der Schlüssel enforcementAction auf deny eingestellt.

    kubectl create -f- <<EOF
    apiVersion: constraints.gatekeeper.sh/v1beta1
    kind: K8sPSPPrivilegedContainer
    metadata:
      name: psp-privileged-container
    spec:
      match:
        kinds:
          - apiGroups: [""]
            kinds: ["Pod"]
    EOF
    
  3. Versuchen Sie, einen Container bereitzustellen, in dem Berechtigungen erteilt werden:

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

    Folgende Fehlermeldung sollte empfangen werden:

    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. Führen Sie zum Bereinigen die folgenden Befehle aus:

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

Alternativen zu Gatekeeper

Mit Gatekeeper können Sie benutzerdefinierte Sicherheitsrichtlinien auf Pod-Ebene deklarieren und anwenden. Sie können auch den in Kubernetes integrierten PodSecurity-Admission-Controller verwenden, um vordefinierte Sicherheitsrichtlinien auf Pod-Ebene anzuwenden. Diese vordefinierten Richtlinien entsprechen den Ebenen, die durch die Pod-Sicherheitsstandards definiert sind.

Nächste Schritte

Gatekeeper bietet eine äußerst effektive Möglichkeit, die Sicherheit auf GKE-Clustern mithilfe deklarativer Richtlinien zu erzwingen und zu validieren. Der Einsatz von Gatekeeper erstreckt sich allerdings über die Sicherheit hinaus und kann in anderen Aspekten der Verwaltung und des Betriebs verwendet werden.