Ressourcen mutieren

Auf dieser Seite wird gezeigt, wie Sie Ressourcen mithilfe des Policy Controller mutieren. Durch Mutieren lassen sich z. B. Standardwerte festlegen. Beispielsweise können Sie ein Label für alle Ressourcen in einem bestimmten Namespace einfügen oder für die imagePullPolicy eines Pods standardmäßig den Wert Always festlegen, wenn dieser nicht bereits angegeben ist.

Mutation aktivieren

Console

Führen Sie die folgenden Schritte aus, um die Mutation zu aktivieren:

  1. Rufen Sie in der Google Cloud Console im Abschnitt Posture Management (Verwaltung des Sicherheitsstatus) die Seite GKE Enterprise-Richtlinie auf.

    Zur Richtlinie

  2. Wählen Sie in der Clustertabelle auf dem Tab Einstellungen in der Spalte Konfiguration bearbeiten die Option Bearbeiten aus.
  3. Maximieren Sie das Menü Policy Controller-Konfiguration bearbeiten.
  4. Klicken Sie das Kästchen Mutations-Webhook aktivieren an.
  5. Wählen Sie Änderungen speichern aus.

gcloud Policy Controller

Führen Sie den folgenden Befehl aus, um die Mutation zu aktivieren:

gcloud container fleet policycontroller update \
    --memberships=MEMBERSHIP_NAME \
    --mutation

Ersetzen Sie MEMBERSHIP_NAME durch den Mitgliedsnamen des registrierten Clusters, um die Mutation zu aktivieren. Du kannst mehrere Mitgliedschaften angeben, die durch ein Komma getrennt sind.

gcloud ConfigManagement

Eine Mutation muss durch Festlegen des Werts true für spec.policyController.mutation.enabled in der Ressource config-management aktiviert werden:

apiVersion: configmanagement.gke.io/v1
kind: ConfigManagement
metadata:
  name: config-management
spec:
  policyController:
    enabled: true
     mutation:
      enabled: true 

Wenn Sie den gcloud CLI-Befehl verwenden, müssen Sie zur Aktivierung der Mutation die Alphaversion verwenden, wie im folgenden Beispiel gezeigt:

  # apply-spec.yaml

  applySpecVersion: 1
  spec:
    policyController:
      enabled: true
      mutationEnabled: true

Nachdem Sie die Datei apply-spec.yaml erstellt haben, führen Sie den folgenden Befehl aus, um die Konfiguration anzuwenden:

  gcloud alpha container fleet config-management apply \
      --membership=MEMBERSHIP_NAME \
      --config=CONFIG_YAML_PATH \
      --project=PROJECT_ID

Ersetzen Sie Folgendes:

  • MEMBERSHIP_NAME: Name der Mitgliedschaft des registrierten Clusters mit den Policy Controller-Einstellungen, die Sie verwenden möchten
  • CONFIG_YAML_PATH: Pfad zur Datei apply-spec.yaml
  • PROJECT_ID: Ihre Projekt-ID.

Definitionen

  • mutator: Eine Kubernetes-Ressource für die Konfiguration des Mutationsverhaltens des Policy Controller.
  • system: Eine Anordnung mehrerer Mutatoren.

Mutationsbeispiel

Das folgende Beispiel zeigt einen Mutator, der imagePullPolicy für alle Container in allen Pods auf Always festlegt:

# set-image-pull-policy.yaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: "spec.containers[name: *].imagePullPolicy"
  parameters:
    assign:
      value: "Always"

In diesem Beispiel gibt es die standardmäßigen Kubernetes-Metadatenfelder (apiVersion, kind, metadata.name), aber in spec ist das Verhalten des Mutators konfiguriert.

spec.applyTo bindet den Mutator an die angegebenen Ressourcen. Wenn wir bestimmte Felder in einem Objekt ändern, definieren wir implizit auch das Schema dieses Objekts. Beispielsweise ist die Anwendung des aktuellen Mutators auf die Namespace-Ressource nicht sinnvoll. Deshalb ist dieses Feld erforderlich, um für Policy Controller anzugeben, für welche Schemas dieser Mutator relevant sein soll. GroupVersionKinds, die in dieser Liste fehlen, werden nicht mutiert.

Mit spec.location wird festgelegt, welches Feld geändert werden soll. In diesem Fall wird ein Glob (*) verwendet, um anzugeben, dass alle Einträge in der Containerliste geändert werden. Die einzige Art von Listen, die vom Feld location geprüft werden können, sind Kartenlisten. Dabei muss das Schlüsselfeld für die Karte angegeben werden. Listen vom Typ "Karte" sind ein Kubernetes-Konstrukt. Weitere Informationen dazu finden Sie in der Kubernetes-Dokumentation.

spec.parameters.assign.value ist der Wert, der location zugewiesen werden soll. Dieses Feld hat keinen bestimmten Typ und kann beliebige Werte annehmen. Beachten Sie aber, dass Kubernetes die Anfrage nach der Mutation weiterhin prüft. Wenn Werte mit einem falschen Schema für das Objekt eingefügt werden, das geändert wird, wird die Anfrage abgelehnt.

Mutatoren für Jobs verwenden

Wenn Sie einen Job oder CronJob konfigurieren, müssen Sie die Version und Gruppe separat angeben, wie im folgenden Beispiel gezeigt:

applyTo:
- groups: ["batch"]
  kind: ["Job"]
  versions: ["v1"]

Wenn Sie einen Mutator für Jobs verwenden, werden die vorhandenen Jobs nur dann geändert, wenn Sie sie bearbeiten. Durch das Ändern eines Jobs wird eine Anfrage an den Mutations-Webhook ausgelöst und dieser wird geändert.

Ablauf der Ausführung

Der wahrscheinlich wichtigste Aspekt von Kubernetes-Mutations-Webhooks ist die Verwendung der zugehörigen Richtlinie für den nochmaligen Aufruf, da die Ausgabe eines Mutators das Verhalten eines anderen Mutators ändern kann. Wenn Sie beispielsweise einen neuen Sidecar-Container hinzufügen, muss ein Mutator, der die Image-Pull-Richtlinie für alle Container festlegt, einen neuen Container mutieren.

In der Praxis bedeutet dies, dass für eine beliebige Anfrage der Mutations-Webhook eines Policy Controller mehr als einmal aufgerufen werden kann.

Zur Verringerung der Latenz wird der Policy Controller automatisch aufgerufen, um zusätzliche HTTP-Anfragen zu vermeiden. Dies bedeutet, dass die Sidecar-Einfügung und die Image-Pull-Richtlinie das erwartete Ergebnis haben.

Die Mutationsroutine des Policy Controller wird so lange aufgerufen, bis die Ressource "konvergiert", d. h. bis zusätzliche Iterationen keine Auswirkung mehr haben.

Syntax des Standorts

Für die Syntax des Standorts wird der Punktzugriff (.) zum Prüfen von Feldern verwendet. Bei zugeordneten Listen können Nutzer mithilfe der Syntax [<key>: <value>] auf einzelne Objekte in einer Liste oder mit [<key>: *] auf alle Objekte in der Liste verweisen.

Werte und Felder können entweder in einfache (') oder in doppelte (") Anführungszeichen gesetzt werden. Das ist erforderlich, wenn dafür Sonderzeichen wie Punkte oder Leerzeichen verwendet werden.

In Werten in Anführungszeichen können Sonderzeichen mit Escapezeichen in Form des Präfix \ versehen werden. "Use \" to escape and \\\" to escape" wird zu Use " to escape and \" to escape.

Im Folgenden finden Sie einige Beispiele für die Ressource v1/Pod:

  • spec.priority verweist auf spec.priority
  • spec.containers[name: "foo"].volumeMounts[mountPath: "/my/mount"].readOnly verweist auf das Feld readOnly der /my/mount-Bereitstellung des foo-Containers.
  • spec.containers[name: *].volumeMounts[mountPath: "/my/mount"].readOnly verweist auf das Feld readOnly der /my/mount-Bereitstellung aller Container.

Wenn Sie auf einen Standort verweisen, der derzeit für eine Ressource nicht vorhanden ist, wird dieser Standort standardmäßig erstellt. Dieses Verhalten kann über Pfadtests konfiguriert werden.

Pfadtests

Wie können Standardeinstellungen festgelegt werden, mit denen vermieden wird, dass ein bereits vorhandener Wert geändert wird? Beispielsweise kann /secure-mount für alle Container als schreibgeschützt festgelegt werden. Es soll aber kein /secure-mount erstellt werden, wenn er noch nicht vorhanden ist. Dies lässt sich jeweils über Pfadtests ausführen.

Im folgenden Beispiel wird eine Mutation von imagePullPolicy vermieden, wenn dieser Pfad bereits festgelegt ist:

# set-image-pull-policy.yaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: "spec.containers[name: *].imagePullPolicy"
  parameters:
    assign:
      value: "Always"
    pathTests:
    - subPath: "spec.containers[name: *].imagePullPolicy"
      condition: "MustNotExist"

Mit dem nächsten Beispiel wird das Erstellen eines leeren sidecar-Containers unterbunden, wenn er noch nicht vorhanden ist:

# set-image-pull-policy.yaml

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  location: 'spec.containers[name: "sidecar"].imagePullPolicy'
  parameters:
    assign:
      value: "Always"
    pathTests:
    - subPath: 'spec.containers[name: "sidecar"]'
      condition: "MustExist"

Bei Bedarf können mehrere Pfadtests angegeben werden.

subPath muss ein Präfix von oder gleich location sein.

Für condition sind nur die Werte MustExist und MustNotExist gültig.

Abgleich

Mutatoren ermöglichen auch einen Abgleich, wobei die gleichen Kriterien wie bei Einschränkungen verwendet werden.

Mutatoren

Derzeit gibt es zwei Arten von Mutatoren: Assign und AssignMetadata.

Assign

Assign kann jeden Wert außerhalb des Felds metadata einer Ressource ändern. Da alle GroupVersionKinds ein eindeutiges Schema haben, muss der Mutator an eine Reihe von bestimmten GroupVersionKinds gebunden sein.

Er hat das folgende Schema:

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: Assign
metadata:
  name: always-pull-image
spec:
  applyTo:
  - groups: [""]
    kinds: ["Pod"]
    versions: ["v1"]
  match:
    kinds: # redundant because of `applyTo`, but left in for consistency
      - apiGroups: ["*"]
        kinds: ["*"]
    namespaces: ["my-namespace"]
    scope: "Namespaced" # or "Cluster"
    excludedNamespaces: ["some-other-ns"]
    labelSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
    namespaceSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
  location: "spec.containers[name: *].imagePullPolicy"
  parameters:
    pathTests:
    - subPath: 'spec.containers[name: "sidecar"]' # must be a prefix of `location`
      condition: "MustExist" # or "MustNotExist"
    - subPath: "spec.containers[name: *].imagePullPolicy"
      condition: "MustNotExist"
    assign:
      value: "Always" # any type can go here, not just a string

AssignMetadata

Mit AssignMetadata können neue Metadatenlabels hinzugefügt werden. Der Wert vorhandener Metadatenlabels lässt sich damit aber nicht ändern. Andernfalls wäre es möglich, ein System von Mutatoren zu schreiben, die unbegrenzt rekursiv sind und zu einer Zeitüberschreitung bei Anfragen führen.

Da alle Ressourcen das gleiche metadata-Schema haben, muss nicht angegeben werden, auf welche Ressource AssignMetadata angewendet wird.

Da mit AssignMetadata keine umfangreichen Mutationen möglich sind, ist auch sein Schema etwas einfacher.

apiVersion: mutations.gatekeeper.sh/v1alpha1
kind: AssignMetadata
metadata:
  name: set-team-name
spec:
  match:
    kinds:
      - apiGroups: ["*"]
        kinds: ["*"]
    namespaces: ["my-namespace"]
    scope: "Namespaced" # or "Cluster"
    excludedNamespaces: ["some-other-ns"]
    labelSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
    namespaceSelector:
      matchLabels:
        mutate: "yes"
      matchExpressions:
      - key: "my-label"
        operator: "In" # or, "NotIn", "Exists", or "DoesNotExist"
        values: ["my-value"]
  location: "metadata.labels.team" # must start with `metadata.labels`
  parameters:
    assign:
      value: "Always" # any type can go here, not just a string

Best Practices

Kubernetes-Vorsichtsmaßnahmen

In der Kubernetes-Dokumentation sind wichtige Überlegungen zur Verwendung von Mutations-Webhooks aufgeführt. Da der Policy Controller als Kubernetes-Zulassungs-Webhook dient, gelten hier die entsprechenden Empfehlungen.

Die Mutationssyntax des Policy Controller ist so konzipiert, dass die Berücksichtigung der Anforderungen für die Ausführung bei Mutations-Webhooks, einschließlich Idempotenz, vereinfacht wird.

Schreibmutatoren

Atomarität

Es wird empfohlen, jeden Mutator so eigenständig wie möglich anzuwenden. Da für Kubernetes das Modell Eventual Consistency gilt, sollte ein Mutator nicht davon abhängig sein, dass ein zweiter Mutator erkannt wurde, um seinen Job ordnungsgemäß ausführen zu können. Wenn Sie beispielsweise einen Sidecar hinzufügen, fügen Sie ihn insgesamt hinzu und erstellen ihn nicht stückweise über mehrere Mutatoren.

Validierung

Wenn es eine Bedingung gibt, die erzwungen werden soll, ist zu empfehlen, dass der Mutator eine entsprechende Einschränkung hat. Diese sorgt dafür, dass Anfragen, die gegen Richtlinien verstoßen, abgelehnt werden, und bereits vorhandene Verstöße bei der Prüfung erkannt werden.

Notfallwiederherstellung

Die Mutation wird als mutierender Kubernetes-Webhook implementiert. Dieser kann auf die gleiche Weise wie der validierende Webhook beendet werden. Die relevante Ressource ist jedoch eine MutatingWebhookConfiguration namens gatekeeper-mutating-webhook-configuration.

Nächste Schritte