Pod Security Standards
What are Pod Security Standards (PSS)?
Pod Security Standards (PSS) is a framework that enables engineers to share and restrict privileges for different kinds of pods and users. These allow or disallow access to users and resources in the clusters, thus securing the Kubernetes clusters and the complete environment efficiently.
There are three types of policies that range between highly permissive and highly restrictive. Engineers can implement a policy type based on pod security requirements. These include:
- Privileged: The policy purposely offers unrestricted access and targets trusted users who manage system-level and infrastructure-level workloads. The mechanism is synonymous with allow-by-default and is the opposite of deny-by-default. With this, all restrictions can be disabled.
- Baseline: With baseline policies, operators and developers can easily manage common containerized workloads without access to privileged sections of the Kubernetes environment. These are for users who work on non-critical applications.
- Restricted: The restricted policies harden Kubernetes by limiting access and privileges. This comes at the cost of compatibility and ease of communication between resources but makes the environment highly secure. It is for users, operators, and developers working on security-critical applications and low-trust users.
Overall, Pod Security Standards outline security controls for Kubernetes resources and ensure cluster operations, workload behaviors, and environmental integrity are well maintained.
What is Pod Security Policy (PSP) and why was it deprecated?
Before the establishment of PSS, security used to be controlled using Pod Security Policy (PSP). One of its key limitations was that a pod must run a set of pre-defined conditions mentioned in the PSP to be recognized by the Kubernetes environment as a valid resource. Without the specifications, the pod would not be accepted into the system.
Since Kubernetes v1.21, PSP was deprecated due to its limitations and complex nature. According to feedback from Kubernetes developers, PSPs were confusing, and engineers found it difficult to determine which PSPs to apply in a given scenario. As a result, unintentional configuration and specification errors would often occur, compromising the Kubernetes environment’s security. The admission controller has now been replaced by Pod Security Admission (PSA), which enforces the policies outlined by the Pod Security Standards.
Functionalities of Pod Security Standard
The Privileged policy functions like the mechanism of allow-by-default for various resources. However, Baseline and Restricted policies can control the following components with the corresponding policies:
Baseline
Control | Policy |
---|---|
HostProcess | Determines how a pod is run in the host namespace. Privileged access to the host is disallowed in the baseline policy. FEATURE STATE: Kubernetes v1.26 [stable]Restricted Fields: • spec.securityContext.runAsUser • spec.securityContext.runAsGroup • spec.securityContext.runAsNonRoot • spec.securityContext.privilegedAllowed Values • Undefined/nil • false |
Host Namespaces | Sharing the host namespaces must be disallowed. Restricted Fields: • spec.hostNetwork • spec.hostPID • spec.hostIPC Allowed Values: • Undefined/null • false |
Privileged Containers | Privileged Pods disable most security mechanisms and must be disallowed. Restricted Fields • spec.containers[*].securityContext.privileged • spec.initContainers[*].securityContext.privileged • spec.ephemeralContainers[*].securityContext.privileged Allowed Values: • Undefined/null • false |
Capabilities | Adding additional capabilities beyond those listed below must be disallowed. Restricted Fields • spec.containers[*].securityContext.capabilities.add • spec.initContainers[*].securityContext.capabilities.add • spec.ephemeralContainers[*].securityContext.capabilities.add Allowed Values • Undefined/nil • AUDIT_WRITE • CHOWN • DAC_OVERRIDE • FOWNER • FSETID • KILL • MKNOD • NET_BIND_SERVICE • SETFCAP • SETGID • SETPCAP • SETUID • SYS_CHROOT |
HostPath Volumes | HostPath volumes must be forbidden. Restricted Fields • spec.volumes[*].hostPath Allowed Values • Undefined/nil |
Host Ports | HostPorts should be disallowed entirely (recommended) or restricted to a known list Restricted Fields • spec.containers[*].ports[*].hostPort • spec.initContainers[*].ports[*].hostPort • spec.ephemeralContainers[*].ports[*].hostPort Allowed Values • Undefined/null • Known list (not supported by the built-in Pod Security Admission controller) • 0 |
AppArmor | On supported hosts, the runtime/default 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. Restricted Fields • metadata.annotations[“container.apparmor.security.beta.kubernetes.io/*”] Allowed Values • Undefined/nil • runtime/default • localhost/* |
SELinux | Setting the SELinux type is restricted, and setting a custom SELinux user or role option is forbidden. Restricted Fields • spec.securityContext.seLinuxOptions.type • spec.containers[*].securityContext.seLinuxOptions.type • spec.initContainers[*].securityContext.seLinuxOptions.type • spec.ephemeralContainers[*].securityContext.seLinuxOptions.type Allowed Values • Undefined/”” • container_t • container_init_t • container_kvm_t ————————————————- Restricted Fields • spec.securityContext.seLinuxOptions.user • spec.containers[*].securityContext.seLinuxOptions.user • spec.initContainers[*].securityContext.seLinuxOptions.user • spec.ephemeralContainers[*].securityContext.seLinuxOptions.user • spec.securityContext.seLinuxOptions.role • spec.containers[*].securityContext.seLinuxOptions.role • spec.initContainers[*].securityContext.seLinuxOptions.role • spec.ephemeralContainers[*].securityContext.seLinuxOptions.role Allowed Values • Undefined/”” |
/proc Mount Type | The default /proc masks are set up to reduce attack surface, and should be required. Restricted Fields • spec.containers[*].securityContext.procMount • spec.initContainers[*].securityContext.procMount • spec.ephemeralContainers[*].securityContext.procMountAllowed ValuesUndefined/nilDefault |
Seccomp | Seccomp profile must not be explicitly set to Unconfined. Restricted Fields • spec.securityContext.seccompProfile.type • spec.containers[*].securityContext.seccompProfile.type • spec.initContainers[*].securityContext.seccompProfile.type • spec.ephemeralContainers[*].securityContext.seccompProfile.type Allowed Values • Undefined/nilRuntimeDefaultLocalhost |
Sysctls | 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. Restricted Fields • spec.securityContext.sysctls[*].name Allowed Values • Undefined/nil • 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 |
Restricted
Restricted comprises everything that comes under Baseline Policy. Furthermore, it also includes the following:
Control | Policy |
---|---|
Volume Types | The restricted policy only permits the following volume types. Restricted Fields • spec.volumes[*] Allowed Values Every item in the spec.volumes[*] list must set one of the following fields to a non-null value: • spec.volumes[*].configMap • spec.volumes[*].csi • spec.volumes[*].downwardAPI • spec.volumes[*].emptyDir • spec.volumes[*].ephemeral • spec.volumes[*].persistentVolumeClaim • spec.volumes[*].projected • spec.volumes[*].secret |
Privilege Escalation (v1.8+) | 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+ (spec.os.name != windows) Restricted Fields • spec.containers[*].securityContext.allowPrivilegeEscalation • spec.initContainers[*].securityContext.allowPrivilegeEscalation • spec.ephemeralContainers[*].securityContext.allowPrivilegeEscalation Allowed Values • false |
Running as Non-root | Containers must be required to run as non-root users. Restricted Fields • spec.securityContext.runAsNonRoot • spec.containers[*].securityContext.runAsNonRoot • spec.initContainers[*].securityContext.runAsNonRoot • spec.ephemeralContainers[*].securityContext.runAsNonRoot Allowed Values • true The container fields may be undefined/nil if the pod-level spec.securityContext.runAsNonRoot is set to true. |
Running as Non-root user (v1.23+) | Containers must not set runAsUser to 0 Restricted Fields • spec.securityContext.runAsUser • spec.containers[*].securityContext.runAsUser • spec.initContainers[*].securityContext.runAsUser • spec.ephemeralContainers[*].securityContext.runAsUser Allowed Values • any non-zero value • undefined/null |
Seccomp (v1.19+) | Seccomp profile must be explicitly set to one of the allowed values. Both the Unconfined profile and the absence of a profile are prohibited. This is Linux only policy in v1.25+ (spec.os.name != windows) Restricted Fields • spec.securityContext.seccompProfile.type • spec.containers[*].securityContext.seccompProfile.type • spec.initContainers[*].securityContext.seccompProfile.type • spec.ephemeralContainers[*].securityContext.seccompProfile.type Allowed Values • RuntimeDefault • Localhost The container fields may be undefined/nil if the pod-level spec.securityContext.seccompProfile.type field is set appropriately. Conversely, the pod-level field may be undefined/nil if _all_ container- level fields are set. |
Capabilities (v1.22+) | Containers must drop ALL capabilities, and are only permitted to add back the NET_BIND_SERVICE capability. This is Linux only policy in v1.25+ (.spec.os.name != “windows”) Restricted Fields • spec.containers[*].securityContext.capabilities.drop • spec.initContainers[*].securityContext.capabilities.drop • spec.ephemeralContainers[*].securityContext.capabilities.drop Allowed Values • Any list of capabilities that includes ALL ————————————————- Restricted Fields • spec.containers[*].securityContext.capabilities.add • spec.initContainers[*].securityContext.capabilities.add • spec.ephemeralContainers[*].securityContext.capabilities.add Allowed Values • Undefined/nil • NET_BIND_SERVICE |
Benefits of Pod Security Standards
- With Pod Security Standards, securing Kubernetes clusters becomes simpler, more straightforward, and more efficient. The framework enhances the security posture of the clusters.
- The policies prevent unauthorized actions from low-trust users and other resources, thus preventing potential vulnerabilities that can be exploited.
- With Restricted and Baseline policies, pod security is hardened by leveraging the least privilege principles. As a result, the attack surface is reduced, and the impact of a potential malicious attack is minimized.
- Pod Security Standards also allow engineers to configure the Kubernetes resources and environments that align with industry security standards and regulatory frameworks, which help with cluster security.
Working with Pod Security Standards
Pod Security Admission is the admission controller to enforce Pod Security Standard policies. This occurs via the following three modes:
- Enforce: With this, policy violations in a pod will result in its rejection.
- Audit: Pods with policy violations will be allowed, but the event in the audit log will be annotated with “audit.”
- Warn: Pods with policy violations will be allowed, but the users will receive a warning.
Example of Namespace Configuration using PSS and PSA
In the below example, the namespace is configured with a cluster-wide setting, and the configuration occurs by default. The labels are commented, but by uncommenting, the PSS can the PSA can implement policies for the namespace.
apiVersion: v1 kind: Namespace metadata: name: psa-pss-test-ns labels: # pod-security.kubernetes.io/enforce: privileged # pod-security.kubernetes.io/audit: privileged # pod-security.kubernetes.io/warn: privileged # pod-security.kubernetes.io/enforce: baseline # pod-security.kubernetes.io/audit: baseline # pod-security.kubernetes.io/warn: baseline # pod-security.kubernetes.io/enforce: restricted # pod-security.kubernetes.io/audit: restricted # pod-security.kubernetes.io/warn: restricted
Limitations and considerations
- Although Pod Security Standards are less complex than its predecessor PSP (Pod Security Policies), adopting and maintaining the specifications is challenging due to the dynamic nature of the environment and resource usage.
- The hardening of pod security causes compatibility issues and impacts the seamless functionality of applications.
- While using Pod Security Standards and Pod Security Admission, it is important to understand how the application performances will be impacted and to what extent the security can be prioritized over the performance. Overall, it must be about creating a balance between the two factors.