The short answer
Give the agent its own kubeconfig, bound to the built-in view ClusterRole, so it can read most objects and delete nothing. Set the reclaim policy of any volume holding data you care about to Retain. Then add a pre-command hook to the agent that asks before kubectl delete namespace or kubectl delete pvc, for the times it runs with your own context instead.
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
What one delete can take
Two commands do most of the damage.
kubectl delete namespace. The Kubernetes docs put it plainly: this deletes everything under the namespace. The delete is asynchronous, so the namespace sits in Terminating for a while, but you can’t call it back.1 Every Deployment, Service, Secret, ConfigMap and claim in it goes.
kubectl delete pvc. Whether the data survives depends on the volume’s reclaim policy. With Delete, deletion removes the PersistentVolume object and the storage asset behind it, the cloud disk itself. Dynamically provisioned volumes inherit the reclaim policy of their StorageClass, and that defaults to Delete.2 So on many clusters, deleting a database’s claim deletes the database’s disk.
An agent tidying up “unused” resources after a test, or resetting a broken environment, reaches for exactly these two.
Step 1: a kubeconfig that can only look
Kubernetes RBAC is purely additive: there are no deny rules.4 You can’t take a delete away from a role that has it; you can only give the agent a role that never had it. The built-in view ClusterRole is a good start. It allows read-only access to most objects in a namespace and does not allow viewing roles, role bindings or Secrets. edit, by contrast, allows read and write access to most objects.4
Create a service account for the agent and bind view in the namespaces it should see:
Code A settings file: the rules a tool reads before it acts.
apiVersion: v1
kind: ServiceAccount
metadata:
name: coding-agent
namespace: staging
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: coding-agent-view
namespace: staging
subjects:
- kind: ServiceAccount
name: coding-agent
namespace: staging
roleRef:
kind: ClusterRole
name: view
apiGroup: rbac.authorization.k8s.io
Then check what the account can do before you hand it over. kubectl auth can-i answers yes or no for an action, and --as checks it for another identity:5
Code Commands typed in a terminal. The text around it says what happens.
kubectl auth can-i list pods -n staging --as=system:serviceaccount:staging:coding-agent
kubectl auth can-i delete namespaces --as=system:serviceaccount:staging:coding-agent
kubectl auth can-i delete persistentvolumeclaims -n staging --as=system:serviceaccount:staging:coding-agent
You want yes, no, no. Build a kubeconfig for that service account and point the agent’s environment at it with KUBECONFIG. Your own admin context stays out of the agent’s reach.
Because view doesn’t include Secrets, the agent can’t read the credentials that would let it act as another service account, which the RBAC docs call out as a form of privilege escalation.4
Step 2: make volumes outlive their claims
Even with careful RBAC, people run agents under their own admin context. Make the data survive a deleted claim anyway. With the Retain policy, deleting a claim doesn’t delete its PersistentVolume.3
Code Commands typed in a terminal. The text around it says what happens.
kubectl patch pv <your-pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
kubectl get pv
The RECLAIMPOLICY column in kubectl get pv should now read Retain for that volume.3 For new volumes, create a StorageClass with reclaimPolicy: Retain and use it for stateful workloads. The trade-off is cleanup: retained volumes stay until an administrator reclaims them by hand,2 so you pay for disks nobody uses until someone looks.
Step 3: a hook before the shell
A hook in the coding agent sees kubectl commands before they run. We ran Deedglass’s shell guard from 0.13.0 against the delete commands an agent is likely to type.6
| Command | Answer |
|---|---|
kubectl delete namespace staging |
asks |
kubectl delete ns prod |
asks |
kubectl delete pvc data-postgres-0 |
asks |
kubectl delete pod web-1 |
nothing |
kubectl delete deployment web |
nothing |
helm uninstall postgres |
nothing |
Code What the screen or file shows, copied as is.
$ npx deedglass@0.13.0 guard shell --no-files --command 'kubectl delete pvc data-postgres-0'
Deedglass asks first: kubectl delete pvc deletes a namespace and everything in it, or a volume claim or volume whose storage the Delete reclaim policy deletes too.
kubectl-delete-storage kubectl delete pvc deletes a namespace and everything in it, or a volume claim or volume whose storage the Delete reclaim policy deletes too
The catalog row covers namespaces, claims and volumes: the deletes that can remove stored data.6 It lets pods and deployments through: they hold no stored data, and a guard that asked about every one would train people to click yes.
helm uninstall was the honest gap in that table: a chart can own claims and Secrets, and 0.13.0 had no row for it. 0.14.1 added one, so helm uninstall postgres now gets an ask; kubectl delete deployment still passes.6 The RBAC layer is still what protects you when the hook can’t see the command. The same is true of anything the hook can’t read: a value known only at run time, such as a script or Makefile target that calls kubectl, passes untouched.6 And if the hook can’t run at all, the command goes ahead unchecked.6
Install it with npx deedglass protect, which adds the guard to Claude Code, Cursor, Codex CLI, Gemini CLI and Copilot CLI; the protect walkthrough shows each file.
A checklist for agent cluster access
Work down this list before an agent gets a kubeconfig:
- The agent has its own service account, not your user.
- It’s bound to
view(or a narrower Role), only in the namespaces it needs. -
kubectl auth can-i delete namespaces --as=…saysno. -
kubectl auth can-i get secrets --as=…saysno. - Volumes holding data use
Retain, or a StorageClass that does. - Production contexts aren’t in the kubeconfig the agent loads.
- A pre-command hook asks before namespace, claim and volume deletes.
- You know how to stop the agent quickly. Our post on an AI agent kill switch covers the options.
If an agent needs to change things in the cluster, give it a Role with the exact verbs and resources, in one namespace, and keep delete on namespaces and claims out of it. The same thinking applies to infrastructure code: see stopping an agent running terraform destroy, what blast radius means for agent credentials, and the wider checklist before an agent touches production.
To see the guard’s answer for a command, run npx deedglass guard shell --no-files --command 'kubectl delete ns staging'. It reads the command and never runs it. To grade what an agent can reach on your own machine, run npx deedglass scan (what the grade means). To watch the checks without installing anything, open the playground.
Written with AI assistance and checked against our claims register.