Detect a cluster-admin grant
The single most common privilege-escalation move on a Kubernetes
cluster is a ClusterRoleBinding whose roleRef is cluster-admin
and whose subjects include either a wildcard or a freshly-created
ServiceAccount. This recipe sets up an end-to-end detection in
about 5 minutes.
Prerequisites
Section titled “Prerequisites”- ugallu umbrella chart installed (audit-detection enabled, default
webhooksource). - The apiserver’s audit policy includes
Metadatalevel forclusterrolebindings.rbac.authorization.k8s.io. On self-managed control planes this is the default; managed control planes usually need a flag flip on the API server.
Verify audit-detection is up:
kubectl -n ugallu-system get deploy ugallu-audit-detectionkubectl -n ugallu-system logs deploy/ugallu-audit-detection \ | grep -i 'webhook listener'Write the rule
Section titled “Write the rule”apiVersion: security.ugallu.io/v1alpha1kind: SigmaRulemetadata: name: cluster-admin-grantedspec: description: | Detect creation or update of a ClusterRoleBinding whose roleRef.name is cluster-admin. match: verb: [create, update, patch] objectRef: resource: clusterrolebindings requestObjectGlob: - jsonPath: "$.roleRef.name" glob: ["cluster-admin"] emit: type: ClusterAdminGranted severity: critical class: Detection rateLimit: burst: 5 sustainedPerSec: 1kubectl apply -f rules/cluster-admin-granted.yamlkubectl get sigmarules cluster-admin-granted -o yamlThe rule’s Status.Compiled should flip to True within a
reconcile tick (under 1 second). If Status.ParseError is set, fix
the rule and re-apply - the operator hot-swaps the in-memory rule
set on every CR write.
Provoke a match
Section titled “Provoke a match”kubectl create clusterrolebinding test-attack \ --clusterrole=cluster-admin \ --serviceaccount=default:defaultObserve
Section titled “Observe”The SecurityEvent CR appears within a second or two:
kubectl get securityevents -A \ --sort-by=.metadata.creationTimestamp# NAME AGE TYPE SEVERITY# ugse-cluster-admin-...-xfb2 2s ClusterAdminGranted criticalInspect the full evidence:
kubectl get securityevent <name> -o yaml | yq .specYou should see:
type: ClusterAdminGrantedseverity: criticalclass: Detectionsubject.kind: ClusterRoleBinding,subject.name: test-attackevidence.requestObject.subjectscarrying the SA you bound
Wire forensics (optional)
Section titled “Wire forensics (optional)”If you want a forensics capture on this event, the default
ForensicsConfig already includes Detection + severity high|critical
in its trigger predicate. Add ClusterAdminGranted to
whitelistedTypes:
apiVersion: security.ugallu.io/v1alpha1kind: ForensicsConfigmetadata: { name: default }spec: trigger: classes: [Detection] minSeverities: [critical, high] whitelistedTypes: - ClusterAdminGranted # ... your other types requireAttested: trueNow every ClusterAdminGranted SE will be attested by attestor
into an AttestationBundle, then forensics will start a capture
pipeline against the granting subject if it is a Pod.
Cleanup
Section titled “Cleanup”kubectl delete clusterrolebinding test-attackkubectl delete sigmarules cluster-admin-grantedThe SE CR is retained per TTLConfig.spec.defaults.securityEvent
(default 168h for critical).