Containers, with their lightweight and isolated nature, have revolutionized application development. But, with great power comes great responsibility. Securing containerized applications isn’t just about the code you write, it’s also about the environment in which the code runs. This is where Kubernetes steps in.
Kubernetes has become the de facto standard for orchestration platforms due to its scalability, flexibility, and robust features. However, this flexibility can be a double-edged sword, as it introduces new security challenges that can sabotage your code and send your dreams of container stardom into a tailspin. As Kubernetes adoption continues to soar, the security challenges that come with it do so, too.
One of the cornerstones of Kubernetes security, especially for developers, used to be Pod Security Policies (PSPs). They were a crucial tool in the Kubernetes security arsenal as they provided a comprehensive framework for defining and enforcing security policies and helped safeguard data, applications, and infrastructure.
This article will deeply dive into the world of PSPs and explore their functionality, significance, and ultimate depreciation.
The Pod Security Policy was essentially a cluster-level resource that could control security-sensitive aspects of pod specifications. It could define a set of conditions and restrict specific access. Pods needed to follow the set of capabilities and requirements specified by the PSP to be able to run on the corresponding cluster. PSPs were implemented via an admissions controller in Kubernetes and didn’t belong to a specific namespace or have any workload dependencies.
Kubernetes security with PSP
Understanding and implementing PSPs in a cluster helped follow the golden principle of least privilege. PSPs helped enable the least privilege concept by applying fine-grained controls of the clearance level for the different workloads present in a Kubernetes environment. This could be a restrictive PSP that was enabled by default, or it could be additional permissions for privileged workloads. Enabling PSPs and configuring them correctly could also help organizations meet core requirements of compliance standards like HIPPA, PCI, etc., since they mandate specific access controls.
PSPs provide a native control mechanism to prevent threats without impacting performance. Without PSPs, a Kubernetes service account could spawn overprivileged pods that cyber criminals could leverage and cause container breakouts. Without a mechanism to restrict pod security privileges, an attacker could do anything a docker command could, like using specific node resources, running a privileged container, etc.
PSP control aspects
Many control aspects could be defined using a PSP, including:
- Restricting access to the host network and namespaces the pod can access.
- Preventing privileged pods from starting and controlling privilege escalation.
- Limiting volumes a pod can access.
- Restricting users/groups a pod can run as.
PSPs and admission controllers
Implementing PSPs as admissions controllers in the Kubernetes API had three implications:
- The first one was that if a pod didn’t meet the requirements, it would be rejected before being scheduled on a cluster. The admissions controller acted as a gatekeeper who would not allow that pod to run.
- The second one was that once PSPs were enabled in a Kubernetes environment, every pod needed to be explicitly allowed without any middle ground.
- The third one was Role-based access control (RBAC). Service accounts require different abilities to run specific, permissive, or restrictive PSPs. So, to enable and implement PSPs, you needed to turn specific RBAC permissions on. Having separate RBAC permissions for different service accounts could become cumbersome and difficult to implement correctly.
PSP and RBAC
One of the major obstacles Ops teams faced when implementing PSPs was RBAC. RBAC was required to associate PSPs to the corresponding runtime pods. Since PSPs were a cluster-wide resource and were not associated with any workload by default, you needed to create a Role after creating a PSP to grant “use” access to the PSP.
So, we have the resource that would be used (the PSP) and the permission to use it (Role), but we still hadn’t defined the subject (who), as in who would be allowed to use that PSP. Every pod created in the cluster has an identity associated with a service account. If the service account is not specified in the pod, a default service account from the namespace is used. So now that you have the Role, the PSP, and the service account, you just need to declare a RoleBinding to associate the role created with the corresponding service account.
Although PSPs were a significant aspect of container security, they were deprecated and no longer recommended. One of the main reasons for the depreciation was that PSPs were known for being complex and challenging to configure. Secondly, PSPs were notorious for their lack of flexibility. Since PSPs were cluster-wide policies, they would be applied uniformly to all namespaces in a cluster. This made it difficult to accommodate various security requirements for different namespaces.
With maintenance overboard and a long list of other issues, PSPs were gradually deprecated and replaced by PodSecurity admission controllers and PodSecurity policies. These mechanisms are more flexible and fine-grained than PSPs, providing greater control and granularity at the namespace level. This enables developers to define security policies more accurately aligned with their application’s needs.
Kubernetes security is a constantly evolving domain fuelled by rapid innovation. Developers must stay current with the latest best practices and security features to fortify applications against vulnerabilities. It’s imperative to remember that security in Kubernetes is not a one-size-fits-all endeavor.