Pod-Sicherheitsrichtlinien mit Gatekeeper anwenden


Auf dieser Seite wird erläutert, wie die Sicherheitskontrollen auf Pod-Ebene auf Ihre Google Kubernetes Engine-Cluster (GKE) angewendet werden sollten.

Übersicht

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.

Neben der Erzwingung derselben Funktionen wie bei PodSecurityPolicies von Kubernetes kann Gatekeep außerdem:

  • 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).

Kubernetes Open-Source-Software (OSS) ist dabei, Kubernetes PodSecurityPolicies einzustellen. Google empfiehlt die Verwendung nicht mehr.

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.

Hinweis

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

Mit den folgenden Methoden können Sie die gcloud-Einstellungen festlegen:

  • Verwenden Sie gcloud init, wenn Sie die Standardeinstellungen ansehen möchten.
  • Verwenden Sie gcloud config, um Ihre Projekt-ID, Zone und Region individuell festzulegen.

gcloud init verwenden

Wenn Sie die Fehlermeldung One of [--zone, --region] must be supplied: Please specify location erhalten, führen Sie diesen Abschnitt aus.

  1. Führen Sie gcloud init aus und folgen Sie der Anleitung:

    gcloud init

    Wenn Sie SSH auf einem Remote-Server verwenden, können Sie mit dem Flag --console-only verhindern, dass mit dem Befehl ein Browserfenster geöffnet wird:

    gcloud init --console-only
  2. Folgen Sie der Anleitung, um gcloud zur Verwendung Ihres Google Cloud-Kontos zu autorisieren.
  3. Erstellen Sie eine neue Konfiguration oder wählen Sie eine vorhandene aus.
  4. Wählen Sie ein Google Cloud-Projekt aus.
  5. Wählen Sie eine Compute Engine-Standardzone für zonale Cluster oder eine Region für regionale oder Autopilot-Cluster aus.

gcloud config verwenden

  • Legen Sie Ihre standardmäßige Projekt-ID fest:
    gcloud config set project PROJECT_ID
  • Wenn Sie mit zonalen Clustern arbeiten, legen Sie die Standardzone für Compute Engine fest:
    gcloud config set compute/zone COMPUTE_ZONE
  • Wenn Sie mit Autopilot oder regionalen Clustern arbeiten, legen Sie die Compute-Standardregion fest:
    gcloud config set compute/region COMPUTE_REGION
  • Aktualisieren Sie gcloud auf die neueste Version:
    gcloud components update

Gatekeeper auf einem Cluster aktivieren

Sie können Gatekeeper in einem GKE-Cluster mit einer der folgenden Methoden aktivieren. Da diese Methoden im selben Cluster nicht gleichzeitig existieren, sollten Sie nur einen davon auswählen.

Anthos Config Management bietet Policy Controller, eine Richtlinien-Engine, die auf dem Open-Source-Projekt Gatekeeper basiert. Google empfiehlt die Verwendung von Anthos Config Management, da es gängige Probleme im Zusammenhang mit der Erzwingung von Richtlinien im großen Maßstab löst, einschließlich Policy-as-Code, Multi-Cluster-Unterstützung, Einbindung in Cloud Logging und der Funktion, die Konfiguration zu synchronisieren.

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

Google Cloud Marketplace verwenden

Gatekeeper ist auch als Kubernetes-Anwendung im Google Cloud Marketplace verfügbar. Gatekeeper kann entweder auf einem vorhandenen Cluster oder auf einem neu erstellten Cluster installiert werden.

Informationen zum Bereitstellen von Gatekeeper aus Cloud Marketplace finden Sie unter Anwendung aus Google Cloud Marketplace bereitstellen.

Einschränkungen und Einschränkungsvorlagen aktivieren

Im Gegensatz zu PodSecurityPolicy können Gatekeeper und seine Einschränkungsvorlagen 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"

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
    

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.