Hello Everyone!! Myself Vivek Kumar Sahu, sophomore(at the time of writting this blog) in Electronics and Telecommunication from Jabalpur Engineering College, India. My field of interests are cloud based technology as well as Linux world. I started exploring all these technologies just after Lockdown started and continued learning Linux and cloud-based technologies. After learning wanted to apply my knowledge and skills through some projects. Then i came to know that best way to make use of your skills and knowledge is by contributing to some open source project or by working in a company. But, being a student open source would be good choice. From there open source took place in my mind. Seriously, if you are complete beginner then 1-2 months you have to roam around the projects, meetings, slack channels, etc. And once you have understanding about the projects then you have to roam around the code written in those projects. It's not easy in the beginning but later on it is.
After exploring different projects from CNCF, I came across a Sandboxed project known as Kyverno.
And it was my right decision to pick the Kyverno project for contribution. For newbie contributor this is one of the good project to start their contribution with it and the reason behind it:-
Firstly, the Kyverno policies written for Kubernetes resources are written in the same language(i.e. YAML) as the resource manifest written in the Kubernetes.
secondly, easy to relate different concepts of Kubernetes while applying different types of policies for different resources. So, it looks quite a relatable project with my skills.
After one month of exploring this project I got an opportunity from Nirmata company (drives Kyverno Project) to work as an intern for 3 months in Kyverno Project.
The mentor assigned to me was shuting zhao and she is currently maintainer of the Kyverno project. She is really a calm, helpful and supportive in nature. She understand beginner contributor and gives time to settle down.
Kyverno is the policy engine for Kubernetes. In technical terms Kyverno is care-taker of Kubernetes in terms of security. If you want to understand Kyverno in more detail, will recommend to you go through these blogs:-
During internship, I had to work on
feature enhancement and it was To extend the test command to support or handle mutate Policy and also
To cover all sample policies. The same reaction I also had earlier after reading this project headline. Didn't understand anything. So, the recommendation to newbie contributors that the best way to understand any project is to read the documentation first and then install that project in your local machine and try to use it, play with it until and unless you get the feel about that project.
Let me explain about this
enhancement feature which I had to work upon. The feature needed to be added in the
Kyverno-CLI to extend the support of the
test command to support or handle
mutate policy. At that time
test command used to support for
validate policy but not for
generate policy. So, it was like a extension feature for
test command to also support for
Let me break the topic into 2 parts i.e.
What is test command, it's uses and how it works and
What is mutate policy and describe them separately.
test is a command (in the Kyverno-cli) like other commands, which provides facility to test policies on resources before deploying policy directly to the cluster. To be more specific
test command provides facility to the user to check or test the policies whether it's properly working on resources or not. Since, it's related to security of Kubernetes resource, so it is recommended to check policies before directly applying to live clusters.
But how does the test command make sure that whatever policy applied on resources is correctly applied or not ??
Good question. Here comes the actual use of
test command. Basically
test command internally work is compares the actual result which is generated from Kyverno engine with expected result provided by the user.
Note: that expected result provided by the user may be wrong but actual result obtained from engine can not be. And if you want to get the actual result then use
apply command. To know more about apply command visit here.
Let's understand more detail how test command works ?
As the user will run below command,
$kyverno test <path of folders containing test.yaml file>
First of all,
test command looks for it's configuration file i.e.
test.yaml in the provided folder by the user.
name: mytests policies: (contains list of path of policies file) - <path/to/policy.yaml> - <path/to/policy.yaml> Resources: (contains list of path of resource file) - <path/to/resource.yaml> - <path/to/resource.yaml> variables: variables.yaml (optional) results: - policy: <name> rule: <name> resource: <name> kind: <name> patchedResource: <path/to/patchedResource.yaml> (path of patchedResource file) status/result: <pass/fail/skip>
Path of Policy provided by the user under the
policies section in the
test.yaml file is fetched from it and similarly all resources are fetched from the path of resources provided by the user under the resources section in the
test.yaml file. After the policies and resources are fetched from the respective paths, then the policy with the help of
selects the resources one by one. If the policy doesn’t selects the resource then policy
skip that resource, which means the rule of the policy won’t be applied to that resource.
But if policy selects the resource which means that the further rule of the policy will be applied to resources and
Lastly, irrespective of policy applied on resource or not applied, the Kyverno engine will generates a result which is known as an
actual result or
And also on the
other hand, user also need to provide the
expected result or
user-defined result under the
results section of the
Expected result here means that what user thinks of the result could be after policy applied on resources. The
common fields on whose basis comparison of
actual result or
engine response with
expected result or
user-defined result are done:-
policy name(name of the policy),
resource name(name of the resource),
kind(type of resource),
patchedResource(path of patched resource or updated resource file,
Pass ----> when policy selects the resource and rule applied on the resource + patchedResource obtained from the engine response must be equal to the patched Resource provided by the user
Fail ----> when policy selects the resource and rule applied on the resource + patchedResource obtained from the engine response is not equal to the patched Resource provided by the user
Skip ----> When policy doesn’t select the resource because the resource description doesn’t match with the match/exclude block of rule of the policy, therefore rule is not applied on the resource. So, policy skips the resource.
As the mutate names suggest mutating something or updating something. Here updation could be anything like removing of any field or addition of any field or replacing of any field on Kubernetes resources. And resources updated through mutation policy is known as patched Resource.
This was the overall design part of how the test command will work with mutate policy.
Let's see the hand's on using
test command for
Let's try to understand the
field in the Policy first.
ClusterPolicy --> which means selecting resources in all namespaces or cluster wide.
metadata: ---> it is the name of Policy
spec: ---> name of the rule,
- name: add-labels
here coincidently, the name of policy is same as rule name. But don't think that they are related something like that. They are totally independent.
NOTE:- Under the rule section there can be one or more than one rules. But the type of policy i.e. validate/mutate/generate must be any among them throughout the policy.
The policy wants to say that selects all the resource of
kind: Pod in whole cluster(i.e. in all namespaces). And after selecting resources add the label
foo: bar to those resources.
apiVersion: kyverno.io/v1 kind: ClusterPolicy metadata: name: add-labels annotations: pod-policies.kyverno.io/autogen-controllers: none policies.kyverno.io/description: >- Labels are used as an important source of metadata describing objects in various ways or triggering other functionality. Labels are also a very basic concept and should be used throughout Kubernetes. This policy performs a simple mutation which adds a label `foo=bar` to Pods, Services, ConfigMaps, and Secrets. spec: rules: - name: add-labels match: resources: kinds: - Pod mutate: patchStrategicMerge: metadata: labels: foo: bar
Below is the resource of
kind: Pod. Which means it will be selected by the policy.
apiVersion: v1 kind: Pod metadata: name: myapp-pod spec: containers: - name: nginx image: nginx:latest
Below, is the patchedResource with added label
foo: bar with it. After mutate rule is applied to the above resource, label
foo: bar will be added to that resource, the resource gets updated because of that. And updated resource is known as a patchedResource.
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: foo: bar spec: containers: - name: nginx image: nginx:latest
Below, is the configuration file of
test command. It contains path of above policies, path of above resources, path of above patched resource and results defined by the user.
name: add-labels policies: - add_labels.yaml resources: - resource.yaml results: - policy: add-labels rule: add-labels resource: myapp-pod patchedResource: patchedResource.yaml kind: Pod result: pass
Now run the below command:-
$ kyverno test <path_of_folder_containing_test.yaml_file>
Executing add-labels... applying 1 policy to 1 resource... │───│────────────│────────────│───────────│────────│ │ # │ POLICY │ RULE │ RESOURCE │ RESULT │ │───│────────────│────────────│───────────│────────│ │ 1 │ add-labels │ add-labels │ myapp-pod │ Pass │ │───│────────────│────────────│───────────│────────│ (base)
Namespaced-policy are applied only on particular namespace.
First of all, let's read out the policy. It says that select resource of
kind: Pod from
testing namespace and after selecting mutate or add the below field in it.
- name: ndots
apiVersion: kyverno.io/v1 kind: Policy metadata: name: add-ndots namespace: testing annotations: policies.kyverno.io/title: Add ndots policies.kyverno.io/category: Sample policies.kyverno.io/subject: Pod policies.kyverno.io/description: >- The ndots value controls where DNS lookups are first performed in a cluster and needs to be set to a lower value than the default of 5 in some cases. This policy mutates all Pods to add the ndots option with a value of 1. spec: background: false rules: - name: add-ndots match: resources: kinds: - Pod mutate: patchStrategicMerge: spec: dnsConfig: options: - name: ndots value: "1"
apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: foo: bar namespace: testing spec: containers: - name: nginx image: nginx:latest
Patched Resource with added
- name: ndots
in the resource.
apiVersion: v1 kind: Pod metadata: labels: foo: bar name: myapp-pod namespace: testing spec: containers: - image: nginx:latest name: nginx dnsConfig: options: - name: ndots value: "1"
name: add-nodeselector policies: - policy.yaml resources: - resource.yaml results: - policy: testing/add-ndots rule: add-ndots resource: myapp-pod patchedResource: patchedResource.yaml namespace: testing kind: Pod result: pass
$ kyverno test <path>
Executing add-nodeselector... applying 2 policies to 1 resource... │───│───────────────────│───────────│───────────────────────│────────│ │ # │ POLICY │ RULE │ RESOURCE │ RESULT │ │───│───────────────────│───────────│───────────────────────│────────│ │ 1 │ testing/add-ndots │ add-ndots │ Pod/testing/myapp-pod │ Pass │ │───│───────────────────│───────────│───────────────────────│────────│
The difference in the
test.yaml between the
Namespaced policy and
ClusterPolicy is in their name of
policy under the
results section. If it is a
Namespaced policy then user need to provide the policy name as:
whereas if it is a
ClusterPolicy then policy name as: .
Namespaced policy is applied to resources present in that particular namespace. Whereas
ClusterPolicy is applied in all namespaces present in whole cluster.
1) There are 2 types of policies:-
ClusterPolicy --> Applied on whole cluster
Policy --> Applied on a particular namespace, which means it will only select those resources having the same namespace as namespaced policy.
Initially the solution works fine for ClusterPolicy but it wasn't supporting namespaced Policy. So, for the same I have to understand the concept of namespaced policy and then apply separate checks to filter resources according to the namespace of the policy.
I think you all have got the basic idea about this enhancement feature for Kyverno-cli. And to know more about the Kyverno project go to kubectl get kyverno project
I would highly thanks to Jim Bugwadia for giving this opportunity. And once again highly thankful to my mentor Shuting zhao, for her continuous support and guidance throughout the project. And also special thanks to Vyankatesh, Pooja and Chip Zoller for their continous help. It was really amazing to work with this community. I don't know how these 3 months passed, it seems like it started only a few days ago. In these 3 months learned many new things from the community members.
That was all from mine side. Thanks for reading it. Hope you liked it. If you have any doubt regarding the Kyverno project join the slack channel.
Resources for beginners wanted to contribute to Kyverno project:-
Kyverno --> https://github.com/kyverno/kyverno
Kyverno policies ---> https://kyverno.io/policies/
Youtube channel ---> https://www.youtube.com/c/Nirmata/videos
golang resources --> https://gobyexample.com/ and https://zetcode.com/all/#go