Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# SPDX-FileCopyrightText: 2026 SAP SE or an SAP affiliate company and Gardener contributors
#
# SPDX-License-Identifier: Apache-2.0

ruleset:
id: pod-security-standards
name: "Pod Security Standards"
version: "v0.1.0"
rules:
# Baseline Profile
- id: PSS-B001
name: "HostProcess"
description: "Windows Pods offer the ability to run HostProcess containers which enables privileged access to the Windows host machine. Privileged access to the host is disallowed in the Baseline policy."
severity: "HIGH"
- id: PSS-B002
name: "Host Namespaces"
description: "Sharing the host namespaces must be disallowed."
severity: "HIGH"
- id: PSS-B003
name: "Privileged Containers"
description: "Privileged Pods disable most security mechanisms and must be disallowed."
severity: "HIGH"
- id: PSS-B004
name: "Capabilities (Baseline)"
description: "Adding additional capabilities beyond the following must be disallowed: AUDIT_WRITE, CHOWN, DAC_OVERRIDE, FOWNER, FSETID, KILL, MKNOD, NET_BIND_SERVICE, SETFCAP, SETGID, SETPCAP, SETUID, SYS_CHROOT."
severity: "HIGH"
- id: PSS-B005
name: "HostPath Volumes"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either that or we should adapt other similar names to be consistent across naming. Or was this taken from the k8s documentation?

Suggested change
name: "HostPath Volumes"
name: "Host Path Volumes"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These names were take directly from the k8s PSS documentation, as the name of the policy. I agree that there is an inconsistency, but should we fix it or stick to the way they are written in k8s?

description: "HostPath volumes must be forbidden."
severity: "HIGH"
- id: PSS-B006
name: "Host Ports"
description: "HostPorts should be disallowed entirely (recommended) or restricted to a known list."
severity: "HIGH"
- id: PSS-B007
name: "Host Probes / Lifecycle Hooks"
description: "The host field in probes and lifecycle hooks must be disallowed."
severity: "HIGH"
- id: PSS-B008
name: "AppArmor"
description: "On supported hosts, the RuntimeDefault AppArmor profile is applied by default. The Baseline policy should prevent overriding or disabling the default AppArmor profile, or restrict overrides to an allowed set of profiles."
severity: "HIGH"
- id: PSS-B009
name: "SELinux"
description: "Setting the SELinux type is restricted, and setting a custom SELinux user or role option is forbidden."
severity: "HIGH"
- id: PSS-B010
name: "/proc Mount Type"
description: "The default /proc masks are set up to reduce attack surface, and should be required."
severity: "HIGH"
- id: PSS-B011
name: "Seccomp (Baseline)"
description: "Seccomp profile must not be explicitly set to Unconfined."
severity: "HIGH"
- id: PSS-B012
name: "Sysctls"
description: "Sysctls can disable security mechanisms or affect all containers on a host, and should be disallowed except for an allowed \"safe\" subset. A sysctl is considered safe if it is namespaced in the container or the Pod, and it is isolated from other Pods or processes on the same Node."
severity: "HIGH"
# Restricted Profile
- id: PSS-R001
name: "Volume Types"
description: "The Restricted policy only permits the following volume types: configMap, csi, downwardAPI, emptyDir, ephemeral, persistentVolumeClaim, projected, secret."
severity: "MEDIUM"
- id: PSS-R002
name: "Privilege Escalation"
description: "Privilege escalation (such as via set-user-ID or set-group-ID file mode) should not be allowed. This is Linux only policy in v1.25+."
severity: "MEDIUM"
- id: PSS-R003
name: "Running as Non-root"
description: "Containers must be required to run as non-root users."
severity: "MEDIUM"
- id: PSS-R004
name: "Running as Non-root user"
description: "Containers must not set runAsUser to 0."
severity: "MEDIUM"
- id: PSS-R005
name: "Seccomp (Restricted)"
description: "Seccomp profile must be explicitly set to RuntimeDefault or Localhost. Unconfined profiles and the absence of a profile are prohibited."
severity: "MEDIUM"
- id: PSS-R006
name: "Capabilities (Restricted)"
description: "Containers must drop ALL capabilities, and are only permitted to add back NET_BIND_SERVICE."
severity: "MEDIUM"
Comment on lines +60 to +83

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I cannot decide if those should be MEDIUM or HIGH. Privilege escalation and runnning as non-root seem like a HIGH requirements to me. How can we decide what to change? The other options is to set everything to high?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some of these rules have more restrictive versions in the baseline policies. Such are: PSS-R001 < PSS-B005; PSS-R005 < PSS-B011; PSS-R006 < PSS-B004.

We can also say that PSS-R004 < PSS-R003.

I agree that we can set PSS-R002 & PSS-R003 to HIGH

251 changes: 251 additions & 0 deletions docs/rulesets/pod-security-standards/ruleset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
# Pod Security Standards Guide

## Introduction

The Pod Security Standards ruleset checks pods running in a Kubernetes cluster against the official [Kubernetes Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/). It implements both the **Baseline** and **Restricted** profiles as individual rules, enabling fine-grained compliance checking and reporting.

- The **Baseline** profile (rules PSS-B001 to PSS-B012) prevents known privilege escalations and is minimally restrictive.
- The **Restricted** profile (rules PSS-R001 to PSS-R006) enforces current pod hardening best practices.

The version documented here is [v0.1.0](pod-security-standards-v0.1.0.yaml).

## Baseline Profile

The Baseline profile prevents known privilege escalations. Targeted at application operators and developers of non-critical applications.

---

### PSS-B001 - HostProcess <a id="PSS-B001"></a>

#### Description
Windows Pods offer the ability to run HostProcess containers which enables privileged access to the Windows host machine. Privileged access to the host is disallowed in the Baseline policy.

#### Fix
Do not set `securityContext.windowsOptions.hostProcess` to `true` at the pod or container level.

---

### PSS-B002 - Host Namespaces <a id="PSS-B002"></a>

#### Description
Sharing the host namespaces must be disallowed.

#### Fix
Do not set `spec.hostNetwork`, `spec.hostPID`, or `spec.hostIPC` to `true`.

---

### PSS-B003 - Privileged Containers <a id="PSS-B003"></a>

#### Description
Privileged Pods disable most security mechanisms and must be disallowed.

#### Fix
Do not set `securityContext.privileged` to `true` on any container.

---

### PSS-B004 - Capabilities (Baseline) <a id="PSS-B004"></a>

#### Description
Adding additional capabilities beyond the following must be disallowed: `AUDIT_WRITE`, `CHOWN`, `DAC_OVERRIDE`, `FOWNER`, `FSETID`, `KILL`, `MKNOD`, `NET_BIND_SERVICE`, `SETFCAP`, `SETGID`, `SETPCAP`, `SETUID`, `SYS_CHROOT`.

#### Fix
Remove any capabilities from `securityContext.capabilities.add` that are not in the allowed set.

---

### PSS-B005 - HostPath Volumes <a id="PSS-B005"></a>

#### Description
HostPath volumes must be forbidden.

#### Fix
Remove any `Volumes` of type `hostPath` from the `Pod` spec.

---

### PSS-B006 - Host Ports <a id="PSS-B006"></a>

#### Description
HostPorts should be disallowed entirely (recommended) or restricted to a known list.

#### Fix
Remove `hostPort` from container port definitions or set it to `0`.

---

### PSS-B007 - Host Probes / Lifecycle Hooks <a id="PSS-B007"></a>

#### Description
The host field in probes and lifecycle hooks must be disallowed. Setting the `host` field in `httpGet` probes or lifecycle hooks allows a container to send requests to arbitrary hosts, bypassing network policies.

#### Fix
Do not set the `host` field in `httpGet` probes (`livenessProbe`, `readinessProbe`, `startupProbe`) or lifecycle hooks (`postStart`, `preStop`).

---

### PSS-B008 - AppArmor <a id="PSS-B008"></a>

#### Description
On supported hosts, the `RuntimeDefault` AppArmor profile is applied by default. The Baseline policy should prevent overriding or disabling the default AppArmor profile, or restrict overrides to an allowed set of profiles.

#### Fix
Do not set `securityContext.appArmorProfile.type` to `Unconfined` at the pod or container level.

---

### PSS-B009 - SELinux <a id="PSS-B009"></a>

#### Description
Setting the SELinux type is restricted, and setting a custom SELinux user or role option is forbidden. Allowed types: (empty), `container_t`, `container_init_t`, `container_kvm_t`.

#### Fix
Do not set `seLinuxOptions.type` to a value outside the allowed set. Remove the field or use one of the allowed types.

---

### PSS-B010 - /proc Mount Type <a id="PSS-B010"></a>

#### Description
The default `/proc` masks are set up to reduce attack surface, and should be required.

#### Fix
Do not set `securityContext.procMount` or set it explicitly to `Default`.

---

### PSS-B011 - Seccomp (Baseline) <a id="PSS-B011"></a>

#### Description
Seccomp profile must not be explicitly set to `Unconfined`.

#### Fix
Do not set `securityContext.seccompProfile.type` to `Unconfined` at the pod or container level.

---

### PSS-B012 - Sysctls <a id="PSS-B012"></a>

#### Description
Sysctls can disable security mechanisms or affect all containers on a host, and should be disallowed except for an allowed "safe" subset. A sysctl is considered safe if it is namespaced in the container or the Pod, and it is isolated from other Pods or processes on the same Node. Allowed: `kernel.shm_rmid_forced`, `net.ipv4.ip_local_port_range`, `net.ipv4.ip_unprivileged_port_start`, `net.ipv4.tcp_syncookies`, `net.ipv4.ping_group_range`, `net.ipv4.ip_local_reserved_ports`, `net.ipv4.tcp_keepalive_time`, `net.ipv4.tcp_fin_timeout`, `net.ipv4.tcp_keepalive_intvl`, `net.ipv4.tcp_keepalive_probes`.

#### Fix
Remove any sysctls that are not in the allowed set from `spec.securityContext.sysctls`.

---

## Restricted Profile

The Restricted profile enforces current pod hardening best practices, at the expense of some compatibility. It includes all Baseline requirements plus the following additional restrictions.

---

### PSS-R001 - Volume Types <a id="PSS-R001"></a>

#### Description
The Restricted policy only permits the following volume types: `configMap`, `csi`, `downwardAPI`, `emptyDir`, `ephemeral`, `persistentVolumeClaim`, `projected`, `secret`.

#### Fix
Restrict `Pod` volume types to `configMap`, `csi`, `downwardAPI`, `emptyDir`, `ephemeral`, `persistentVolumeClaim`, `projected` and `secret`.

---

### PSS-R002 - Privilege Escalation <a id="PSS-R002"></a>

#### Description
Privilege escalation (such as via set-user-ID or set-group-ID file mode) should not be allowed. This is Linux only policy in v1.25+.

#### Fix
Set `securityContext.allowPrivilegeEscalation` to `false` on every container.

``` yaml
apiVersion: v1
kind: Pod
spec:
containers:
- name: ...
securityContext:
allowPrivilegeEscalation: false
initContainers:
- name: ...
securityContext:
allowPrivilegeEscalation: false
```
---

### PSS-R003 - Running as Non-root <a id="PSS-R003"></a>

#### Description
Containers must be required to run as non-root users.

#### Fix
Set `runAsNonRoot: true` at the pod level or on each container. Container-level settings override pod-level.

``` yaml
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
containers:
- name: ...
securityContext:
runAsNonRoot: true
```
---

### PSS-R004 - Running as Non-root user <a id="PSS-R004"></a>

#### Description
Containers must not set `runAsUser` to 0.

#### Fix
Do not set `runAsUser` to `0`. Set it to a non-zero value or omit it.

---

### PSS-R005 - Seccomp (Restricted) <a id="PSS-R005"></a>

#### Description
Seccomp profile must be explicitly set to `RuntimeDefault` or `Localhost`. Unconfined profiles and the absence of a profile are prohibited.

#### Fix
Set `securityContext.seccompProfile.type` to `RuntimeDefault` or `Localhost` at the pod level or on each container.

``` yaml
apiVersion: v1
kind: Pod
spec:
securityContext:
seccompProfile:
type: RuntimeDefault
containers:
- name: ...
securityContext:
seccompProfile:
type: RuntimeDefault
```
---

### PSS-R006 - Capabilities (Restricted) <a id="PSS-R006"></a>

#### Description
Containers must drop `ALL` capabilities, and are only permitted to add back `NET_BIND_SERVICE`.

#### Fix
Set `capabilities.drop` to include `ALL` and only add `NET_BIND_SERVICE` if required.

``` yaml
apiVersion: v1
kind: Pod
spec:
containers:
- name: ...
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
```
Loading