Stop Authority Amplification
References: [Hugging Face technical timeline](https://huggingface.co/blog/agent-intrusion-technical-timeline), [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/), and [EKS identity guidance](https://docs.aws.amazon.com/eks/latest/best-practices/identity-and-access-management.html)
The enterprise problem and today’s slice
Enterprise problem: A local foothold becomes an enterprise incident when one workload identity can read secrets, alter cluster policy, reach the network, and reuse source-control credentials.
Whole-course context: The evidence ledger identifies the claims; the sandbox map identifies a compromised worker. This day removes privilege edges from that worker.
Today’s slice: Implement independently revocable workload identity, namespace-scoped RBAC, secret delivery, and egress policy.
End-of-day evidence: A denied privilege-escalation probe, a revoked workload identity, and a healthy peer service request.
Still unsolved: Incident-specific forensic conclusions remain outside the public evidence and organisational response plan.
Customer outcome and implementation focus
The platform owner needs one compromised evaluator to remain one compromised evaluator. The key decision is to bind capability to a short-lived workload identity rather than place broad, reusable credentials in a pod or shared secret.
| Story ID | User story | Observable acceptance |
|---|---|---|
| D03-US-01 | As a platform owner, I want the evaluator restricted to its namespace and approved API verbs, so that it cannot alter cluster-wide policy. | kubectl auth can-i denies cluster role binding creation for the evaluator identity. |
| D03-US-02 | As an incident responder, I want workload authority revocable without redeploying other services, so that containment has a bounded blast radius. | Revoking one identity produces access denial while a peer workload continues to serve its health request. |
Components in focus
Authority amplification happens at handoffs, not in a single “security layer.” The table names the compute process, its owner, and the durable policy or evidence state at each handoff.
| Layer | Component and owner | Compute/runtime | Storage | Responsibility and evidence |
|---|---|---|---|---|
| Workload | Evaluator service account, ML platform | Non-root Job pods | No credential cache; projected token is short-lived | Names the workload principal; pod UID and token audience are evidence. |
| Cluster | RBAC authorizer, cluster operator | API server control plane | etcd owns Role and RoleBinding state | Allows only named namespace verbs; authorization decision is auditable. |
| Cloud | Workload identity federation, cloud security | Token exchange endpoint | Cloud IAM policy store | Exchanges a trusted subject for a narrow cloud role; provider audit log proves issuance. |
| Secrets | Secret manager, application security | CSI mount or runtime fetch | Secret manager owns secret bytes and versions | Delivers one named secret without Kubernetes Secret replication; access event proves read. |
| Network | Egress policy, network security | CNI and proxy | Git policy plus flow logs | Allows named destinations; denied flow record proves isolation. |
The service account is a workload name, not permission by itself. RBAC and cloud federation each make an independent decision; neither implies access through the other boundary. The shared audit sink correlates their decisions by pod identity and time.
Bind a workload to a narrow Kubernetes role
Cluster-admin bindings are an amplification edge because any code in the pod can act as the cluster. Bind a Role, not a ClusterRole, to the evaluator service account and list only the read verbs needed for its own namespace.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata: { name: evaluator-read, namespace: evaluations }
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata: { name: evaluator-read, namespace: evaluations }
subjects:
- kind: ServiceAccount
name: evaluator
roleRef: { apiGroup: rbac.authorization.k8s.io, kind: Role, name: evaluator-read }
Declared intent: permit only read access to ConfigMaps in evaluations. Interpreter: the Kubernetes API server authorizer reads these objects from etcd on every API request. Software effect: requests outside the role are denied. Hardware effect: no new compute is created; API-server and etcd capacity process the authorization lookup. Evidence: kubectl auth can-i create clusterrolebindings --as=system:serviceaccount:evaluations:evaluator must return no.
Revoke and prove containment
Revocation is incomplete when it only deletes a configuration row but leaves a valid credential or network path. Delete the workload’s federation binding, wait for its short token to expire, make one scoped cloud call, and prove a peer identity still works.
kubectl auth can-i get configmaps -n evaluations --as=system:serviceaccount:evaluations:evaluator # Expected: yes.
kubectl auth can-i create clusterrolebindings --as=system:serviceaccount:evaluations:evaluator # Expected: no.
kubectl get pods -n payments -l app=payments-api # Unaffected positive control.
Decision rule: every edge from a workload to cluster, cloud, secret, or network authority must have its own owner, scope, audit signal, and revocation path.
Before and after, side by side
A shared credential collapses every authority boundary: any compromised process inherits all of them. Workload-scoped authority makes each handoff explicit and independently removable.
Key takeaways
- Identity in the pod, Kubernetes RBAC, cloud IAM, secrets, and egress are separate decisions.
- Test containment with one denied escalation probe and one unaffected peer workload.
Checklist
- [ ] The evaluator has no cluster-wide binding or reusable cloud secret.
- [ ] Each authority edge has a revocation event and audit proof.