workload-identity-federates
A Kubernetes workload-identity binding (KSA<->GSA / IRSA / AKS Workload Identity) lets the pod's projected SA token federate into a cloud Role/ServiceAccount; escalation roll-ups are federation-chains'.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?pod_identity) in [
WorkloadIdentity, FederatedIdentity, ExternalIdentity, ServiceAccount] # the pod's projected ServiceAccount identity
?pod_identity is a Kubernetes workload identity (GKE WI KSA / EKS IRSA SA / AKS WI SA)
node_type(?cloud_identity) in [Role, ServiceAccount, MachineIdentity] # the cloud identity the pod assumes
exists TrustsExternalIdentity(?anchor -> ?pod_identity) backing this mapping (the cloud Role/SA OIDC trust on the cluster issuer)
emit
| source type | WorkloadIdentity |
|---|---|
| target type | Role |
| source | ?pod_identity |
| target | ?cloud_identity |
| conditions | trust_condition |
| state logic | DELEGATED to federation-chains federation-maps-to-identity: ACTIVE when the cluster-OIDC trust condition is BROAD/UNPINNED (the cloud Role/SA accepts any namespace/KSA `sub`, a wildcard/shared aud, or the binding maps any pod in a namespace an attacker can schedule into), CONDITIONAL(trust_condition) when pinned to a specific namespace:serviceaccount the attacker cannot run a pod as, BLOCKED if the cluster OIDC provider is disabled/deleted. This rule inherits that exact state — it is the same collapse keyed to a k8s pod ?pod_identity; do not compute a stronger state here. |
Narrative
The pod workload identity {pod_identity.name} is bound to the cloud identity {cloud_identity.name} via the cluster's OIDC issuer (KSA<->GSA / IRSA / AKS Workload Identity); a pod running as {pod_identity.name} presents a token {cloud_identity.name}'s trust accepts, federating in as {cloud_identity.name} with no static credential (federation-chains rolls up the foothold and impersonation).
Raw rule rules/derived/container-chains.yaml
id: workload-identity-federates
emits: CanFederateAs
description: A Kubernetes workload-identity binding (KSA<->GSA / IRSA / AKS Workload Identity) lets the
pod's projected SA token federate into a cloud Role/ServiceAccount; escalation roll-ups are federation-chains'.
applies_to:
- '*'
match:
- - pod_identity: null
- ExternalIdentityMapsTo
- cloud_identity: null
where:
- 'node_type(?pod_identity) in [WorkloadIdentity, FederatedIdentity, ExternalIdentity, ServiceAccount] #
the pod''s projected ServiceAccount identity'
- ?pod_identity is a Kubernetes workload identity (GKE WI KSA / EKS IRSA SA / AKS WI SA)
- 'node_type(?cloud_identity) in [Role, ServiceAccount, MachineIdentity] # the cloud identity the pod
assumes'
- exists TrustsExternalIdentity(?anchor -> ?pod_identity) backing this mapping (the cloud Role/SA OIDC
trust on the cluster issuer)
emit:
source_type: WorkloadIdentity
target_type: Role
source: ?pod_identity
target: ?cloud_identity
permissions: []
conditions:
- trust_condition
state_logic: "DELEGATED to federation-chains federation-maps-to-identity: ACTIVE when the cluster-OIDC\
\ trust condition is BROAD/UNPINNED (the cloud Role/SA accepts any namespace/KSA `sub`, a wildcard/shared\
\ aud, or the binding maps any pod in a namespace an attacker can schedule into), CONDITIONAL(trust_condition)\
\ when pinned to a specific namespace:serviceaccount the attacker cannot run a pod as, BLOCKED if\
\ the cluster OIDC provider is disabled/deleted. This rule inherits that exact state \u2014 it is\
\ the same collapse keyed to a k8s pod ?pod_identity; do not compute a stronger state here."
confidence: min(contributing_confidences)
derived_from:
- ?pod_identity ExternalIdentityMapsTo ?cloud_identity
- ?anchor TrustsExternalIdentity ?pod_identity (cluster OIDC trust)
false_positive_note: "CITE, DO NOT DUPLICATE federation-chains: this rule exists only to name the k8s\
\ workload-identity case explicitly and dedupes with federation-chains federation-maps-to-identity\
\ on (CanFederateAs, ?pod_identity, ?cloud_identity) \u2014 emit once. The CanEnter*/CanImpersonate/escalation\
\ roll-ups off this CanFederateAs are federation-chains' (federate-then-enter-*, federate-inherits-capabilities)\
\ \u2014 never re-derive them here. The whole judgment is the OIDC trust pin: an IRSA trust whose\
\ `sub` is `system:serviceaccount:NS:SA` bound to a namespace/SA the attacker cannot run a pod as\
\ is a legitimate control => CONDITIONAL(trust_condition), not ACTIVE. An UNPINNED binding (the Role\
\ trusts `system:serviceaccount:*:*`, or the attacker can create/schedule a pod as the trusted KSA\
\ \u2014 e.g. via rule 2 exec or pod-create RBAC in that namespace) is ACTIVE. Do NOT treat mere existence\
\ of workload identity as compromise. If ?cloud_identity is a plain User the CanFederateAs target\
\ set excludes it \u2014 keep it FederatesTo (see federation-chains). A disabled cluster OIDC issuer\
\ => adapter emits no trust => this rule does not fire."
narrative: The pod workload identity {pod_identity.name} is bound to the cloud identity {cloud_identity.name}
via the cluster's OIDC issuer (KSA<->GSA / IRSA / AKS Workload Identity); a pod running as {pod_identity.name}
presents a token {cloud_identity.name}'s trust accepts, federating in as {cloud_identity.name} with
no static credential (federation-chains rolls up the foothold and impersonation).