How to Migrate From Kubernetes Pod Security Policies (PSPs) to Kyverno
Migrating from Kubernetes PSP to Kyverno is just as simple as defining any other Kubernetes resource.
Join the DZone community and get the full member experience.
Join For FreeSince its genesis, Kubernetes has been the go-to container orchestration solution for enterprises needing scalable containerized applications implemented on microservices architecture. It essentially deals with the Pod as the most basic unit, which may hold one or more containers. Since any application deployed within Kubernetes is executed through one or more Pods, it is important for the user to ensure that they are secure from misconfigurations and security breaches. Thus, Pod security is not just a major concern but a necessity for Kubernetes clusters and even more for business-critical applications.
To fulfill this need, Kubernetes introduced PodSecurityPolicy in its v1.3 release. However, PodSecurityPolicy has been officially deprecated by Kubernetes in the v1.21 release and has been entirely removed in the v1.25 release, which was a step taken due to some major issues encountered by users throughout the years of its use that could not be addressed without introducing breaking changes (more details could be found on an official post made by Kubernetes).
The Purpose of PodSecurityPolicy
PodSecurityPolicy (PSP) is an admission controller that is built within Kubernetes. It serves the purpose of controlling security-sensitive aspects of the Kubernetes Pods specification. For example, if your use case demands that the Pods must be restricted from accessing the host system’s resources, devices, and kernel capabilities, you would want to avoid running Pods in your cluster in a privileged mode. To accomplish this, the corresponding PSP definition would be as shown below:
Snippet 1: Sample PSP Definition to Restrict Privileged Pods
apiVersion: policy/v1beta1
kind: PodSecurityPolicy
metadata:
name: restrict-privileged-pods
spec:
privileged: false
seLinux:
rule: RunAsAny
supplementalGroups:
rule: RunAsAny
runAsUser:
rule: RunAsAny
fsGroup:
rule: RunAsAny
volumes:
- '*'
But the removal of PSP in the Kubernetes v1.25 release does not mean that it’s an end for Pod security at all. It will be replaced by a Pod Security Admission (PSA) controller, which utilizes the Kubernetes admission control webhooks. The PSA controller, however, comes with some serious drawbacks, such as the inability to mutate the incoming resource, no enforcement of Pod controllers, and unconfigurable messages, to name a few. You can find a list of all the pros and cons of PSA and their detailed explanation in this session conducted by the Kyverno maintainers Shuting Zhao (Staff Engineer, Nirmata) and Chip Zoller (Technical Product Manager, Nirmata).
Kyverno for Kubernetes Native Policy Management
Created by Nirmata, later donated to the Cloud Native Computing Foundation (CNCF), and currently, a CNCF Incubating project – Kyverno is a policy engine that is specifically designed for Kubernetes. While having significant advantages over the PSA controller, it utilizes the Kubernetes admission control webhooks to inspect the newly created or modified resources that attempt to make their way into the cluster. It does so by checking the definitions of resources in question-based on the Kyverno policies installed within the cluster. The policies can be scoped to the entire cluster using the ClusterPolicy
custom resource or a particular namespace within the cluster using the Policy
custom resource.
A sample Kyverno policy with a block-ephemeral-containers
rule definition to strictly block the usage of ephemeralContainers
within a Pod is shown below:
Snippet 2: Sample Kyverno Policy to Block Ephemeral Containers
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: block-ephemeral-containers
spec:
validationFailureAction: enforce
rules:
- name: block-ephemeral-containers
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Ephemeral containers are not permitted."
pattern:
spec:
X(ephemeralContainers): "null"
However, resource validation is just one of the four capabilities of Kyverno. The other three include resource mutation (modifying the incoming resource), resource generation (generating or creating new resources based on incoming resources), and supply chain security guarantees. But to stick to the scope of this article, only the validation of resources is explained throughout.
For steps on installing Kyverno, please visit the official Kyverno Installation documentation, and to explore all the available sample policies created by the Kyverno community (191 at the moment and counting), please visit the official Kyverno Policies webpage.
Writing Kyverno Policies
One might get intimidated by the thought of learning something entirely new to accomplish a requirement. It also seems quite tedious for cluster administrators to learn an entirely new language or technology to deliver and maintain a new requirement or behavior in their cluster. And when it concerns the security of the cluster itself, it certainly seems inevitable.
However, that’s not the case for Kyverno, for it is designed in a way that allows one to write policies for Kubernetes in the Kubernetes native fashion itself, that is, through YAML definitions in the form of Kubernetes custom resources. In essence, it makes it extremely simple for someone who knows how to work with Kubernetes but is new to Kyverno to understand the expected behavior of a Kyverno policy.
You have already seen a sample Kyverno policy in Snippet 2. A basic explanation for the policy defined there is as follows:
validationFailureAction: enforce
indicates that any resource which violates this policy will be blocked. Suppose validationFailureAction is set to audit instead of enforce. In that case, the policy violation is logged within the Kyverno policy report (see the official Kyverno Reporting documentation to learn more about policy reports). Still, the Kyverno Reporting documentation to learn more about policy reports) but the resource is allowed to be created.- The
rules
field stores a list of rules that you’d like to define within your policy. In this case, avalidate
rule is being used, which is being matched against any resource withkind: Pod
. - The
validate
field indicates that this rule will trigger a resource validation in case the incoming resources have matching kinds according to thematch
field. Thepattern
field insidevalidate
defines the pattern you want to look for when validating X(ephemeralContainers)
tells Kyverno that the key specified within the parentheses must not exist within the resource definition.X(),
in this case, is known as a Negation Anchor in Kyverno (see the official Kyverno Anchorsdocumentation to learn more about Anchors in Kyverno).
In case you’re interested in writing your very first policy or fulfilling a use case through your own Kyverno policy, you can find a very detailed guide in the official Kyverno documentation for writing policies.
Pod Security With Kyverno Policies
The equivalent Kyverno ClusterPolicy for the PSP defined in Snippet 1 is shown below.
Snippet 3: Sample Kyverno Policy Definition to Restrict Privileged Pods
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: restrict-privileged-pods
spec:
validationFailureAction: enforce
rules:
- name: restrict-privileged-pods
match:
any:
- resources:
kinds:
- Pod
validate:
message: "Rejected by restrict-privileged-pods rule."
pattern:
spec:
=(initContainers):
- =(securityContext):
=(privileged): false
=(ephemeralContainers):
- =(securityContext):
=(privileged): false
containers:
- =(securityContext):
=(privileged): false
With the explanation provided in the Writing Kyverno Policies section for the policy defined in Snippet 2, it must be quite easy to understand Snippet 3. Here, instead of the Negation Anchor, you can observe the usage of Equality Anchor =()
. The purpose of Equality Anchor is to validate the existence of the key provided within the parentheses. If the key exists, it proceeds with validating its value. If that key further has a child element that is enclosed within the Equality Anchor, then the child element is further evaluated as a validation pattern.
For example, a simple explanation for=(securityContext):
=(privileged): false
would be:
“If the key is equal to securityContext
, and if the child element of securityContext
has a key equal to privileged
, then the value for the privileged
key should be equal to false
”
Migrating from Kubernetes PSP to Kyverno is just as simple as defining any other Kubernetes resource.
Published at DZone with permission of Abhinav Sinha. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments