Securing Workloads with Kubernetes Pod Security Admission (PSA)
Ensuring that Pods running in your Kubernetes cluster adhere to security best practices is fundamental to maintaining a secure environment. For years, PodSecurityPolicy (PSP) was the primary mechanism for enforcing these constraints. However, PSPs proved complex to manage, difficult to apply consistently, and had usability challenges.
Important: PodSecurityPolicy (PSP) was deprecated in Kubernetes v1.21 and removed entirely in v1.25. If you are running a modern Kubernetes cluster, you should not be using PSPs.
The successor to PSP is the built-in Pod Security Admission (PSA) controller, combined with the defined Pod Security Standards (PSS). PSA offers a simpler, more standardized, and easier-to-manage approach to enforcing Pod security baselines at the namespace level.
This guide explains the concepts behind PSA and PSS, provides practical examples, and outlines best practices for securing your workloads using the current Kubernetes standard. We’ll briefly cover PSPs for historical context.
PodSecurityPolicy (PSP): A Look Back (Deprecated)
Before PSA, PodSecurityPolicy was a cluster-level resource that defined a set of conditions a Pod must meet to be accepted into the cluster (or mutated). PSPs controlled security-sensitive aspects like:
- Running privileged containers.
- Accessing the host filesystem or network.
- Allowed volume types.
- User/group ID execution constraints.
- Allowed Linux capabilities.
While powerful, PSPs required complex RBAC configurations (binding Policies to Service Accounts via Roles/ClusterRoles) and often led to confusing authorization errors if not perfectly configured.
Example Restricted PSP (Historical Context Only):
# --- DEPRECATED: Do not use on K8s v1.25+ ---
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restricted-psp-example
annotations:
seccomp.security.alpha.kubernetes.io/allowedProfileNames: 'runtime/default'
seccomp.security.alpha.kubernetes.io/defaultProfileName: 'runtime/default'
spec:
privileged: false # Disallow privileged containers
allowPrivilegeEscalation: false # Prevent gaining more privileges
requiredDropCapabilities: # Drop all capabilities
- ALL
# Allow specific volume types only
volumes:
- 'configMap'
- 'emptyDir'
- 'projected'
- 'secret'
- 'downwardAPI'
- 'persistentVolumeClaim'
hostNetwork: false # Disallow host network access
hostIPC: false
hostPID: false
runAsUser:
rule: 'MustRunAsNonRoot' # Require non-root user
seLinux:
rule: 'RunAsAny' # SELinux context (adjust as needed)
supplementalGroups:
rule: 'MustRunAs'
ranges: # Define allowed group ID ranges
- min: 1
max: 65535
fsGroup:
rule: 'MustRunAs'
ranges:
- min: 1
max: 65535
readOnlyRootFilesystem: false # Optional: Could be set to true
Key takeaway: PSPs offered granular control but required significant effort to implement correctly across a cluster, leading to their deprecation.
The Modern Approach: Pod Security Admission (PSA) & Standards (PSS)
PSA is a built-in admission controller (enabled by default in modern Kubernetes versions) that enforces security constraints based on the Pod Security Standards. It simplifies Pod security by providing predefined profiles and applying them at the namespace level.
Pod Security Standards (PSS)
These are three predefined policies, offering tiered levels of security:
privileged
: Unrestricted policy, providing the widest possible permissions. Allows for known privilege escalations. Should only be used for trusted, system-level workloads managed by privileged users. Avoid for general application workloads.baseline
: A minimally restrictive policy preventing known privilege escalations while ensuring broad application compatibility. It disallows hostNetwork, privileged containers, hostPath volumes, etc., but is less strict thanrestricted
on things like capabilities or user IDs. A good default starting point for many applications.restricted
: A heavily restricted policy following current Pod hardening best practices. It enforces non-root execution, drops most capabilities, restricts volume types, requires secureseccomp
profiles, etc. Offers the best security posture but may require application modifications to comply. The recommended standard for most application workloads.
Each standard defines specific controls related to fields in the Pod spec
and securityContext
. You can find the detailed controls for each standard in the official Kubernetes documentation.
Pod Security Admission (PSA) Controller
The PSA controller enforces the PSS profiles based on labels applied to Namespaces. This namespace-level configuration makes it much easier to manage than the complex RBAC required for PSPs.
Configuration via Namespace Labels:
You apply labels to a Namespace to configure the PSA mode for a specific PSS profile:
enforce
: Pods violating the specified profile level are rejected at creation time. This is the primary enforcement mechanism.- Label:
pod-security.kubernetes.io/enforce: <PROFILE>
(e.g.,restricted
) - Label:
pod-security.kubernetes.io/enforce-version: <VERSION>
(e.g.,latest
orv1.28
) - Pins the enforcement to a specific K8s minor version’s standard.
- Label:
audit
: Pods violating the profile level are allowed, but an audit event is recorded in the Kubernetes Audit Log. Useful for monitoring non-compliance without blocking workloads immediately.- Label:
pod-security.kubernetes.io/audit: <PROFILE>
- Label:
pod-security.kubernetes.io/audit-version: <VERSION>
- Label:
warn
: Pods violating the profile level are allowed, but a warning message is sent back to the user creating the Pod. Useful during policy rollout or for informing users.- Label:
pod-security.kubernetes.io/warn: <PROFILE>
- Label:
pod-security.kubernetes.io/warn-version: <VERSION>
- Label:
Example Namespace Configuration:
This example enforces the restricted
standard, audits against baseline
, and warns against baseline
violations for Pods created in the my-secure-app
namespace.
apiVersion: v1
kind: Namespace
metadata:
name: my-secure-app
labels:
# Enforce: Reject Pods violating the 'restricted' standard (latest version)
pod-security.kubernetes.io/enforce: restricted
pod-security.kubernetes.io/enforce-version: latest
# Audit: Log audit events for Pods violating the 'baseline' standard
pod-security.kubernetes.io/audit: baseline
pod-security.kubernetes.io/audit-version: latest
# Warn: Send warnings to users creating Pods violating the 'baseline' standard
pod-security.kubernetes.io/warn: baseline
pod-security.kubernetes.io/warn-version: latest
Modes & Rollout: You can use different modes simultaneously. A common strategy is to start with warn
or audit
mode for a stricter profile (like restricted
) to identify non-compliant workloads without breaking them, then gradually move to enforce
mode once workloads are updated.
Best Practices for Pod Security Admission
- Use PSA, Not PSPs: Ensure you are using PSA on supported Kubernetes versions (v1.23+ recommended, PSP removed in v1.25). Disable the PSP admission controller if migrating.
- Default to
restricted
: Aim to apply therestricted
PSS profile usingenforce
mode to all application namespaces where possible. This provides the strongest security baseline. - Use
baseline
as a Fallback: Ifrestricted
breaks applications initially, apply thebaseline
profile inenforce
mode as a minimum standard while working towardsrestricted
compliance. Usewarn: restricted
oraudit: restricted
to identify gaps. - Reserve
privileged
for Exceptions: Only use theprivileged
profile for specific, trusted system workloads (e.g., monitoring agents, CSI drivers) in dedicated, secured namespaces. Document and tightly control access to these namespaces. - Apply Policies Per Namespace: Leverage the namespace-level labeling for granular control. Different namespaces can have different enforcement levels based on workload sensitivity and trust.
- Pin Versions: Use the
-version
label (e.g.,pod-security.kubernetes.io/enforce-version: v1.28
) to pin policies to a specific Kubernetes minor version’s standard. This prevents unexpected behavior when the cluster is upgraded and the standards potentially change. Uselatest
only if you intend to automatically adopt new standard versions upon upgrade. - Audit and Warn During Rollout: Use
audit
andwarn
modes to identify non-compliant workloads before enablingenforce
mode, preventing disruption. Monitor audit logs. - Exemptions: PSA allows exempting specific users, runtime classes, or namespaces from enforcement if absolutely necessary, but use exemptions sparingly and with strong justification.
- Combine with Other Security Tools: PSA is one layer. Combine it with Network Policies, RBAC, securityContext settings within Pods (which PSA validates), image scanning, and runtime security tools for defense-in-depth.
Migrating from PSP to PSA
- Understand PSS Profiles: Familiarize yourself with the controls defined in the
baseline
andrestricted
Pod Security Standards. - Analyze Existing Workloads: Identify which workloads would violate the
baseline
orrestricted
standards. Tools likekubectl-psp-migrate
or manual review can help. - Enable PSA Controller: Ensure the
PodSecurity
admission plugin is enabled in yourkube-apiserver
configuration (usually enabled by default in v1.23+). - Apply PSA Labels (Audit/Warn Mode): Apply appropriate PSS labels (e.g.,
audit: restricted
,warn: restricted
) to your namespaces without enablingenforce
yet. Monitor audit logs and warnings for non-compliant Pods. - Remediate Workloads: Update non-compliant Pod specs (e.g., add
securityContext
, remove privileged settings) to meet the target PSS profile (baseline
orrestricted
). - Enable Enforcement: Once workloads are compliant, change the namespace label mode from
audit
/warn
toenforce
(e.g.,enforce: restricted
). - Disable PSP: Once PSA is fully enforced across relevant namespaces, disable the
PodSecurityPolicy
admission controller in thekube-apiserver
configuration and remove all PSP and related RBAC resources (Roles, ClusterRoles, RoleBindings, ClusterRoleBindings grantinguse
permission on PSPs).
Conclusion: Simplified and Standardized Pod Security
Pod Security Admission and Pod Security Standards represent a significant improvement over the deprecated PodSecurityPolicy mechanism. By providing clear, tiered standards (privileged
, baseline
, restricted
) and a straightforward namespace-level enforcement model via labels, PSA makes it easier for cluster administrators and developers to apply consistent security baselines across their workloads. While migrating requires analysis and potential workload adjustments, adopting PSA/PSS is crucial for securing modern Kubernetes clusters effectively and aligning with current best practices.
References
- Kubernetes Documentation - Pod Security Admission: https://kubernetes.io/docs/concepts/security/pod-security-admission/
- Kubernetes Documentation - Pod Security Standards: https://kubernetes.io/docs/concepts/security/pod-security-standards/
- Kubernetes Documentation - Migrating from PodSecurityPolicy: https://kubernetes.io/docs/tasks/configure-pod-container/migrate-from-psp/
- Kubernetes Blog: PodSecurityPolicy Deprecation: Past, Present, and Future: https://kubernetes.io/blog/2021/04/06/podsecuritypolicy-deprecation-past-present-and-future/
Comments