Hello all,
This is the fourth blog on the series, this post focuses on Adminission Controller. How it can be useful at cluster level? We will look into practicle examples and their respected results.
But before moving ahead, lets first understand what is Admission Controller
AC is a component in kubernetes which controls the resources at cluster level. Control the resources means, it allows what is allwoed to deploy and what is not. So whenever the developer trying to deploy the restricted configuration, the admission controller gets notified by using the webhook URL and validate or mutate the configurations.
These are two components that are very important to understand.
Validate: It checks wheather it validates the configuration is valid or invalid, if it is invalid, do not deploy.
Mutate: This checks if the configuration is valid, do Nothing. But if it is invalid, then mutate it to the default pre-defined settings. For ex: If hostPath set to '/' then we can mutate it to '/someotherpath/' so when any POD or Deployment contains hostPath value '/' will turns to '/someotherpath'
We can either create our own Admission Controller, where we can create webhooks where we can define the mutate and validate componets, but this will be a very time consuming but if you wanted to understand from its core, then create it manually. Otherwise we can use Kyverno or OPA.
Keyverno creates a Admission Controller which intercepts the requests coming from KubeAPI server, and then perform execution of mutate or/and validate policies against the requests. The whole process is automated, you do not need to add the webhooks manually, Kyverno create webhooks automatically.
helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace
Now we will look into practical examples
We wanted to ensure that each and every ROLE we created must not contain super admin privileges.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: pod-reader
rules:
- apiGroups: [""]
resources: ["*"]
verbs: ["*"]
So what we will create is a Policy, that will check if any of the misconfigurations are trying to deploy in the cluster, do not deploy them.
this is the example of Kyverno Policy
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: validate-rbac-policies
spec:
validationFailureAction: enforce
background: true
rules:
- name: validate-rbac-policies
match:
any:
- resources:
kinds:
- Role
- ClusterRole
validate:
message: "Do not implement dangerous permissions"
deny:
conditions:
any:
- key: ""
operator: Equals
value: true
what exactly this policy is doing is, it match the kind of the configuration, is it a Role or ClusterRole. Once it identified, it sends the validate request to admission controller via HTTP Webhook which validate the Kind against the policies that we defined. We defined deny if only the condiction applied. And the condition here is, it checks the resources if it is set to '*' if it is set to '*' deny the deployment of Role inside the cluster.
And as a result, we received an error
In this example we will try to validate the POD Security Standards, if set insecurely, do not deploy.
This is the policy that we created
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: validate-ns-permission
spec:
validationFailureAction: enforce
background: true
rules:
- name: validate-ns-permission
match:
any:
- resources:
kinds:
- Namespace
validate:
message: "Privileged PSA Found"
pattern:
metadata:
labels:
=(pod-security.kubernetes.io/enforce): "!privileged"
=(pod-security.kubernetes.io/audit): "!privileged"
=(pod-security.kubernetes.io/warn): "!privileged"
This Policy deny the deployment of Namespace if any Namespace configuration contains any lable set to privileged.
Now if we try to deploy Namespace (the configuration is on right side in image) with any of these lables, we received the error.
The error we received
Now we will execute an exmaple of Mutation. Suppose we wanted to deploy the default configurations so whenever the developer applied the configurations that are not the default, the mutationwebhook will convert the configurations to default one. Lets see how
We wanted to change 'privileged' to 'restricted'. So we created a mutate policy.
In the left hand side, we can see that we added mutate instead of validate. And we defined 'restricted' for the lable 'pod-security.kubernetes.io/enforce'. In the right hand side we can see we are tyring to deploy 'privileged' permission to the namespace. We deployed namespace as below:
So after deploying the Namespace, we received no error, why? If you have remember we also had the validate policy which checks if 'privileged' is set then don't deploy. So why are not we receiving any error?
Because mutation webhooks always take preference first then validation webhooks. So once we apply the namespace, the mutation webhook called, it changes the 'privileged' value to 'restricted' and then validate webhook called, which checks no 'privileged' was used (as it turns to restricted by mutation webhook) and we recevied no errors. So we successfully mutate objects by using Kyverno.
This could help in securing Kubernetes Environment at the earliest stage. We can use automated tools after this, so if somehow we deployed vulnerable configuration, the automated tools could suggessfully caught the misconfiguration and notified the developer. We will talk these in later posts
https://kyverno.io/
https://github.com/kyverno/kyverno
That's all folks, I hope you find this useful. Let me know if you have anysuggestions.
Contact me on twitter- agrawalsmart7
Have a great weekend
Thanks for your time