lolspider / notes
Clipping · 8 分钟

Kyverno is a platform primitive, not a security tool

Where does Kyverno live in your organization? I don’t mean which cluster! On which team’s slide deck does it show up? Whose budget line? For most companies I’ve…

cncf.io audra

📝 摘要

作者指出 Kyverno 长期被错误归类为安全工具,导致大多数组织只使用其 validation(验证)能力,而忽略了 mutate(变更)、generate(生成)、verify images(镜像验证)三个建设性动词——它们占了 Kyverno 四分之三的功能。文章提出 Kyverno 应被视为平台原语(platform primitive),与 Pod、Service 一样是构建平台的基础组件,具备抽象复杂性、提供保证、可组合、自服务四大属性。平台团队利用 Kyverno 实现了 namespace 自动配置、sidecar 注入、镜像引用重写、默认资源请求注入、所有权标签等能力,这些都不是安全场景,而是开发者体验和运维卫生的"无聊但承重"的工作。核心重新框架:策略即平台表达组织意图的 API——将信念从文档和人的头脑中搬到系统中,成为自动、不可见的执行。

核心概念: Kyverno 不是站在集群门口的保安,而是平台的结缔组织——将平台的"观点"变成平台的"行为"。

关键技术栈 / 关键要点:

  1. 四个动词层级 — Validation=护栏、Mutation=铺设道路、Generation=脚手架、Verification=信任,Mutation 被严重低估
  2. 平台原语四属性 — 抽象复杂性、提供保证、可组合、自服务,Kyverno Policy 满足全部四项
  3. 策略即产品 — 策略应有版本、用户、废弃周期和异常流程,渐进发布(审计→警告→强制)成为标准交付方式
  4. GitOps 扩展 — Policy repo 与 app manifests 同等重要,但也带来 Argo CD/Flux 与 Kyverno mutation 的协调冲突
  5. 安全框架的局限 — "策略=拒绝"的心智模型导致只用 Kyverno 1/4 能力,三个建设性动词被浪费

关键结论 / 实践建议: 重新审视 Kyverno 文档,将其视为平台 SDK 而非安全手册;从 Mutation 入手释放 Kyverno 的真正潜力;将策略视为代码产品,采用渐进发布流程。


Where does Kyverno live in your organization? I don’t mean which cluster! On which team’s slide deck does it show up? Whose budget line?

For most companies I’ve talked to, the answer is security. Kyverno is evaluated alongside OPA/Gatekeeper, approved by the security team, deployed with a bundle of Pod Security Standard policies, and then… mostly sits there, blocking the occasional root container.

Meanwhile, the teams actually getting interesting value out of Kyverno are the ones doing things with it that make me stop and take notes. These are almost never security teams. They are platform teams. And I don’t think that’s a coincidence. I think we’ve filed Kyverno in the wrong mental category, and that miscategorization is costing us access to most of what the tool can do.

I’ve been circling this observation for a while. My first Kyverno conference talk, back at KCD Munich 2023, was literally titled “Securing Your Kubernetes Workloads with Kyverno” — I was filing it in the security drawer myself. Three years of production work later, my talks are about governance, CEL, and platform self-service, and my post on the Platform Engineering blog argued that Kyverno has outgrown “policy engine” as a description entirely. This post is me finally putting the underlying claim in one sentence, and it’s the opening argument of a longer series on policy-driven platform engineering: Kyverno is a platform primitive. Not a security tool that platform teams happen to use. A building block for platforms, in the same sense that Pods and Services are building blocks, that happens to also be useful for security.

The problem with the security framing

Let me be clear about what I’m not saying. Kyverno absolutely does security work. It blocks insecure configs, it enforces PSS, it verifies image signatures. If your CISO asks whether it helps with compliance, the answer is yes, genuinely.

But “security tool” carries a specific mental model with it: policy as a gate. Something bad shows up, the gate stops it. The primary verb is deny. Success gets measured in blocked deployments.

Now look at what Kyverno actually does. Four things: validate, mutate, generate, verify images. Only the first one fits the gate model. Mutation changes resources on their way into the cluster. Generation creates entirely new resources in response to things happening. Image verification is about establishing trust more than blocking threats, if you squint.

Three out of four verbs are constructive. They add things, change things, build things. And yet if you look at how most organizations deploy Kyverno, it’s validation policies wall to wall. That’s the security framing expressing itself in the config. When your mental model is “policy = deny,” you end up using a quarter of the tool.

Okay, so what’s a “platform primitive”

I should define the term since I’m hanging the whole post on it. When I say primitive, I mean it the way programming languages mean it: a small, well-understood building block that you compose bigger things out of. For a platform, I’d say a primitive needs four properties:

  1. It abstracts complexity. Developers use it without understanding the machinery underneath.
  2. It provides guarantees. Using it means certain properties hold automatically.
  3. It composes. You combine it with other primitives to build higher-level stuff.
  4. It’s self-service. You get it from the platform, not from a ticket queue.

Pods, Services, ConfigMaps: primitives. Crossplane compositions: primitives. And I want to convince you Kyverno policies belong on that list too.

What platform teams actually do with it

The best way I know to make this concrete is just to list the things I’ve seen platform teams build with Kyverno once they stopped thinking of it as a security scanner with opinions.

Namespace furnishing. A developer creates a namespace, and Kyverno generates the default NetworkPolicy, ResourceQuota, LimitRange, RoleBindings, and others. Nobody reads a wiki page listing the six things you’re supposed to remember. The namespace shows up furnished.

Sidecar injection. Observability agents, mesh proxies, secret sync containers – they’re all mutated into Pod specs at admission. The developer’s Deployment manifest stays clean and boring. The platform’s requirements get met anyway. Nobody negotiated anything.

Image reference rewriting. This one’s my favorite because it’s so simple and saves so much aggravation. Your platform wants images pulled through an internal mirror. You could ask every developer to remember mirror.internal/ prefixes forever, and they won’t, and you’ll have flaky builds when Docker Hub rate-limits you. Or Kyverno rewrites nginx:1.25 to mirror.internal/nginx:1.25 at admission and the whole problem just… stops existing. Developers write the natural thing. The right thing happens.

Default resource requests. Instead of blocking Pods without CPU/memory requests, which is technically correct but practically infuriating, inject workload-appropriate defaults. The scheduler gets what it needs. Developers deal with it when they actually need to tune something, not before.

Ownership labels. Team, cost center, environment. Enforce them where ambiguity is real, default them where it isn’t.

Read that list again and notice: none of it is security. It’s developer experience and operational hygiene—the boring, load-bearing work of running a platform.

What ties it together is that each one takes a belief the organization holds about how things should work and turns it into automatic, invisible enforcement. Nobody has to remember. That’s what a primitive does: it makes a guarantee so you don’t have to think about it.

Policy is how the platform expresses intent

Every organization has beliefs about how things should run. Some are security beliefs, like no root containers and only signed images. Some are operational, like everything has resource limits. Some are financial, like everything has a cost-center label. Some are honestly just cultural, like every deployment traces back to a catalog entry somewhere.

The traditional home for these beliefs is documentation. Wikis, onboarding decks, PR checklists, that one senior engineer who reviews everything. Which means enforcement is uneven, knowledge is tribal, and the platform team ends up as a human bottleneck because nothing works without someone in the loop.

Policy as code, versioned in Git, delivered by your GitOps tooling, and enforced by Kyverno is how those beliefs stop being documentation and become infrastructure. The platform’s rules stop living in people’s heads and start living in the system.

That’s the reframe, compressed: policy is the platform’s API for organizational intent.

What falls out of this

If you buy the reframe, some useful things follow, and they’re roughly the roadmap for the rest of this series.

The four verbs stop being a flat feature list and turn into a hierarchy of platform capabilities. Validation is guardrails. Mutation is paved roads. Generation is scaffolding. Verification is trust. Mutation in particular is wildly underused relative to how powerful it is. That gets its own post because I have a lot to say about it.

Policies start looking like products: versions, users, deprecation cycles, exception processes. Progressive rollout (auditing, then warning, then enforcing) stops being an advanced technique and becomes just how you ship a policy. Exceptions become tracked debt instead of quiet approvals buried in Slack threads.

And GitOps gets bigger. If policy is code and policy is how the platform expresses intent, the policy repo matters as much as the app manifests it governs. Your Argo CD or Flux isn’t just deploying workloads anymore. It’s deploying the rules that shape workloads. Which, by the way, opens up some genuinely tricky reconciliation questions when a policy mutates a resource that Argo CD thinks it owns. Also a future post. It’s a fun one if your idea of fun is sync loops.

The takeaway

Next time you’re in the Kyverno docs, try reading them as a platform SDK instead of a security manual. The API surface is bigger than the security framing suggests, and the things you can build on it are more interesting than “block bad Pods.”

Kyverno isn’t a bouncer standing at the door of your cluster. It’s connective tissue. It’s how the platform’s opinions become the platform’s behavior. Once that clicks, it’s hard to unsee — and the rest of this series is about what you do after it clicks.