frontdoor rule · FD030

GCP service account impersonation chain to admin

A chain, not a single grant

Google Cloud, Amazon Web ServicesUpdated Source on GitHub

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.

text
github.com/acme/api @ main  →  ci@acme-prod       (no privileges — looks fine)
                            →  build@acme-prod    (no privileges — looks fine)
                            →  deploy@acme-prod   ← roles/owner

A 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:

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

  2. The removable hop — the last link before the privileged end. That is usually the one added for a one-off task and never removed.

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