Dieses Dokument wurde mithilfe automatisierter maschineller Übersetzungstechnologie übersetzt. Wir bemühen uns um korrekte Übersetzungen, übernehmen jedoch keine Gewähr für die Vollständigkeit, Richtigkeit oder Zuverlässigkeit der übersetzten Inhalte. Im Falle von Abweichungen ist die englische Originalversion maßgebend und stellt den verbindlichen Text dar.

Dies ist eine unveröffentlichte Dokumentation für Admission Controller 1.34-dev.

Verwendung von Pod-Sicherheitszulassung mit SUSE Security Admission Controller

Pod-Sicherheitsrichtlinien (PSP) wurden seit der Kubernetes-Version 1.25 entfernt. Sie werden durch die Pod-Sicherheitszulassung (PSA) ersetzt.

Die PSA vereinfacht die Sicherung der Pods in Kubernetes-Clustern.

Die PSA hat drei Profile (beschrieben in den Pod-Sicherheitsstandards) für Namespaces:

  • privilegiert, das die breiteste Palette von Berechtigungen bietet

  • Basislinie, um neue Privilegieneskalationen zu verhindern

  • eingeschränkt, um Pods zu härten

Ein PSA-Controller führt Aktionen bei der Erkennung von Verstößen durch. Die Aktionen sind: enforce, audit und warn. Sie können konfiguriert werden.

Zum Zeitpunkt des Schreibens, mit Kubernetes 1.28, hat der PSA-Controller die folgenden Einschränkungen:

  • Keine Mutationsfähigkeiten

  • Höhere Objekte (wie Deployment, Job) werden nur bewertet, wenn die audit oder warn Modi aktiviert sind

Admission Controller kann verwendet werden, um ein PSA-Profil zu integrieren und so diese Einschränkungen zu vermeiden.

Sie könnten Admission Controller verwenden, um die alte PSP-Konfiguration zu ersetzen, wie in PSP-Migration gezeigt. Das Ziel dieses Artikels ist es jedoch zu zeigen, wie Admission Controller die neue PSA ergänzen kann.

Beispiel

In diesem Beispiel erstellen wir einen Namespace und wenden restriktive PSA-Richtlinien an:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: v1.25
EOF

Dieses PSA-Profil erlaubt es nicht, Container zu erstellen, die ihre Anwendung als den root Benutzer ausführen. Bei der Definition dieses Containers:

  • muss das runAsNonRoot Attribut auf true gesetzt werden.

  • das runAsUser kann nicht auf 0 gesetzt werden.

Daher wird die folgende Ressource ihren gewünschten Zustand nicht erreichen:

kubectl Befehl zur Konfiguration einer Ressource mit runAsUser: 0 (markiert als ➀)
kubectl apply -n my-namespace -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: template-nginx
  template:
    metadata:
      labels:
        app: template-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        securityContext:
          runAsNonRoot: true
          runAsUser: 0 (1)
          allowPrivilegeEscalation: false
          capabilities:
            drop:
              - "ALL"
          seccompProfile:
            type: "RuntimeDefault"
        ports:
        - containerPort: 80
EOF
1 runAsUser: 0

Wenn wir die Bereitstellung überprüfen, können wir sehen, dass die PSA die Erstellung des Pods verhindert:

kubectl get deploy -n my-namespace nginx-deployment -o json | jq ".status.conditions[] | select(.reason == \"FailedCreate\")"
{
  "lastTransitionTime": "2022-10-28T19:09:56Z",
  "lastUpdateTime": "2022-10-28T19:09:56Z",
  "message": "pods \"nginx-deployment-5f98b4db8c-2m96l\" is forbidden: violates PodSecurity \"restricted:v1.25\": runAsUser=0 (container \"nginx\" must not set runAsUser=0)",
  "reason": "FailedCreate",
  "status": "True",
  "type": "ReplicaFailure"
}

Sie können dies beheben, indem Sie das runAsUser: 0 aus der Container-Definition entfernen:

kubectl Befehl zur Konfiguration einer Ressource ohne runAsUser: 0
kubectl apply -n my-namespace -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: template-nginx
  template:
    metadata:
      labels:
        app: template-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        securityContext:
          runAsNonRoot: true
          allowPrivilegeEscalation: false
          capabilities:
            drop:
              - "ALL"
          seccompProfile:
            type: "RuntimeDefault"

        ports:
        - containerPort: 80
EOF

Jetzt erlaubt die PSA einen Versuch zur Erstellung des Pods, aber es schlägt immer noch fehl.

kubectl get pods -n my-namespace
NAME                                READY   STATUS                       RESTARTS   AGE
nginx-deployment-57d8568bbb-h4bx7   0/1     CreateContainerConfigError   0          47s

Das liegt daran, dass die Containerdefinition keinen Benutzer angegeben hat, der beim Starten eines Programms im Container verwendet werden soll. Der Standard ist, als Root-Benutzer auszuführen, wenn dies der Fall ist. Das ist durch die runAsNonRoot Direktive nicht erlaubt:

kubectl get pods -n my-namespace nginx-deployment-57d8568bbb-h4bx7 -o json | jq ".status.containerStatuses"
[
  {
    "image": "nginx:1.14.2",
    "imageID": "",
    "lastState": {},
    "name": "nginx",
    "ready": false,
    "restartCount": 0,
    "started": false,
    "state": {
      "waiting": {
        "message": "container has runAsNonRoot and image will run as root (pod: \"nginx-deployment-57d8568bbb-8mvkc_my-namespace(add7bcc5-3d23-43d0-94e9-6e78f887a53f)\", container: nginx)",
        "reason": "CreateContainerConfigError"
      }
    }
  }
]

Hier kann Admission Controller helfen. Sie können die user-group-policy Richtlinie verwenden, um die Bereitstellungsdefinition zu ändern. Dies konfiguriert einen Standardbenutzer für Container, die diese Information weglassen.

Für dieses Beispiel benötigen Sie den Admission Controller Stack im Kubernetes-Cluster. Siehe die Quickstart-Anleitung für weitere Details.

Es ist möglich, einen Benutzer-ID-Bereich durchzusetzen, zum Beispiel 1000—​2000 und 4000—​5000:

kubectl-Befehl zur Durchsetzung eines Benutzer-ID-Bereichs
kubectl apply -f - <<EOF
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
  name: user-group-psp
spec:
  policyServer: default
  module: registry://ghcr.io/kubewarden/policies/user-group-psp:latest
  rules:
  - apiGroups: ["", "apps"]
    apiVersions: ["v1"]
    resources: ["pods", "deployments"]
    operations:
    - CREATE
    - UPDATE
  mutating: true
  settings:
    run_as_user:
      rule: "MustRunAs"
      overwrite: false
      ranges:
        - min: 1000
          max: 2000
        - min: 4000
          max: 5000
    run_as_group:
      rule: "RunAsAny"
    supplemental_groups:
      rule: "RunAsAny"
EOF

Überprüfen Sie, ob die Richtlinie aktiv ist, bevor Sie fortfahren:

kubectl get clusteradmissionpolicy.policies.kubewarden.io/user-group-psp

Wenn die Richtlinie aktiv ist, erstellen Sie die Bereitstellung erneut:

kubectl-Befehl zur erneuten Erstellung der Bereitstellung
kubectl delete deployment -n my-namespace nginx-deployment && \
kubectl apply -n my-namespace -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: template-nginx
  template:
    metadata:
      labels:
        app: template-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        securityContext:
          runAsNonRoot: true
          allowPrivilegeEscalation: false
          capabilities:
            drop:
              - "ALL"
          seccompProfile:
            type: "RuntimeDefault"

        ports:
        - containerPort: 80
EOF

Jetzt wird die Bereitstellung durch die Richtlinie von Admission Controller verändert, die es erlaubt, dass der Pod gestartet wird. Der im Pod definierte Container hat einen Standardwert von runAsUser:

kubectl get pods -n my-namespace nginx-deployment-57d8568bbb-nv8fj -o json | jq ".spec.containers[].securityContext"
{
  "allowPrivilegeEscalation": false,
  "capabilities": {
    "drop": [
      "ALL"
    ]
  },
  "runAsNonRoot": true,
  "runAsUser": 1000,
  "seccompProfile": {
    "type": "RuntimeDefault"
  }
}

Die Admission Controller-Integration kann in diesem Szenario mehr tun. Es kann den Wert des bereitgestellten runAsUser überprüfen.

Diese Ressource wird von der vorherigen Admission Controller-Richtlinie abgelehnt:

kubectl-Befehl zur Anzeige der Ressourcenablehnung
kubectl apply -n my-namespace -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment2
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: template-nginx
  template:
    metadata:
      labels:
        app: template-nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        securityContext:
          runAsNonRoot: true
          runAsUser: 7000 (1)
          allowPrivilegeEscalation: false
          capabilities:
            drop:
              - "ALL"
          seccompProfile:
            type: "RuntimeDefault"
        ports:
        - containerPort: 80
EOF
1 runAsUser: 7000

Es wird abgelehnt, weil der runAsUser-Wert auf 7000 gesetzt ist, was außerhalb der von der Richtlinie erlaubten Bereiche liegt:

kubectl get deploy -n my-namespace nginx-deployment -o json | jq ".status.conditions[] | select(.reason == \"FailedCreate\")"
{
  "lastTransitionTime": "2022-10-28T19:22:04Z",
  "lastUpdateTime": "2022-10-28T19:22:04Z",
  "message": "admission webhook \"clusterwide-user-group-psp.kubewarden.admission\" denied the request: User ID outside defined ranges",
  "reason": "FailedCreate",
  "status": "True",
  "type": "ReplicaFailure"
}

Zusammenfassung

PSA bietet eine einfache Möglichkeit, Kubernetes-Cluster abzusichern. Das Hauptziel von PSA ist Einfachheit, und es hat nicht die Macht und Flexibilität der früheren PSP.

Die Verwendung von Admission Controller zusammen mit PSA hilft, diese Lücke zu schließen.