
Overview
Some companies implement a policy on their Kubernetes clusters to ensure that every configuration and setup is deployed in accordance with applicable rules, to meet sound security standards, and, most importantly, to comply with the ISO 27001 standard, which requires that every running workload meet minimum security standards based on the CIS Benchmark.
Background
GitOps is a common practice found in many organizations. By integrating Kubernetes manifest management—for example, using Helm charts and ArgoCD—the deployment workflow for Kubernetes workloads becomes controllable and auditable. However, does this approach cover everything? Unfortunately, this mechanism only covers the client-side, where in a business-as-usual scenario, users are required to create manifests using templates from provided charts—which sometimes also impose restrictions on helper files.These templates are meant to ensure conventions and governance remain within established guidelines—for example, every deployment must have a “team” tag, or a container image must not use the “latest” tag. However, these mechanisms only enforce compliance on the client-side. The same applies to ArgoCD: ArgoCD only ensures that running workloads align with the declarative manifest stored in the VCS. Although it offers auto-sync and auto-heal features, both still have time intervals that could potentially create security vulnerabilities. So, how can we ensure security not only on the client-side but also on the server-side? What if a user has access to the cluster with a role that allows them to create or modify existing workloads? It’s entirely possible for that user to escalate their privileged access to perform uncontrolled actions. That’s where Kyverno comes in....
Bottom line:
Helm’s helpers.tpl and ArgoCD’s self-heal feature bridge the gap between “what’s in Git” and “what’s in the cluster.” However, both assume that the entire resource lifecycle originates from and is controlled solely through the Git → Helm render → ArgoCD apply pipeline. As soon as a resource originates from another path—such as a controller/operator, subchart, runtime debug, a reconciliation time gap, or a tooling compromise—that protection no longer applies. Kyverno closes that gap because it is positioned not within a “specific deployment pipeline,” but within the API server itself, so its scope automatically covers all of the above paths without needing to know where the resource came from.
Explanation
Kyverno runs on a Kubernetes Admission Controller (KAC, a component of the Kubernetes API Server), intercepting incoming requests to the Kubernetes API before they are forwarded and stored in etcd, and performing mutations and validations on them. In addition, Kyverno also functions as a controller, using a watch-and-reconcile mechanism to generate new rules or modify existing ones in response to activities or events that occur.
The following is a flowchart showing how Kyverno reviews and patches incoming requests from clients.

The following is Kyverno’s flow as a controller that performs watch-and-reconcile events or activities.

Use Case
Kubernetes has a native, built-in admission controller commonly referred to as podSecurity or PSA (Pod Security Admission). PSA has only three profiles: privileged, baseline, and restricted. Once you apply a profile, all the controls within it take effect simultaneously; you cannot selectively enable or exclude specific controls, for example, on a per-image or per-container basis.
For example, suppose you want to use the “restricted” profile for all namespaces starting with “prod-*,” but there’s a Cadvisor container that needs access to the host’s /proc directory. This causes that container to fail the Seccomp check. PSA also only has the capability to block at the pod level, not at the controller level. As a result, a Deployment or StatefulSet can remain deployed even if its pods are not, which will create “ghost” events or resources due to control desynchronization.
Use cases that can only be fulfilled using Kyverno (not possible with standard native Kubernetes):
- Auto-restart a Deployment when the Secret it uses changes (mutate-existing).
- Automatically generate a default-deny NetworkPolicy and ResourceQuota when a new namespace is created (generate).
- Verify image signatures (Sigstore/cosign/Notary) before a pod is allowed to run.
- Automatically mutate image tags to digests to make the image immutable.
- Granular exceptions per image/container against a single security profile (e.g., exclude a single container from a restricted profile without compromising the entire namespace) —> this is not possible with native PSA.
- Validate cross-resource dependencies (e.g., check that labels are unique across the cluster, or that a field in one resource matches a field in another resource).
- Synchronize content between resources (e.g., copy data from one ConfigMap to another ConfigMap in a different namespace).
- Native compliance reporting within the cluster (Policy Reports) without relying on external audit logs.
- Combining validate + mutate + generate within a single policy definition for an end-to-end scenario (e.g., generate a new resource, then mutate that resource once it’s successfully created).
- Testing policies in CI before they reach the cluster (Kyverno CLI), including manifest checks against the Restricted Pod Security Standard without requiring a running cluster.
Why do we need it?
Kubernetes doesn’t have a single place to manage “policies” comprehensively.
- RBAC handles who can access what
- ResourceQuota and LimitRange handle resource quotas
- NetworkPolicy handles network traffic
- PSA handles pod security. These four components operate independently, have different configuration methods, and none of them can be used to create policies specific to our own business needs—such as “images must come from the internal registry” or “all resources must have a ‘team’ label.” Kyverno unifies all of these into a single policy model written in YAML.
Another issue is that all of those built-in mechanisms are purely for validation, and even then, their scope is limited. None of them can automatically “correct” or create new resources on their own if something is missing. Kyverno has the capability to do that—it can mutate existing resources and even automatically generate new ones—a capability that no native mechanism possesses.
As for PSA, even though it’s a built-in Kubernetes feature, it actually has quite a few limitations. It applies only to Pods, operates on an all-or-nothing basis per profile, cannot be customized per image or per container, has very rigid exceptions, and we cannot get violation reports directly within the cluster—we have to go through audit logs located outside the cluster.
And most importantly, the ecosystem has been around for a long time and is well-established. There are hundreds of ready-to-use policies available in the official library; it supports image signature verification (Sigstore/Notary); there are Policy Reports to monitor compliance; and a CLI for testing policies directly in CI. So we don’t need to build separate tools to get all of this.
Kyverno vs. Similar Tools: Benchmarks & Trade-offs
An objective comparison of Kyverno against OPA/Gatekeeper, Kubewarden, and native Kubernetes features (ValidatingAdmissionPolicy/MutatingAdmissionPolicy), based on Kyverno 1.13 vs. Gatekeeper 3.18 (early 2026 release) and the official documentation for each project.
| Dimension | Kyverno | OPA/Gatekeeper | Kubewarden (WASM) | Native K8s (ValidatingAdmissionPolicy / MutatingAdmissionPolicy) |
|---|---|---|---|---|
| Simple policy evaluation latency | ~1–3 ms | ~0.5–2 ms (Pre-compiled Rego is indeed faster in this scenario) | Varies, depending on WASM module complexity | Fastest; runs directly within the API server, without a network hop to a webhook |
| Complex policy latency (requires additional API lookups) | ~10–30 ms | Tends to be slower if there are many constraint templates and recompilation is required | Can slow down significantly if many resources are queried | Not possible; CEL does not support external calls, so rules this complex cannot be created here at all |
| Cold-start (time until the policy is ready to enforce, e.g., after a restart/upgrade) | Fast, since it only involves parsing YAML | Can take over 30 seconds on large deployments because hundreds of Rego templates must be recompiled | Depends on the number of modules loaded | Instant, since it’s part of the server API |
| Memory footprint | ~600MB total (4 controllers) in large deployments; ~2GB per replica with hundreds of policies | More sensitive to the number of constraint templates; can reach up to 4GB per replica in large deployments | Not much public data available yet; tends to increase with the number of running WASM modules | Minimal overhead since it runs on top of the API server that’s already running |
| Policy language | YAML (+ CEL for the latest policy kind) | Rego (specialized language, steep learning curve) | General-purpose compilation languages (Go, Rust, etc.) compiled to WASM | CEL |
| Mutation | Mature, widely used in production | Available (Assign/AssignMetadata), but rarely used seriously in production | Depends on each policy’s implementation | Available (MutatingAdmissionPolicy), but just reached GA in v1.36 (April 2026); still new |
| Generate / auto-provision other resources | Available (GeneratingPolicy) | No equivalent mechanism | None | Not possible at all |
| Image / supply chain verification | Built-in (Sigstore/Notary) | Requires additional components outside of Gatekeeper itself | Depends on custom policies written | Not possible (CEL cannot call external services) |
| Flexibility for complex/non-standard logic | Limited to CEL/JMESPath expressions | Strong, since Rego is a general-purpose policy language | Most flexible; can use any logic in a standard compiled language | Limited to CEL |
| Resources that can be queried in policies | Extensive, almost all resources + CRDs | Extensive | Limited; currently only Namespaces, Ingresses, and Services | Limited to the object being reviewed |
| Project maturity status | CNCF Graduated | CNCF Graduated (OPA project) | Still growing, smaller community | Native, but mutation features are just GA |
Conclusion
If the primary parameter is purely “speed per request,” Gatekeeper or native VAP/MAP might have a slight edge in some scenarios. However, when operational costs (cold-start, memory), feature completeness (validate + mutate + generate + image verification in a single package), and ecosystem maturity are factored in, Kyverno excels in the combination of all these factors—though this doesn’t mean it wins outright on every individual metric.

Overview
Beberapa perusahaan menerapkan sebuah policy pada kubernetes cluster yang mereka miliki guna memastikan setiap konfigurasi dan setup dapat terdeploy sesuai dengan rule yang berlaku, untuk memenuhi standard security yang baik dan utamanya untuk memenuhi standard ISO 27001 yang mengharuskan setiap workload yang running memiliki standard minimum security standard based on CIS Benchmark.
Background
GitOps merupakan hal yang umum yang sering kita temui pada banyak organisasi, dengan mengawinkan management kubernetes manifest misalnya dengan menggunakan Helm charts dan juga ArgoCD, flow deployment dalam konteks kubernetes workload menjadi dapat dikontrol dan diaudit, namun apakah approach tsb sudah mengcover semuanya? sayangnya, mekanisme tsb baru mengcover client-side area, dimana dalam case business-as-usual user diharuskan membuat manifest dengan menggunakan template dari chart yang disediakan yang dimana terkadang juga ada restriction pada file helpers.tpl untuk menjaga convention serta governance tetap pada koridornya, misalnya setiap deployment diwajibkan memiliki sebuah tag team atau sebuah container image tidak boleh menggunakan tag latest, namun mekanisme tsb hanya menjaga di domain client-side, hal yang serupa juga berlaku untuk ArgoCD, ArgoCD hanya memastikan workload yang running sesuai dengan declarative manifest yang di simpan pada VCS, walaupun ada fitur auto-sync dan auto-heal namun kedua fitur tsb tetap memiliki interval jeda waktu yang dapat berpotensi menjadi celah keamanan, lalu bagaimana menjaga bukan hanya di ranah client-side namun juga di ranah server-side? jika ada user yang memiliki akses kedalam cluster dengan role yang mumpuni untuk membuat atau memodifikasi existing workload? privileged access sangat dimungkinkan untuk di eskalasi oleh user tsb untuk melakukan tindakan yang tidak terkontrol. Oleh karena itu disini Kyverno hadir....
Intinya: Helm helpers.tpl + ArgoCD self-heal menutup celah "apa yang tertulis di Git vs apa yang ada di cluster". Tapi keduanya sama-sama berasumsi bahwa seluruh lifecycle resource berasal dan hanya dikontrol lewat jalur Git -> Helm render -> ArgoCD apply. Begitu ada resource yang lahir dari jalur lain; controller/operator, subchart, runtime debug, celah waktu reconcile, atau kompromi tooling itu sendiri, proteksi itu tidak berlaku. Kyverno menutup celah itu karena posisinya bukan di "jalur deployment tertentu", tapi di API server itu sendiri, sehingga cakupannya otomatis mencakup semua jalur di atas tanpa perlu tahu resource itu datang dari mana.
Explanation
Kyverno berjalan pada sebuah Kubernetes Admission Controller (KAC adalah component di Kubernetes API Server), bekerja dengan meng-intercept request yang masuk ke Kubernetes API sebelum request tsb diteruskan dan disimpan ke etcd dengan melakukan mutating dan validating. Selain itu, Kyverno juga berjalan sebagai controller dengan menggunakan mekanisme watch-and-reconcile untuk melakukan generating ataupun mutate-existing rule terhadap activity atau event yang terjadi.
Berikut adalah flow bagaimana Kyverno melakukan review dan patching terhadap request yang masuk dari client.

Berikut adalah flow Kyverno sebagai controller yang melakukan watch-and-reconcile event atau activity.

Use Case
Kubernetes memiliki native built-in admission contoller yang biasanya disebut podSecurity / PSA (Pod Security Admission), PSA hanya memiliki 3 profile yaitu privileged, baseline, dan restricted dan begitu kamu pakai satu profile, semua kontrol di dalamnya berlaku sekaligus, kamu tidak bisa pilih kontrol mana yang mau diaktifkan atau dikecualikan misalnya per image/container.
Contohnya kamu ingin menggunakan restricted profile untuk seluruh namespace prod-*, tapi ada container cadvisor yang butuh akses ke /proc host, hal tsb menyebabkan container tsb gagal cek ke Seccomp. PSA juga hanya memiliki kapability untuk melakukan blockir di level pod bukan di level controller, alhasil deployment / statefulset dapat tetap terdeploy walaupun pod nya tidak, hal ini akan menimbulkan event / resource "hantu" akibat adanya ketidaksinkronan control.
Use case yang cuma bisa dipenuhi kalau pakai Kyverno (tidak bisa dengan native Kubernetes biasa):
- Auto-restart Deployment begitu Secret yang dipakainya berubah (mutate-existing).
- Auto-generate NetworkPolicy default-deny dan ResourceQuota begitu Namespace baru dibuat (generate).
- Verifikasi signature image (Sigstore/cosign/Notary) sebelum Pod boleh jalan.
- Mutate tag image jadi digest secara otomatis supaya image jadi immutable.
- Exception granular per image/container terhadap satu profile keamanan (mis. exclude satu container dari restricted profile, tanpa melemahkan seluruh namespace) —> ini yang tidak bisa dilakukan PSA native.
- Validasi lintas resource yang saling terkait (mis. cek label harus unik di seluruh cluster, atau field satu resource harus cocok dengan field resource lain).
- Sinkronisasi konten antar resource (mis. copy data dari satu ConfigMap ke ConfigMap lain di namespace berbeda).
- Laporan kepatuhan native di dalam cluster (Policy Reports) tanpa bergantung ke audit log eksternal.
- Menggabungkan validate + mutate + generate dalam satu definisi policy yang sama, untuk satu skenario end-to-end (misalnya: generate resource baru, lalu mutate resource itu begitu berhasil dibuat).
- Testing policy di CI sebelum sampai ke cluster (Kyverno CLI), termasuk cek manifest terhadap Restricted Pod Security Standard tanpa perlu cluster yang jalan.
Why we need it?
Kubernetes tidak memiliki satu tempat untuk mengatur "policy" secara menyeluruh.
- RBAC ngurusin siapa boleh akses apa
- ResourceQuota sama LimitRange ngurusin kuota resource
- NetworkPolicy ngurusin lalu lintas network
- PSA ngurusin keamanan Pod. Empat hal ini jalan sendiri-sendiri, cara konfigurasinya beda-beda, dan tdak ada satupun yang bisa dipakai buat bikin aturan spesifik ke bisnis kita sendiri, misalnya "image wajib dari registry internal" atau "semua resource harus ada label team-nya". Kyverno menyatukan semua itu jadi satu model policy yang ditulis dalam YAML.
Masalah lain, semua mekanisme bawaan tadi sifatnya cuma validasi aja, dan itupun scope-nya sempit. Tidak ada satupun yang bisa otomatis "membetulkan" atau bikin resource baru sendiri kalau ada yang kurang. Kyverno punya kemampuan buat itu, bisa mutate resource yang sudah ada, bahkan bisa generate resource baru otomatis, yang tidak dipunyai mekanisme native manapun.
Soal PSA, walaupun ini fitur bawaan Kubernetes, kenyataannya keterbatasannya cukup banyak. Cuma berlaku buat Pod, semua-atau-tidak-sama-sekali per profile nya, tidak bisa dikustomisasi per image atau per container, exception-nya kaku banget, dan kita tidak bisa dapat laporan pelanggaran secara langsung di dalam cluster, harus lewat audit log yang letaknya di luar cluster.
Dan yang paling penting, ekosistemnya udah jalan lama dan matang. Ada ratusan policy siap pakai yang tinggal kita ambil dari library resminya, sudah support verifikasi signature image (Sigstore/Notary), ada Policy Reports buat pantau kepatuhan, plus CLI buat testing policy langsung di CI. Jadi kita tidak perlu rakit-rakit tool terpisah buat dapat semua ini.
Kyverno vs Tools Sejenis: Benchmark & Trade-off
Perbandingan objektif Kyverno terhadap OPA/Gatekeeper, Kubewarden, dan fitur native Kubernetes (ValidatingAdmissionPolicy/MutatingAdmissionPolicy), berdasarkan data benchmark Kyverno 1.13 vs Gatekeeper 3.18 (rilis awal 2026) dan dokumentasi resmi masing-masing proyek.
| Dimensi | Kyverno | OPA/Gatekeeper | Kubewarden (WASM) | Native K8s (ValidatingAdmissionPolicy / MutatingAdmissionPolicy) |
|---|---|---|---|---|
| Latensi evaluasi policy sederhana | ~1–3 ms | ~0.5–2 ms (Rego yang sudah dikompilasi memang lebih cepat di jalur ini) | Bervariasi, tergantung kompleksitas module WASM | Paling cepat; jalan langsung di dalam API server, tanpa network hop ke webhook |
| Latensi policy kompleks (butuh lookup API tambahan) | ~10–30 ms | Cenderung lebih lambat kalau constraint template banyak dan perlu recompile | Bisa melambat signifikan kalau resource yang di-query banyak | Tidak bisa; CEL tidak mendukung external call, jadi rule sekompleks ini tidak bisa dibuat di sini sama sekali |
| Cold-start (waktu sampai policy siap enforce, mis. setelah restart/upgrade) | Cepat, karena hanya parsing YAML | Bisa 30 detik lebih pada deployment besar karena harus recompile ratusan Rego template | Tergantung jumlah module yang di-load | Instan, karena memang bagian dari API server |
| Memory footprint | ~600MB total (4 controller) pada deployment besar; ~2GB per replica dengan ratusan policy | Lebih sensitif terhadap jumlah constraint template, bisa sampai 4GB per replica pada deployment besar | Belum banyak data publik, cenderung naik seiring jumlah module WASM yang berjalan | Overhead minimal karena menumpang di API server yang memang sudah berjalan |
| Bahasa policy | YAML (+ CEL untuk policy kind terbaru) | Rego (bahasa khusus, learning curve tinggi) | Bahasa kompilasi umum (Go, Rust, dll.) yang dikompilasi ke WASM | CEL |
| Mutation | Matang, dipakai luas di production | Ada (Assign/AssignMetadata), tapi jarang dipakai serius di production | Tergantung implementasi policy masing-masing | Ada (MutatingAdmissionPolicy), tapi baru GA di v1.36 (April 2026); masih baru |
| Generate / auto-provision resource lain | Ada (GeneratingPolicy) | Tidak ada mekanisme setara | Tidak ada | Tidak bisa sama sekali |
| Verifikasi image / supply chain | Ada bawaan (Sigstore/Notary) | Perlu tambahan di luar Gatekeeper sendiri | Tergantung policy custom yang ditulis | Tidak bisa (CEL tidak bisa memanggil layanan eksternal) |
| Fleksibilitas untuk logic kompleks/non-standar | Terbatas pada ekspresi CEL/JMESPath | Kuat karena Rego memang bahasa general-purpose untuk policy | Paling fleksibel; bisa pakai logic apa pun dalam bahasa kompilasi biasa | Terbatas pada CEL |
| Resource yang bisa di-query dalam policy | Luas, hampir semua resource + CRD | Luas | Terbatas; saat ini baru Namespace, Ingress, Service | Terbatas pada object yang sedang direview |
| Status kematangan proyek | CNCF Graduated | CNCF Graduated (proyek OPA) | Masih tumbuh, komunitas lebih kecil | Native, tapi fitur mutation-nya baru GA |
Kesimpulan
Kalau parameter utamanya murni "kecepatan per-request", Gatekeeper atau native VAP/MAP bisa menang tipis di beberapa skenario. Tapi begitu operational cost (cold-start, memory), kelengkapan fitur (validate + mutate + generate + image verification dalam satu paket), dan kematangan ekosistem dimasukkan, Kyverno unggul di gabungan semua faktor itu, bukan berarti menang mutlak di setiap metrik satu per satu.