DEV Community

Yuvraj ๐Ÿงข
Yuvraj ๐Ÿงข

Posted on • Originally published at evalsocket.dev on

Generate polices ! Make Kubernetes life hassle free with Kyverno

Briefly, Kyverno is a policy engine built for Kubernetes. It runs as an admission controller that can mutate and validate incoming resources. Also, Kyverno can generate any type of resource-based on various triggers of the admission request.

kyverno

A Kyverno generates resources based on a given set of conditions or triggers (read more about match/exclude). Kyverno generates a policy that supports two types of generate rules.

Here is an example of a generated policy

  1. Copy a resource from one namespace to another namespace. It's similar to copy command in a shell. The user has to define the clone block for providing the source resource path. In the below example source is config-template configmap in the default namespace
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: basic-policy
spec:
  rules:
    - name: "Generate ConfigMap"
      match:
        resources:
          kinds:
          - Namespace
      generate:
        kind: ConfigMap # Kind of resource
        name: default-config # Name of the new Resource
        namespace: "{{request.object.metadata.name}}" # namespace that triggers this rule
        synchronize : true
        clone:
          namespace: default
          name: config-template
Enter fullscreen mode Exit fullscreen mode
  1. Generate a resource from inline data. In this type of generating policy users can define a defined data block directly in the policy.
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: basic-policy
spec:
  rules:
    - name: "Generate Secret (insecure)"
      match:
        resources:
          kinds:
          - Namespace
      generate:
        kind: ConfigMap
        name: config-app
        namespace: "{{request.object.metadata.name}}" # namespace that triggers this rule
        data:
          data:
            USERNAME: evalsocket=
            DATABASE: blog
        metadata:
          labels:
            purpose: config
Enter fullscreen mode Exit fullscreen mode

Both examples above will trigger when a new namespace is created then kyverno will automatically generate the configmap and secrets in the newly created namespace.

# Create a configmap in default namespace (We need this configmap for generating resources)
โžœ  evalsocket โœ— kubectl create configmap config-template -n default --from-literal=special.how=very
configmap/config-template created
โžœ  evalsocket โœ— kubectl apply -f namespace-configmap-secret.yaml
clusterpolicy.kyverno.io/basic-policy created
# Trigger the policy by creating a namespace
โžœ  evalsocket โœ— kubectl create namespace kyverno-example
namespace/kyverno-example created
#Verify the resources
โžœ  evalsocket โœ— kubectl get configmap,secret -n kyverno-example
NAME                       DATA   AGE
configmap/default-config   1      42s
configmap/config-app       1      42s

NAME                         TYPE                                  DATA   AGE
secret/default-token-rq4dx   kubernetes.io/service-account-token   3      42s
# We did it
Enter fullscreen mode Exit fullscreen mode

Now let's discuss the behavior of the field synchronize: true. If you enable synchronization that means that kyverno will manage your generated resources and administrators can only update/delete a resource from the policy. All direct action on generated resources will be blocked by the kyverno. And in case of clone rule, the cluster-admin can update/delete generated resources from the source resources.

# Let's try to delete configmap generated from default namespace. It should block your request basecause synchronize : true in case of generated configmap
โžœ  evalsocket โœ—  kubectl delete configmap default-config -n kyverno-example
Error from server: admission webhook "nirmata.kyverno.resource.validating-webhook" denied the request: Resource is managed by a Kyverno policy and cannot be update manually. You can edit the generate policy to update this resource.

#Now let's try to delete generated resource configmap that doesn't have synchronize : true and synchronize has default value false.
โžœ  evalsocket โœ—  kubectl delete configmap config-app -n kyverno-example
configmap "config-app" deleted

# Update Your configmap in default namespace  and check your update to see synchronize. Set special.how=why
โžœ  evalsocket โœ— kubectl edit configmap config-template -n default
configmap/config-template edited

โžœ  evalsocket โœ— kubectl get configmap default-config -n kyverno-example  -oyaml
apiVersion: v1
data:
  special.how: why
kind: ConfigMap
metadata:
  creationTimestamp: "2020-07-28T00:13:58Z"
  labels:
    app.kubernetes.io/managed-by: kyverno
    app.kubernetes.io/synchronize: enable
    kyverno.io/generated-by: Namespace--kyverno-example
  name: default-config
  namespace: kyverno-example
  resourceVersion: "1682"
  selfLink: /api/v1/namespaces/kyverno-example/configmaps/default-config
  uid: b683b4c1-c498-4c25-b018-aa0c63cbcf7f

Enter fullscreen mode Exit fullscreen mode

Let's try one more example. This time we will try to generate rbac from generate policy. By default kyverno service account doesn't have that permission, Admin has to manually provide access to kyverno service account. Please read more about kyverno role

Add admin privilege to kyverno for creating the role

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kyverno:policycontroller
rules:
  - apiGroups:
      - '*'
    resources:
      - '*'
    verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kyverno:userinfo
rules:
  - apiGroups:
      - '*'
    resources:
      - roles
      - clusterroles
      - rolebindings
      - clusterrolebindings
      - configmaps
    verbs:
      - create
      - delete
      - get
      - list
      - patch
      - update
      - watch
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: kyverno-admin-generate
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: kyverno:generatecontroller # clusterRole defined above, to manage generated resources
subjects:
  - kind: ServiceAccount
    name: kyverno-service-account # default kyverno serviceAccount
    namespace: kyverno
Enter fullscreen mode Exit fullscreen mode

Now we are ready for generating role and cluster role. let's take an example policy for generating role

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: "gen-role-policy"
spec:
  background: false
  rules:
  - name: "gen-role"
    match:
        resources:
          kinds:
            - Namespace
    generate:
        kind: Role
        name: "ns-role"
        namespace: test
        synchronize: true
        data:
          rules:
          - apiGroups: [""]
            resources: ["pods"]
            verbs: ["get", "watch", "list"]
Enter fullscreen mode Exit fullscreen mode

Follow the steps to generate roles

โžœ  evalsocket โœ—  kubectl apply -f gen-role-policy.yaml
clusterpolicy.kyverno.io/gen-role-policy created

โžœ  evalsocket โœ— kubectl create ns new
namespace/new created

โžœ  evalsocket โœ— kubectl get Role -n new
Enter fullscreen mode Exit fullscreen mode

Some use cases for the generate policy are

  1. Create default Network policies for each namespace
  2. Create default resource quotas for each namespace
  3. for more example please check best practices

Check out the Kyverno GitHub page to learn more about the generate policy and several other features, like validating and deny rule. Find more about kyverno in the previous post Kubernetes Policy Management with Kyverno..

Top comments (0)