Kubernetes: Pod Security

kubernetes security Pod Security Standards namespace

4 min read | by Jordi Prats

Security is one of the key concerns when running workloads on Kubernetes. To help teams safeguard their cluster environments, Kubernetes offers Pod Security Standards (PSS). These standards define how to enforce security controls for your pod workloads.

Pod Security Standards are a set of predefined security profiles created to ensure workloads are secured according to best practices. They define how different pods should be allowed to behave based on their level of security risk. These profiles govern important security configurations, including privilege levels, volume types, and access to the host system.

There are three levels of Pod Security Standards, providing a different level of security on your pods:

  • Restricted (most restrictive)
  • Baseline (moderately restrictive)
  • Privileged (least restrictive)

Restricted

The Restricted standard is the most secure of the three, offering a highly locked-down environment for running pods. It enforces strict security practices to prevent privileged operations and isolate workloads from the host system. Key rules in this standard include:

  • No privilege escalation
  • No access to host namespaces or hostPath volumes
  • Use of security best practices like running as a non-root user
  • Limited use of Linux capabilities

Baseline

The Baseline standard represents a more moderate security posture. It balances functionality and security by prohibiting some high-risk capabilities while still allowing commonly used features. This profile aims to restrict known vulnerabilities while accommodating typical application use cases. Key restrictions include:

  • No privilege escalation
  • Restricted access to host namespaces and hostPath volumes
  • Controlled use of capabilities like NET_ADMIN
  • Avoids excessive control over the host filesystem or network interfaces

Privileged

The Privileged standard is the least restrictive of the three, allowing most pod capabilities. It is ideal for workloads that require broad access to the underlying host system, but it comes with increased risk because it provides fewer security boundaries between the pod and the host. Some key aspects of this standard include:

  • No restrictions on privilege escalation
  • Access to host namespaces, such as network and process namespaces
  • Use of hostPath volumes, allowing pods to interact with the host filesystem

Enforcing Pod Security Standards

To apply Pod Security Standards to your Kubernetes workloads, you need to label the namespace where the pods are running with the desired security profile. For example, to enforce restricted on a namespace named test-pod-security, you can run the following command:

kubectl label ns test-pod-security pod-security.kubernetes.io/enforce=restricted

We can test it by creating a pod in the test-pod-security namespace that violates the restricted profile. For example, the following pod definition tries to run the container as root:

cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: test-pod-security
  namespace: test-pod-security
spec:
  containers:
  - name: test-container
    image: alpine:latest
    command: ["sh", "-c", "sleep 1h"]
    securityContext:
      runAsUser: 0
EOF

When you try to create this pod, you'll get an error message indicating that the pod violates the restricted profile:

$ cat <<EOF | kubectl apply -f -
> apiVersion: v1
> kind: Pod
> metadata:
>   name: test-pod-security
>   namespace: test-pod-security
> spec:
>   containers:
>   - name: test-container
>     image: alpine:latest
>     command: ["sh", "-c", "sleep 1h"]
>     securityContext:
>       runAsUser: 0
> EOF
Error from server (Forbidden): error when creating "STDIN": pods "test-pod-security" is forbidden: violates PodSecurity "restricted:latest": allowPrivilegeEscalation != false (container "test-container" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test-container" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test-container" must set securityContext.runAsNonRoot=true), runAsUser=0 (container "test-container" must not set runAsUser=0), seccompProfile (pod or container "test-container" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")

If we change the label to baseline or privileged, the pod will be created successfully:

$ kubectl label ns test-pod-security pod-security.kubernetes.io/enforce=baseline --overwrite
namespace/test-pod-security labeled
$ cat <<EOF | kubectl apply -f -
> apiVersion: v1
> kind: Pod
> metadata:
>   name: test-pod-security
>   namespace: test-pod-security
> spec:
>   containers:
>   - name: test-container
>     image: alpine:latest
>     command: ["sh", "-c", "sleep 1h"]
>     securityContext:
>       runAsUser: 0
> EOF
pod/test-pod-security created

Posted on 02/09/2024