Apply Pod Security Standards at the Cluster Level

Note

This tutorial applies only for new clusters.

Pod Security is an admission controller that carries out checks against the Kubernetes Pod Security Standards when new pods are created. It is a feature GA’ed in v1.25. This tutorial shows you how to enforce the baseline Pod Security Standard at the cluster level which applies a standard configuration to all namespaces in a cluster.

To apply Pod Security Standards to specific namespaces, refer to Apply Pod Security Standards at the namespace level.

If you are running a version of Kubernetes other than v1.29, check the documentation for that version.

Before you begin

Install the following on your workstation:

This tutorial demonstrates what you can configure for a Kubernetes cluster that you fully control. If you are learning how to configure Pod Security Admission for a managed cluster where you are not able to configure the control plane, read Apply Pod Security Standards at the namespace level.

Choose the right Pod Security Standard to apply

Pod Security Admission lets you apply built-in Pod Security Standards with the following modes: enforce, audit, and warn.

To gather information that helps you to choose the Pod Security Standards that are most appropriate for your configuration, do the following:

  1. Create a cluster with no Pod Security Standards applied:

    1. kind create cluster --name psa-wo-cluster-pss

    The output is similar to:

    1. Creating cluster "psa-wo-cluster-pss" ...
    2. Ensuring node image (kindest/node:v1.29.0) 🖼
    3. Preparing nodes 📦
    4. Writing configuration 📜
    5. Starting control-plane 🕹️
    6. Installing CNI 🔌
    7. Installing StorageClass 💾
    8. Set kubectl context to "kind-psa-wo-cluster-pss"
    9. You can now use your cluster with:
    10. kubectl cluster-info --context kind-psa-wo-cluster-pss
    11. Thanks for using kind! 😊
  2. Set the kubectl context to the new cluster:

    1. kubectl cluster-info --context kind-psa-wo-cluster-pss

    The output is similar to this:

    1. Kubernetes control plane is running at https://127.0.0.1:61350
    2. CoreDNS is running at https://127.0.0.1:61350/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    3. To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
  3. Get a list of namespaces in the cluster:

    1. kubectl get ns

    The output is similar to this:

    1. NAME STATUS AGE
    2. default Active 9m30s
    3. kube-node-lease Active 9m32s
    4. kube-public Active 9m32s
    5. kube-system Active 9m32s
    6. local-path-storage Active 9m26s
  4. Use --dry-run=server to understand what happens when different Pod Security Standards are applied:

    1. Privileged

      1. kubectl label --dry-run=server --overwrite ns --all \
      2. pod-security.kubernetes.io/enforce=privileged

      The output is similar to:

      1. namespace/default labeled
      2. namespace/kube-node-lease labeled
      3. namespace/kube-public labeled
      4. namespace/kube-system labeled
      5. namespace/local-path-storage labeled
    2. Baseline

      1. kubectl label --dry-run=server --overwrite ns --all \
      2. pod-security.kubernetes.io/enforce=baseline

      The output is similar to:

      1. namespace/default labeled
      2. namespace/kube-node-lease labeled
      3. namespace/kube-public labeled
      4. Warning: existing pods in namespace "kube-system" violate the new PodSecurity enforce level "baseline:latest"
      5. Warning: etcd-psa-wo-cluster-pss-control-plane (and 3 other pods): host namespaces, hostPath volumes
      6. Warning: kindnet-vzj42: non-default capabilities, host namespaces, hostPath volumes
      7. Warning: kube-proxy-m6hwf: host namespaces, hostPath volumes, privileged
      8. namespace/kube-system labeled
      9. namespace/local-path-storage labeled
    3. Restricted

      1. kubectl label --dry-run=server --overwrite ns --all \
      2. pod-security.kubernetes.io/enforce=restricted

      The output is similar to:

      1. namespace/default labeled
      2. namespace/kube-node-lease labeled
      3. namespace/kube-public labeled
      4. Warning: existing pods in namespace "kube-system" violate the new PodSecurity enforce level "restricted:latest"
      5. Warning: coredns-7bb9c7b568-hsptc (and 1 other pod): unrestricted capabilities, runAsNonRoot != true, seccompProfile
      6. Warning: etcd-psa-wo-cluster-pss-control-plane (and 3 other pods): host namespaces, hostPath volumes, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true
      7. Warning: kindnet-vzj42: non-default capabilities, host namespaces, hostPath volumes, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true, seccompProfile
      8. Warning: kube-proxy-m6hwf: host namespaces, hostPath volumes, privileged, allowPrivilegeEscalation != false, unrestricted capabilities, restricted volume types, runAsNonRoot != true, seccompProfile
      9. namespace/kube-system labeled
      10. Warning: existing pods in namespace "local-path-storage" violate the new PodSecurity enforce level "restricted:latest"
      11. Warning: local-path-provisioner-d6d9f7ffc-lw9lh: allowPrivilegeEscalation != false, unrestricted capabilities, runAsNonRoot != true, seccompProfile
      12. namespace/local-path-storage labeled

From the previous output, you’ll notice that applying the privileged Pod Security Standard shows no warnings for any namespaces. However, baseline and restricted standards both have warnings, specifically in the kube-system namespace.

Set modes, versions and standards

In this section, you apply the following Pod Security Standards to the latest version:

  • baseline standard in enforce mode.
  • restricted standard in warn and audit mode.

The baseline Pod Security Standard provides a convenient middle ground that allows keeping the exemption list short and prevents known privilege escalations.

Additionally, to prevent pods from failing in kube-system, you’ll exempt the namespace from having Pod Security Standards applied.

When you implement Pod Security Admission in your own environment, consider the following:

  1. Based on the risk posture applied to a cluster, a stricter Pod Security Standard like restricted might be a better choice.

  2. Exempting the kube-system namespace allows pods to run as privileged in this namespace. For real world use, the Kubernetes project strongly recommends that you apply strict RBAC policies that limit access to kube-system, following the principle of least privilege. To implement the preceding standards, do the following:

  3. Create a configuration file that can be consumed by the Pod Security Admission Controller to implement these Pod Security Standards:

    1. mkdir -p /tmp/pss
    2. cat <<EOF > /tmp/pss/cluster-level-pss.yaml
    3. apiVersion: apiserver.config.k8s.io/v1
    4. kind: AdmissionConfiguration
    5. plugins:
    6. - name: PodSecurity
    7. configuration:
    8. apiVersion: pod-security.admission.config.k8s.io/v1
    9. kind: PodSecurityConfiguration
    10. defaults:
    11. enforce: "baseline"
    12. enforce-version: "latest"
    13. audit: "restricted"
    14. audit-version: "latest"
    15. warn: "restricted"
    16. warn-version: "latest"
    17. exemptions:
    18. usernames: []
    19. runtimeClasses: []
    20. namespaces: [kube-system]
    21. EOF

    Note: pod-security.admission.config.k8s.io/v1 configuration requires v1.25+. For v1.23 and v1.24, use v1beta1. For v1.22, use v1alpha1.

  4. Configure the API server to consume this file during cluster creation:

    1. cat <<EOF > /tmp/pss/cluster-config.yaml
    2. kind: Cluster
    3. apiVersion: kind.x-k8s.io/v1alpha4
    4. nodes:
    5. - role: control-plane
    6. kubeadmConfigPatches:
    7. - |
    8. kind: ClusterConfiguration
    9. apiServer:
    10. extraArgs:
    11. admission-control-config-file: /etc/config/cluster-level-pss.yaml
    12. extraVolumes:
    13. - name: accf
    14. hostPath: /etc/config
    15. mountPath: /etc/config
    16. readOnly: false
    17. pathType: "DirectoryOrCreate"
    18. extraMounts:
    19. - hostPath: /tmp/pss
    20. containerPath: /etc/config
    21. # optional: if set, the mount is read-only.
    22. # default false
    23. readOnly: false
    24. # optional: if set, the mount needs SELinux relabeling.
    25. # default false
    26. selinuxRelabel: false
    27. # optional: set propagation mode (None, HostToContainer or Bidirectional)
    28. # see https://kubernetes.io/docs/concepts/storage/volumes/#mount-propagation
    29. # default None
    30. propagation: None
    31. EOF

    Note: If you use Docker Desktop with kind on macOS, you can add /tmp as a Shared Directory under the menu item Preferences > Resources > File Sharing.

  5. Create a cluster that uses Pod Security Admission to apply these Pod Security Standards:

    1. kind create cluster --name psa-with-cluster-pss --config /tmp/pss/cluster-config.yaml

    The output is similar to this:

    1. Creating cluster "psa-with-cluster-pss" ...
    2. Ensuring node image (kindest/node:v1.29.0) 🖼
    3. Preparing nodes 📦
    4. Writing configuration 📜
    5. Starting control-plane 🕹️
    6. Installing CNI 🔌
    7. Installing StorageClass 💾
    8. Set kubectl context to "kind-psa-with-cluster-pss"
    9. You can now use your cluster with:
    10. kubectl cluster-info --context kind-psa-with-cluster-pss
    11. Have a question, bug, or feature request? Let us know! https://kind.sigs.k8s.io/#community 🙂
  6. Point kubectl to the cluster:

    1. kubectl cluster-info --context kind-psa-with-cluster-pss

    The output is similar to this:

    1. Kubernetes control plane is running at https://127.0.0.1:63855
    2. CoreDNS is running at https://127.0.0.1:63855/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
    3. To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.
  7. Create a Pod in the default namespace:

    security/example-baseline-pod.yaml Apply Pod Security Standards at the Cluster Level - 图1

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. name: nginx
    5. spec:
    6. containers:
    7. - image: nginx
    8. name: nginx
    9. ports:
    10. - containerPort: 80
    1. kubectl apply -f https://k8s.io/examples/security/example-baseline-pod.yaml

    The pod is started normally, but the output includes a warning:

    1. Warning: would violate PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "nginx" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "nginx" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "nginx" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "nginx" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
    2. pod/nginx created

Clean up

Now delete the clusters which you created above by running the following command:

  1. kind delete cluster --name psa-with-cluster-pss
  1. kind delete cluster --name psa-wo-cluster-pss

What’s next