gcp-datafusion-swap-pipeline-sa
datafusion.instances.update + iam.serviceAccounts.actAs on a target SA lets a principal replace the dataprocServiceAccount; all future pipeline runs execute as the new SA.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
?principal has effective datafusion.instances.update on the instance
node_type(?sa) in [
ServiceAccount, MachineIdentity]
?sa is an acceptable dataprocServiceAccount (roles/datafusion.runner + roles/dataproc.worker granted, or equivalent)
emit
| source type | Identity |
|---|---|
| target type | Compute |
| source | <principal> |
| target | <Cloud Data Fusion instance> |
| permissions | datafusion.instances.update iam.serviceAccounts.actAs |
| conditions | iam_permission role_compatibility |
| state logic | ACTIVE if datafusion.instances.update AND iam.serviceAccounts.actAs on ?sa are both confirmed in the effective grant. The downstream CanExecuteAs (can-execute-as execute-as-via-config-identity-swap: CanModifyConfiguration + CanPassIdentity → CanExecuteAs) is ACTIVE once both contributing edges are ACTIVE and role_compatible(?sa, instance) holds. CONDITIONAL(iam_permission) if actAs is unresolved. BLOCKED if a deny policy applies to either permission. |
Narrative
{principal.name} can update the Cloud Data Fusion instance {instance.name} (datafusion.instances.update) to replace its dataprocServiceAccount with {sa.name} (iam.serviceAccounts.actAs confirmed); all future pipeline runs execute as {sa.name}, granting {principal.name} effective code execution as {sa.name} via the next run.
Raw rule rules/derived/gcp/datastream.yaml
id: gcp-datafusion-swap-pipeline-sa
emits: CanModifyConfiguration
description: datafusion.instances.update + iam.serviceAccounts.actAs on a target SA lets a principal replace
the dataprocServiceAccount; all future pipeline runs execute as the new SA.
match:
- - ?principal
- CanPassIdentity
- ?sa
where:
- ?principal has effective datafusion.instances.update on the instance
- node_type(?sa) in [ServiceAccount, MachineIdentity]
- ?sa is an acceptable dataprocServiceAccount (roles/datafusion.runner + roles/dataproc.worker granted,
or equivalent)
emit:
source_type: Identity
target_type: Compute
source: <principal>
target: <Cloud Data Fusion instance>
permissions:
- datafusion.instances.update
- iam.serviceAccounts.actAs
conditions:
- iam_permission
- role_compatibility
state_logic: "ACTIVE if datafusion.instances.update AND iam.serviceAccounts.actAs on ?sa are both confirmed\
\ in the effective grant. The downstream CanExecuteAs (can-execute-as execute-as-via-config-identity-swap:\
\ CanModifyConfiguration + CanPassIdentity \u2192 CanExecuteAs) is ACTIVE once both contributing edges\
\ are ACTIVE and role_compatible(?sa, instance) holds. CONDITIONAL(iam_permission) if actAs is unresolved.\
\ BLOCKED if a deny policy applies to either permission."
confidence: 0.92
derived_from:
- <CanPassIdentity edge_id for ?principal -> ?sa>
- <datafusion.instances.update effective permission>
false_positive_note: "Requires both IAM permissions to be confirmed: datafusion.instances.update (GCP\
\ control-plane) AND iam.serviceAccounts.actAs on the target SA. Additionally, the Data Fusion service\
\ agent must be able to actAs the target SA to create the Dataproc cluster \u2014 if the service agent\
\ lacks that grant, the swap API call will succeed but pipeline runs will fail. Model the service-agent\
\ actAs requirement as a role_compatibility condition. Without actAs, the instance update is BLOCKED\
\ at Dataproc cluster provisioning time, not at the API level."
narrative: '{principal.name} can update the Cloud Data Fusion instance {instance.name} (datafusion.instances.update)
to replace its dataprocServiceAccount with {sa.name} (iam.serviceAccounts.actAs confirmed); all future
pipeline runs execute as {sa.name}, granting {principal.name} effective code execution as {sa.name}
via the next run.'