frontdoor rule · FD030
GCP service account impersonation chain to admin
A chain, not a single grant
Severity: critical when the entry point admits anyone or a whole domain, high otherwise.
What it means
An outside identity reaches something that matters through one or more hops, where no single hop looks wrong.
github.com/acme/api @ main → ci@acme-prod (no privileges — looks fine)
→ build@acme-prod (no privileges — looks fine)
→ deploy@acme-prod ← roles/ownerA scanner that reports the first hop tells you the repository can become ci@.
That is true, and useless. Every review of ci@ in isolation comes back clean,
because ci@ genuinely holds nothing — its value is entirely in what it can
become.
Fires when the end of the chain is either privileged or holds data.
Why "privileged" is not the only trigger
roles/bigquery.dataViewer is not a privilege escalation. A tool looking only
for escalation paths would call a chain ending there harmless, which is the
wrong answer if the dataset is your customer table.
frontdoor classifies the terminal by what it actually holds — admin, data,
compute — and says which. That is also how chains are ranked: entry looseness
× terminal sensitivity, never by length. A two-hop chain from "any GitHub
repository" into project owner beats a five-hop chain from one pinned branch
into a log bucket.
What the edges are
GCP: roles/iam.serviceAccountTokenCreator,
roles/iam.serviceAccountUser, roles/iam.workloadIdentityUser and
roles/iam.serviceAccountKeyAdmin between service accounts.
AWS: a same-account trust policy naming another role. AWS treats a trust policy naming a same-account principal as sufficient on its own, so the edge is real without also reading the caller's identity policy.
How to fix it
The finding names three things, in the order worth trying:
The weakest link, which is almost always the entry point. An impersonation binding names one identity; a federation binding can name a whole platform. Tightening the entry point fixes every chain through it at once.
The removable hop — the last link before the privileged end. That is usually the one added for a one-off task and never removed.
The terminal's permissions. A chain into something that holds nothing is not a chain worth walking.
Limits worth knowing
The walk stops at six hops and at 200 chains. Cycles are cut by the path, not globally, so the same account legitimately appears on two different paths.
If a service account's IAM policy could not be read, chains through it simply do
not appear — the denial is listed in .unreadable, and the report never implies
the graph is complete when it is not.
frontdoor answers this once, when you run it; Secorvia checks it continuously across every account you connect, on a free tier that needs no card.