DEV Community

Cover image for I Built a Read-Only kubectl So AI Agents Can't Break My Cluster
Mustafa Veysi Soyvural
Mustafa Veysi Soyvural

Posted on • Originally published at github.com

I Built a Read-Only kubectl So AI Agents Can't Break My Cluster

Last month I gave Claude access to one of our staging clusters. Within minutes it tried to kubectl exec into a pod and ran kubectl get secret -o yaml. Nothing bad happened — but it made me think: what if it had been production?

So I built kubectl-ro.

What it does

It's a thin wrapper around kubectl that only allows read-only commands. You use it exactly like kubectl:

kubectl-ro get pods -n kube-system        # works
kubectl-ro logs deployment/my-app          # works
kubectl-ro delete pod nginx                # nope
# ✘ BLOCKED: 'delete' is a mutating command
Enter fullscreen mode Exit fullscreen mode

That's it. If the command would change anything in your cluster, it gets blocked before kubectl ever sees it.

Why not just use RBAC?

You absolutely should use RBAC. But RBAC is server-side — it requires cluster admin setup, service accounts, role bindings. kubectl-ro is client-side. You install it, point your AI agent at it, and you're done. No cluster changes needed.

Think of it as a seatbelt, not a replacement for airbags.

It also protects secrets

This was the part that surprised me most. Even "read-only" kubectl can leak sensitive data:

kubectl get secret db-creds -o yaml    # prints base64-encoded passwords
kubectl describe secret db-creds       # same thing, different format
Enter fullscreen mode Exit fullscreen mode

kubectl-ro blocks these. You can list secrets (names and types), but you can't extract values. In MCP mode, secret values are replaced with [REDACTED] automatically.

It works as an MCP server too

This is the part I'm most excited about. Run kubectl-ro serve and it becomes an MCP server with 20 read-only tools that any AI agent can use:

{
  "mcpServers": {
    "kubectl-ro": {
      "command": "kubectl-ro",
      "args": ["serve"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Now your AI can list_pods, get_pod_logs, list_deployments, get_events — all the things you'd want it to see, nothing it shouldn't touch.

How the policy works

There's no config file. The policy is baked into the binary on purpose — you can't accidentally misconfigure it.

The logic is simple:

  • Mutating commands (delete, apply, create, exec, scale, drain...) → always blocked
  • Read commands (get, describe, logs, top, events...) → allowed, with secrets checks
  • Unknown commands → blocked by default (fail-safe)

It also rejects arguments with control characters, which prevents a class of prompt injection attacks where an LLM hallucinates weird bytes.

Every action is logged

Everything goes to ~/.kubectl-ro/audit.log:

{"timestamp":"2026-03-29T13:04:36Z","action":"get pods","result":"allowed"}
{"timestamp":"2026-03-29T13:04:36Z","action":"delete pod x","result":"blocked","reason":"'delete' is a mutating command"}
Enter fullscreen mode Exit fullscreen mode

So if something weird happens, you can see exactly what was attempted.

Try it

go install github.com/soyvural/kubectl-ro@latest
Enter fullscreen mode Exit fullscreen mode

Or grab a binary from the releases page.

You can test the policy without running anything:

kubectl-ro --check get pods           # prints: OK
kubectl-ro --check delete pod nginx   # prints: BLOCKED
Enter fullscreen mode Exit fullscreen mode

Put it on your PATH and it works as a kubectl plugin too: kubectl ro get pods.


The repo is at github.com/soyvural/kubectl-ro. It's MIT licensed, written in Go, and has zero external runtime dependencies.

If you're giving AI agents access to your clusters, I'd love to hear how you're handling the safety side. What's your approach?

Top comments (1)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.