As Kubernetes continues to mature as the leading container orchestration platform, security remains a paramount concern for organizations deploying containerized applications. Among the fundamental tools in Kubernetes' security arsenal, Pod Security Policies (PSP)once played a pivotal role. PSP allowed administrators to meticulously define and enforce security constraints on Pods, ensuring that only containers meeting specific security standards could operate within the cluster.
However, the landscape of Kubernetes security is evolving rapidly, and it's important to note that PSP has now been deprecated, starting with Kubernetes 1.25 (see link to Kubernetes 1.25 Urgent Release notes). This change stems from various factors, including the complexity of managing and maintaining PSP policies, often leading to operational challenges for users.
In response to the deprecation, organizations are now looking for modern alternatives to PSP, ones that not only address security requirements but also streamline the process of securing workloads inKubernetes.
In this comprehensive guide, we embark on a journey to navigate this shift in Kubernetes security practices, focusing on the transition to Pod Security Admission (PSA). PSA is one of the most robust alternatives available, and this article explores it in-depth. However, it's worth mentioning that two other alternatives, Kyverno and OPA Gatekeeper, will be covered in separate articles within this series.
Throughout this article, you will find detailed instructions for setting up and installing PSA, step-by-step migration guides to transition from PSP to PSA smoothly, and precise commands for transferring existing PSP rules to PSA. Additionally, you will gain the knowledge to assess namespaces for migration readiness using dry-run commands tailored to PSA.
By the end of this guide, you will gain a comprehensive understanding of the strengths and limitations of PSA, equipping you to make an informed decision based on your organization's specific security requirements and Kubernetes environment.
With this guide, you can confidently modernize your Kubernetes security practices, ensuring that your workloads remain protected as you bid farewell to the era of Pod Security Policies.
PSA Enforces Kubernetes Security Standards: PSA ensures containers adhere to Kubernetes' native security standards, which are defined by the Pod Security Standards. These standards classify security policies into three distinct profiles, each with a different level of restrictiveness:
Privileged: The Privileged policy is intentionally open and entirely unrestricted. Typically, this policy targets system- and infrastructure-level workloads managed by trusted users. It is characterized by an absence of restrictions. While allow-by-default mechanisms like Gatekeeper may inherently be Privileged, for deny-by-default mechanisms such as Pod Security Policy (PSP), the Privileged policy should deactivate all restrictions.
Baseline: The Baseline policy is designed for easy adoption by common containerized workloads while preventing known privilege escalations. It caters to application operators and developers of non-critical applications.
Restricted: The Restricted policy is focused on enforcing rigorous Pod hardening best practices, albeit at the potential expense of some compatibility. It primarily targets operators and developers of security-critical applications, as well as lower-trust users. For a comprehensive list of controls that should be enforced or disallowed under each profile, you can refer to the official documentation.
No Direct PSP Rule Transfer: Unlike some other solutions, PSA does not offer a straightforward method for directly migrating or modifying Pod Security Policy (PSP) rules. PSA's primary focus is on validating pods against the established Kubernetes security standards, including the profiles mentioned above.
No Mutations: While PSA is effective at validation, it cannot modify or customize pod specifications as PSP could. PSA's main purpose is to enforce predefined Kubernetes security standards and does not include features for altering or mutating pod specifications. It primarily focuses on validating pods against these established standards.
Since PSA is a Kubernetes Native component, to make it work, you just need to ensure that the Pod Security Admission (PSA) controller is enabled in your Kubernetes cluster. You can do that by running the following command:
kubectl api-versions | grep admission
Control of Pod Security Admission is influenced by namespace labels. This implies that individuals with the capability to update, patch, or create namespaces also have the authority to modify the Pod Security settings for those namespaces. This modification could potentially bypass stricter security policies. Before proceeding, it is essential to verify that namespace permissions are assigned exclusively to trusted and privileged users. It is advisable to refrain from granting these elevated permissions to users who do not require such access. If additional constraints are needed for configuring Pod Security labels on Namespace objects, consider utilizing an admission webhook to enforce those restrictions.
Before migrating to Pod Security Admission (PSA), it is beneficial to normalize your PodSecurityPolicies (PSP):
Remove Unsupported Fields: Eliminate options not covered by the Pod Security Standards. These options include:
.spec.allowedHostPaths
.spec.allowedFlexVolumes
.spec.allowedCSIDrivers
.spec.forbiddenSysctls
.spec.runtimeClass
.spec.defaultAllowPrivilegeEscalation
.spec.runtimeClass.defaultRuntimeClassName
.metadata.annotations['seccomp.security.alpha.kubernetes.io/defaultProfileName']
.metadata.annotations['apparmor.security.beta.kubernetes.io/defaultProfileName']
.spec.defaultAddCapabilities
Important Note:
Removing these fields may lead to workloads lacking necessary configurations, which could potentially cause operational issues. It is crucial to ensure that workloads can function correctly with the simplified policies.
When determining the appropriate Pod Security level for your namespace, you have several methods to consider:
If you are familiar with the expected access level and security requirements for the namespace, you can select an appropriate Pod Security level based on those specific requirements. This approach is similar to how you would approach security settings in a new cluster.
Utilize the "Mapping PodSecurityPolicies to Pod Security Standards"reference to map each of your existing Pod Security Policies (PSPs) to a corresponding Pod Security Standard level.
If your PSPs are not originally based on the Pod Security Standards, you may need to make a decision. Choose a Pod Security level that is at least as permissive as your PSPs, or opt for a level that is at least as restrictive. To identify which PSPs are in use for pods within a specific namespace, use the following command:
kubectl get pods -n $NAMESPACE -o jsonpath="{.items[*].metadata.annotations.kubernetes\.io\/psp}" | tr " " "\n" | sort -u
Conduct a dry run and apply the label command from the next section to test both the Baseline and Restricted Pod Security levels. This helps you assess whether these levels are sufficiently permissive for your existing workloads. Choose the least-privileged valid level that aligns with your existing workloads.
It's important to note that the mentioned options are based on existing pods, which may not account for workloads that are not currently running. This includes CronJobs, scale-to-zero workloads, or other workloads that have not yet been deployed.
Once you've determined the Pod Security level for your namespace (except for the Privileged level), it's important to validate the chosen policy. Pod Security offers testing options to ensure a smooth rollout and compliance with security standards.
Dry Run Testing:
Use this method to assess the impact of the selected policy without immediate enforcement.
To perform a dry run, use the following command, which will highlight any existing pods that do not meet the specified policy level:
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
Audit mode allows you to record policy violations without enforcing them. Violating pods are logged in the audit records for later review. Enable audit mode with the command:
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/audit=$LEVEL
If unexpected policy violations arise during testing, you can:
Once you are confident that the selected Pod Security level is appropriate for your namespace, you can proceed to enforce it. This step ensures that the desired security standards are actively applied to your workloads within the namespace.
To enforce the desired Pod Security level on the namespace, use the following command:
kubectl label --overwrite ns $NAMESPACE pod-security.kubernetes.io/enforce=$LEVEL
Executing this command will activate and enforce the specified Pod Security level, enhancing the security posture of your namespace.
Create a fully privileged Pod Security Policy (PSP) by applying a YAML configuration file, such as privileged-psp.yaml. This PSP should grant all necessary privileges to pods and create a cluster role named privileged-psp to allow the use of Pod Security Policies (PSPs) and associate it with the privileged PSP:
kubectl apply -f privileged-psp.yaml
kubectl create clusterrole privileged-psp --verb use --resource podsecuritypolicies.policy --resource-name privileged
Create a role binding in the target namespace to associate the privileged-psp cluster role with the system:serviceaccounts:$NAMESPACE
group. This binding effectively grants all service accounts within the namespace access to the fully privileged PSP, bypassing PodSecurityPolicy:
kubectl create -n $NAMESPACE rolebinding disable-psp --clusterrole privileged-psp --group system:serviceaccounts:$NAMESPACE
With this setup, the privileged PSP is non-mutating, and the PodSecurityPolicy admission controller always prioritizes non-mutating PSPs. As a result, pods in this namespace will no longer be modified or restricted by PodSecurityPolicy.
One advantage of this approach is its reversibility. If any issues arise, you can easily roll back the change by deleting the RoleBinding associated with disabling PodSecurityPolicy. Ensure that pre-existing Pod Security Policies remain in place during this process.
To revert the PodSecurityPolicy disablement for the namespace, simply delete the RoleBinding created earlier:
kubectl delete -n $NAMESPACE rolebinding disable-psp
With existing namespaces updated to enforce Pod Security Admission, it's essential to review and update your processes and policies for creating new namespaces. This ensures that new namespaces are configured with an appropriate Pod Security profile from the outset.
Consider the following steps to enhance namespace creation processes:
Adjust Namespace Creation Policies: Update your organization's policies and procedures for creating new namespaces to include the selection and application of the desired Pod Security level. Ensure that security standards are established right from the creation stage.
Static Configuration: You can statically configure the Pod Security admission controller to define default enforcement, audit, and/or warning levels for unlabeled namespaces. This approach ensures that namespaces lacking explicit Pod Security labels still adhere to your specified security standards by default.
By revisiting your namespace creation processes, you can seamlessly integrate Pod Security standards into your Kubernetes environment and maintain a consistent and secure approach across all namespaces, old and new.
Once you are confident that the PodSecurityPolicy (PSP) admission controller is no longer needed and that Pod Security Admission (PSA) has been successfully implemented and validated, you can proceed to disable the PSP admission controller.
Here are the steps to disable the PSP admission controller:
Modify kube-apiserver Configuration:
/etc/kubernetes/manifests/kube-apiserver.yaml.
--disable-admission-plugins
flag to disable the PSP admission controller. Ensure that it's removed from the list of active admission plugins.kube-apiserver --disable-admission-plugins=PodSecurityPolicy
Restart kube-apiserver:
systemctl restart kubelet
After sufficient "soak time" to be confident that you won't need to roll back to PSPs, proceed to the next step.
With the PSP admission controller disabled and PSA in place, you can safely delete your existing PodSecurityPolicies, as well as any associated Roles, ClusterRoles, RoleBindings, and ClusterRoleBindings.
kubectl delete podsecuritypolicies --all
kubectl delete roles,clusterroles,rolebindings,clusterrolebindings --selector=rbac.authorization.kubernetes.io/autoupdate=true
This cleanup step ensures that there are no residual PSP configurations in your cluster.
By deactivating the PSP admission controller and eliminating PSP-related resources, you simplify your cluster's security architecture, completing the transition to Pod Security Admission.
In this comprehensive guide, we've explored the essential steps and considerations for smoothly transitioning your Kubernetes cluster's security framework from Pod Security Policies (PSP) to Pod Security Admission (PSA). This migration ensures that your workloads continue to run securely while aligning with Kubernetes' evolving security standards.
This guide equips you with the knowledge and steps required to migrate confidently from PSP to PSA, ensuring a secure and efficient transition while safeguarding your Kubernetes workloads. Stay tuned for upcoming articles, where I will explore alternative migration paths to Kyverno and OPA Gatekeeper.