<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: jai sandesh</title>
    <description>The latest articles on DEV Community by jai sandesh (@jai_sandesh_ls).</description>
    <link>https://dev.to/jai_sandesh_ls</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3583676%2F97aaabc2-1c57-4f36-a24e-1f760cba026d.png</url>
      <title>DEV Community: jai sandesh</title>
      <link>https://dev.to/jai_sandesh_ls</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jai_sandesh_ls"/>
    <language>en</language>
    <item>
      <title>Designing Conflict-Free Kyverno Policies: Patterns for Ownership, Scope, and Determinism</title>
      <dc:creator>jai sandesh</dc:creator>
      <pubDate>Mon, 09 Feb 2026 08:15:53 +0000</pubDate>
      <link>https://dev.to/jai_sandesh_ls/designing-conflict-free-kyverno-policies-patterns-for-ownership-scope-and-determinism-4dn2</link>
      <guid>https://dev.to/jai_sandesh_ls/designing-conflict-free-kyverno-policies-patterns-for-ownership-scope-and-determinism-4dn2</guid>
      <description>&lt;h3&gt;
  
  
  ▶️&lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In &lt;a href="https://dev.to/jai_sandesh_ls/kyverno-policy-conflicts-why-last-writer-wins-is-a-production-bug-1j7i"&gt;Kyverno Policy Conflicts&lt;/a&gt;, we saw a pattern of structural failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple policies mutating the same fields&lt;/li&gt;
&lt;li&gt;Validation rules assuming a state that mutations later invalidate&lt;/li&gt;
&lt;li&gt;Policy intent fragmented across independent rules&lt;/li&gt;
&lt;li&gt;Even when policies are “correct,” nothing prevents someone from introducing a conflicting policy later&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is not a blog about fixing YAML syntax or tweaking individual rules.&lt;/p&gt;

&lt;p&gt;It’s about designing policies so contradictions cannot exist in the first place.&lt;/p&gt;

&lt;h3&gt;
  
  
  🗺️&lt;strong&gt;The Strategy (High Level)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We prevent future contradictions using four layers, all enforceable by Kyverno:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;RBAC - Very few having access to creates, update,and delete the policy.&lt;/li&gt;
&lt;li&gt;Policy ownership – only one policy may own a given field.&lt;/li&gt;
&lt;li&gt;Intent isolation – policies for different intents must never overlap.&lt;/li&gt;
&lt;li&gt;Guardrail policies – deny creation of conflicting policies.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  👥&lt;strong&gt;RBAC&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;RBAC can provide a basic guard against policy tampering or the introduction of contradictory Kyverno policies by unknown or unauthorized actors. However, RBAC alone is not sufficient—it only controls who can act, not what they are allowed to change or why.&lt;/p&gt;

&lt;p&gt;There are two complementary ways to address this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Restrict access via RBAC&lt;/em&gt;&lt;br&gt;
Define strict &lt;code&gt;RoleBindings&lt;/code&gt; / &lt;code&gt;ClusterRoleBindings&lt;/code&gt; so that only approved users or groups are allowed to create, update, or delete Kyverno policies.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Enforce ownership with a Kyverno validating policy&lt;/em&gt;&lt;br&gt;
Add a validating policy that denies any modification to Kyverno policies unless the request originates from approved service accounts—typically the ones responsible for policy reconciliation, such as Argo CD or CI/CD systems.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example policy:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: ValidatingPolicy
metadata:
  name: only-argocd-can-manage-kyverno-policies
spec:
  validationActions:
    - Deny
  matchConstraints:
    resourceRules:
      - apiGroups: ["policies.kyverno.io"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE", "DELETE"]
        resources:
          - mutatingpolicies
          - validatingpolicies
          - generatingpolicies
          - deletingpolicies
          - imagevalidatingpolicies
          - policyexceptions
  variables:
    - name: sa
      expression: parseServiceAccount(request.userInfo.username)
  validations:
    - message: "Only Argo CD is allowed to create/update/delete Kyverno policies."
      expression: &amp;gt;
        variables.sa.Namespace == "argocd" &amp;amp;&amp;amp;
        variables.sa.Name == "argocd-application-controller"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🛡️&lt;strong&gt;Ownership + Guardrails&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The core idea is simple: every mutable JSON path must have exactly one owning policy, and the cluster must enforce it.&lt;br&gt;
Ownership means nothing if it isn’t enforced.Guardrails mean nothing without clear ownership.These two have to exist together.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
This policy owns the field entirely, encodes a complete and coherent intent, does not rely on execution order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: MutatingPolicy
metadata:
  name: canonical-security-context
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  mutations:
    - patchType: ApplyConfiguration
      applyConfiguration:
        expression: &amp;gt;
          Object{
            spec: Object.spec{
              securityContext: Object.spec.securityContext{
                runAsNonRoot: true,
                runAsUser: 1000
              }
            }
          }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once a single policy is defined as the owner of securityContext, no other policy should be allowed to change it.&lt;br&gt;
From that point on, the cluster must reject any new policy that tries to modify securityContext fields.&lt;/p&gt;

&lt;p&gt;The YAML below enforces this by denying the creation of such policies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: ValidatingPolicy
metadata:
  name: guardrail-security-context-ownership
spec:
  validationActions:
    - Deny
  matchConstraints:
    resourceRules:
      - apiGroups: ["policies.kyverno.io"]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources:
          - mutatingpolicies
  validations:
    - message: &amp;gt;
        spec.securityContext is owned by the canonical-security-context policy.
        Do not mutate it elsewhere.
      expression: &amp;gt;
        !object.spec.mutations.exists(m,
          m.applyConfiguration.expression.contains("securityContext")
        )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  🏷️&lt;strong&gt;Intent Isolation: Prevent Accidental Interaction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The rule is simple policies of the same kind but with different intentions must be clearly separated.&lt;br&gt;
This separation must be enforced through conditions in the policy spec. One of the most common and reliable ways to do this is by using labels to scope policy execution.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Intent via labels:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;metadata:
  labels:
    policy.intent: security

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Policies match only that intent:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;matchConstraints:
  resourceRules:
    - apiGroups: [""]
      apiVersions: ["v1"]
      resources: ["pods"]
      selector:
        matchLabels:
          policy.intent: security

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  📌&lt;strong&gt;Conculsion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Preventing policy conflicts isn’t about writing more rules it’s about setting clear boundaries.&lt;br&gt;
When ownership is explicit, intent is isolated, and guardrails are enforced, Kyverno policies stop interacting in surprising ways. Exceptions stay intentional, and future mistakes are blocked early.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>policyascode</category>
      <category>kyverno</category>
    </item>
    <item>
      <title>Kyverno Policy Conflicts: Why “Last-Writer-Wins” Is a Production Bug</title>
      <dc:creator>jai sandesh</dc:creator>
      <pubDate>Mon, 09 Feb 2026 08:14:19 +0000</pubDate>
      <link>https://dev.to/jai_sandesh_ls/kyverno-policy-conflicts-why-last-writer-wins-is-a-production-bug-1j7i</link>
      <guid>https://dev.to/jai_sandesh_ls/kyverno-policy-conflicts-why-last-writer-wins-is-a-production-bug-1j7i</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;▶️Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Kyverno has become the go-to policy engine for Kubernetes because it feels simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Policies are YAML,&lt;/li&gt;
&lt;li&gt;They run at admission time,&lt;/li&gt;
&lt;li&gt;No custom controllers required.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That simplicity is also why teams run into policy conflicts in production.&lt;/p&gt;

&lt;p&gt;Most Kyverno incidents are not bugs in Kyverno.&lt;br&gt;
They are caused by incorrect assumptions about how policies are executed.&lt;/p&gt;
&lt;h3&gt;
  
  
  🤔&lt;strong&gt;The Assumption Almost Everyone Makes&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Most teams implicitly assume at least one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Policies run in the order they are applied&lt;/li&gt;
&lt;li&gt;Cluster-scoped policies are evaluated before namespace-scoped ones&lt;/li&gt;
&lt;li&gt;Kyverno resolves conflicts deterministically&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ None of these assumptions are true.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Kyverno provides:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no policy priority,&lt;/li&gt;
&lt;li&gt;no guaranteed ordering across policies,&lt;/li&gt;
&lt;li&gt;no conflict detection between mutations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  🧠&lt;strong&gt;How Kyverno Actually Processes an Admission Request&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;For a single admission request, Kyverno evaluates policies in phases:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All matching &lt;code&gt;mutate rules&lt;/code&gt; are executed&lt;/li&gt;
&lt;li&gt;All matching &lt;code&gt;validate rules&lt;/code&gt; are evaluated&lt;/li&gt;
&lt;li&gt;All matching &lt;code&gt;generate rules&lt;/code&gt; are processed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This order is guaranteed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;What is not guaranteed:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The execution order between two different mutate policies&lt;/li&gt;
&lt;li&gt;The execution order between mutate rules across different policies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside a single policy, rules are processed top-to-bottom.Across multiple policies, order is explicitly undefined.&lt;/p&gt;
&lt;h3&gt;
  
  
  📌&lt;strong&gt;Concrete Failure Modes&lt;/strong&gt;
&lt;/h3&gt;
&lt;h4&gt;
  
  
  🧪&lt;strong&gt;Example1: Mutate vs Mutate: Where Things Quietly Break&lt;/strong&gt;
&lt;/h4&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️&lt;em&gt;The examples are written on kyverno version 1.17 and policies are created at the same time&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Consider two mutate policies that both match the same Pod.&lt;br&gt;
&lt;em&gt;Policy A&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: MutatingPolicy
metadata:
  name: enforce-non-root
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  mutations:
    - patchType: ApplyConfiguration
      applyConfiguration:
        expression: &amp;gt;
          Object{
            spec: Object.spec{
              securityContext: Object.spec.securityContext{
                runAsNonRoot: true
              }
            }
          }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Policy B&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: MutatingPolicy
metadata:
  name: force-run-as-user-0
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  mutations:
    - patchType: ApplyConfiguration
      applyConfiguration:
        expression: &amp;gt;
          Object{
            spec: Object.spec{
              securityContext: Object.spec.securityContext{
                runAsUser: 0
              }
            }
          }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What Kyverno Sees&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both policies match the same Pod&lt;/li&gt;
&lt;li&gt;Both apply mutations&lt;/li&gt;
&lt;li&gt;Kyverno applies both patches&lt;/li&gt;
&lt;li&gt;Execution order across policies is not guaranteed&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  🧪&lt;strong&gt;Example 2: Mutate vs Validate — Self-Inflicted Admission Failure&lt;/strong&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Scenario&lt;/em&gt;&lt;br&gt;
One policy mutates a resource to enforce a default.Another policy validates the same field assuming a different expected state.&lt;br&gt;
Both policies are correct in isolation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MutatingPolicy — Add default label&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: MutatingPolicy
metadata:
  name: add-default-app-label
spec:
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  mutations:
    - patchType: ApplyConfiguration
      applyConfiguration:
        expression: &amp;gt;
          Object{
            metadata: Object.metadata{
              labels: Object.metadata.labels{
                app: "default"
              }
            }
          }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ValidatingPolicy — Require a specific label value&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: policies.kyverno.io/v1
kind: ValidatingPolicy
metadata:
  name: require-app-frontend
spec:
  validationActions:
    - Deny
  matchConstraints:
    resourceRules:
      - apiGroups: [""]
        apiVersions: ["v1"]
        operations: ["CREATE", "UPDATE"]
        resources: ["pods"]
  validations:
    - message: "Label app=frontend is required"
      expression: "object.metadata.?labels.app.orValue('') == 'frontend'"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What Actually Happens&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mutation runs first and sets app=default&lt;/li&gt;
&lt;li&gt;Validation runs after mutation&lt;/li&gt;
&lt;li&gt;Validation fails because app=frontend is required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;❗ Admission denied.&lt;br&gt;
❗ Even if the Pod originally satisfied the validation rule.&lt;/p&gt;

&lt;h3&gt;
  
  
  📉&lt;strong&gt;&lt;em&gt;Why This Gets Worse at Scale&lt;/em&gt;&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With just one or two policies, these interactions are easy to reason about.&lt;/p&gt;

&lt;p&gt;At scale:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multiple teams mutate the same fields,&lt;/li&gt;
&lt;li&gt;validation rules encode different assumptions,&lt;/li&gt;
&lt;li&gt;scopes overlap silently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Failures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;don’t always happen immediately,&lt;/li&gt;
&lt;li&gt;often appear only for specific workloads,&lt;/li&gt;
&lt;li&gt;are hard to trace back to policy interaction, not policy logic.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Kyverno evaluates each policy independently.&lt;br&gt;
It does not infer intent or resolve conflicts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;💡Key Insight&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Kyverno evaluates policies independently; it does not infer or reconcile intent across them. When intent is fragmented across multiple policies, Kyverno will enforce all matching rules, even if their combined effects are contradictory. &lt;a href="https://dev.to/jai_sandesh_ls/designing-conflict-free-kyverno-policies-patterns-for-ownership-scope-and-determinism-4dn2"&gt;Part II presents design patterns to prevent this class of conflicts.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>policyascode</category>
      <category>kyverno</category>
      <category>devops</category>
    </item>
    <item>
      <title>Zero-Trust in Practice: Enforcing Time-Bound RoleBindings with Kyverno</title>
      <dc:creator>jai sandesh</dc:creator>
      <pubDate>Sun, 26 Oct 2025 17:32:41 +0000</pubDate>
      <link>https://dev.to/jai_sandesh_ls/zero-trust-in-practice-enforcing-time-bound-rolebindings-with-kyverno-5hl5</link>
      <guid>https://dev.to/jai_sandesh_ls/zero-trust-in-practice-enforcing-time-bound-rolebindings-with-kyverno-5hl5</guid>
      <description>&lt;h3&gt;
  
  
  👨‍💻Intro
&lt;/h3&gt;

&lt;p&gt;Temporary admin access in Kubernetes is messy.You grant a RoleBinding for debugging and forget to remove it congratulations, you now have a hidden cluster admin forever.&lt;br&gt;
I wanted to fix that with Kyverno no CronJobs, no cleanup scripts.&lt;/p&gt;

&lt;p&gt;This guide explains how to enforce temporary RoleBindings both at the cluster level and the namespace level, using Kyverno policies that clean up automatically.&lt;/p&gt;
&lt;h3&gt;
  
  
  ⚙️ Why Kyverno?
&lt;/h3&gt;

&lt;p&gt;Manual cleanup jobs are fragile.&lt;br&gt;
They rely on human discipline, timing, and extra components like scripts or CronJobs.Kyverno solves this at the policy level by using its inbuilt features&lt;br&gt;
It watches resources in real time and can automatically delete expired RoleBindings based on their labels.&lt;br&gt;
No sidecars, no containers, no scripting just YAML that enforces itself.&lt;/p&gt;
&lt;h3&gt;
  
  
  🏗️ High-Level Overview
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Give Kyverno permission to delete RoleBindings and ClusterRoleBindings.&lt;/li&gt;
&lt;li&gt;Use Kyverno’s built-in cleanup capability (cleanup.kyverno.io/ttl) to define expiration times.&lt;/li&gt;
&lt;li&gt;Kyverno will automatically remove the temporary elevated access when the TTL expires.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  🔧 Implementation
&lt;/h3&gt;

&lt;p&gt;Tested on:&lt;br&gt;
Kyverno: v1.15.2&lt;br&gt;
Kubernetes: v1.34&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step1: &lt;em&gt;Install Kyverno&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helm repo add kyverno https://kyverno.github.io/kyverno/
helm repo update
helm install kyverno kyverno/kyverno -n kyverno --create-namespace

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step2: &lt;em&gt;Grant Cleanup Permissions&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Kyverno’s cleanup controller requires permission to delete RoleBindings and ClusterRoleBindings.&lt;br&gt;
Create a ClusterRole and bind it to Kyverno’s service account (kyverno-cleanup-controller) in the kyverno namespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kyverno-cleanup-access
rules:
- apiGroups: ["rbac.authorization.k8s.io"]
  resources:
    - rolebindings
  verbs:
    - delete
    - get
    - list
    - watch
- apiGroups: ["rbac.authorization.k8s.io"]
  resources:
    - clusterrolebindings
  verbs:
    - delete
    - get
    - list
    - watch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kyverno-cleanup-access-binding
subjects:
- kind: ServiceAccount
  name: kyverno-cleanup-controller
  namespace: kyverno
roleRef:
  kind: ClusterRole
  name: kyverno-cleanup-temp-access
  apiGroup: rbac.authorization.k8s.io
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step3: &lt;em&gt;Create Temporary RoleBindings&lt;/em&gt;&lt;/strong&gt; &lt;br&gt;
I’ll create a RoleBinding (and assume the Role already exists). For elevated access, I’ll use the built-in edit Role as the example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create ns test-ns
kubectl create sa test

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;creating roles and rolebindings&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl create rolebinding edit-access-binding --clusterrole=edit --serviceaccount=test-ns:test --namespace=test-ns

kubectl create clusterrolebinding edit-access-clusterbinding --clusterrole=edit --serviceaccount=test-ns:test

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step4: &lt;em&gt;Add TTL Labels&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;
Label these RoleBindings with Kyverno’s built-in TTL label.&lt;br&gt;
This determines how long they should exist before automatic cleanup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl label rolebinding edit-access-binding cleanup.kyverno.io/ttl=60m -n test-ns

kubectl label clusterrolebinding edit-access-clusterbinding cleanup.kyverno.io/ttl=60m

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After 60 minutes, Kyverno will automatically delete both bindings — no scripts required.&lt;/p&gt;

&lt;h3&gt;
  
  
  🧾 Summary:
&lt;/h3&gt;

&lt;p&gt;Kyverno natively supports automatic cleanup using the cleanup.kyverno.io/ttl label.&lt;br&gt;
By granting it proper permissions, you can enforce expiration policies for RoleBindings, ClusterRoleBindings, or any other resources that need timed deletion.&lt;/p&gt;

&lt;p&gt;This approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminates manual cleanup scripts&lt;/li&gt;
&lt;li&gt;Prevents forgotten privileged bindings&lt;/li&gt;
&lt;li&gt;Keeps your cluster secure and self-governing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No external scheduler. No drift. Just policy.&lt;/p&gt;

</description>
      <category>kyverno</category>
      <category>kubernetes</category>
      <category>security</category>
      <category>automation</category>
    </item>
  </channel>
</rss>
