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'.

derived any cloud emits CanFederateAs

match

A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.

{'pod_identity': None} ExternalIdentityMapsTo {'cloud_identity': None}

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 typeWorkloadIdentity
target typeRole
source?pod_identity
target?cloud_identity
conditionstrust_condition
state logicDELEGATED 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).
move · open · esc close