返回资讯中心
外部精选
软件工程
#开发者实时流

Show HN: Frontdoor: find who can assume into your cloud accounts

Map the federated trust into your cloud accounts.

Hacker News 最新RohaanXD2026/10/25 · 16 天前30 分钟阅读

以下正文同步自 Hacker News 最新,版权归原站所有,已转换为易读排版。

Map the federated trust into your cloud accounts.

Who outside can get in, and how far they get once they are in.

Install · Rules · Compared to other tools · Safety · Docs

Every cloud security scanner looks at what is inside an account. None of them map the doors leading in: the OIDC, SAML and cross-account trusts that let a GitHub repository, a CI pipeline, a SaaS vendor or another cloud obtain credentials in your account.

They are easy to get wrong and nothing flags them when you do. A role that trusts a GitHub repository looks identical in an inventory whether the trust is pinned to one branch of one repo or left open to every repository on GitHub. frontdoor reads the trust policy and tells you which one it is.

$ frontdoor scan

frontdoor 0.1.0 · acme-prod (111122223333), acme-prod · 2026-09-25 09:12 UTC

▐ WHO CAN GET IN ────────────────────────────────────────────────────────────

ANY GitHub Actions tenant → role/ci-deploy privileged github.com/acme/api @ refs/heads/main → role/deploy-prod

▐ HOW FAR THEY GET ──────────────────────────────────────────────────────────

github.com/acme/api @ refs/heads/main → role/deploy-prod sts:AssumeRoleWithWebIdentity → [gcp] data-pipeline@acme-prod BigQuery datasets One repo compromise reaches BigQuery datasets.

▐ CRITICAL (1) ─────────────────────────────────────────────────────────────

FD001 ANY GitHub Actions tenant can assume role/ci-deploy arn:aws:iam::111122223333:role/ci-deploy

Wrong The trust policy places no condition on token.actions.githubusercontent.com:sub, so the subject claim is never checked. Attacker Anyone able to get a token from token.actions.githubusercontent.com - which on a public CI platform means anyone at all - can assume this role and use everything it grants. Fix Pin the subject claim to the exact identity you intend to trust.

"Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com", "token.actions.githubusercontent.com:sub": "repo:acme/api:ref:refs/heads/main" } }

Docs https://www.secorvia.com/docs/frontdoor/FD001

2 external identities can enter your clouds. 1 accepts ANY GitHub repository. One of them crosses AWS into GCP and reaches BigQuery datasets. 3 findings: 2 critical, 1 high.

Status: feature complete. AWS, GCP and Azure (beta), 15 rules, the full output layer, and cross-cloud chains.

Requires Go 1.26 to build. See the dependency note under Safety.

go install github.com/secorvia/frontdoor/cmd/frontdoor@latest frontdoor scan

It uses whatever credentials you already have (~/.aws, gcloud auth application-default, az login), reads nothing else, writes nothing anywhere, and prints the report above. No config file, no account, no signup.

ID Severity What it catches

FD001 critical¹ No condition on the subject claim, so any tenant of that issuer can assume the role

FD002 critical to medium² No condition on the audience claim

FD003 critical An open door on a role that can escalate to account takeover

FD005 medium Subject condition namespaced to the wrong issuer, so AWS never evaluates it

FD010 high Org-wide subject (repo:acme/*), meaning any repository in the org

FD011 high Repository pinned but any branch or tag can assume

FD012 high The pull_request context is accepted (pull_request_target risk)

FD013 high³ Cross-account trust with no sts:ExternalId, the confused deputy

FD014 high³ Trust to an account that is neither yours nor a vendor we can identify

FD015 high Trust rests on repository_owner alone, which is a name, not a stable id

FD020 medium Long-lived access keys still active on an account that uses federation

FD021 medium Unused identity provider, or an external trust never assumed

FD022 medium/low OIDC thumbprint missing, or not matching the issuer's current cert (AWS only)

FD030 critical/high Chain. A federated identity that reaches something privileged, or a data store, through one or more hops

FD031 critical/high Cross-cloud chain. The path leaves the cloud it started in

¹ high instead when the door is held by a real narrowing condition such as aws:PrincipalOrgID or sts:ExternalId, and also for a SAML trust, which admits every user of your IdP. That is too wide, but it is not the open internet.

² Severity here is contextual rather than a flat "critical", which is a deliberate departure. Missing aud with no subject condition means any token that issuer ever minted is accepted, so that is critical. Missing aud with an exact subject is a hardening gap, so medium. On GitHub the workflow chooses its own aud anyway, so aud was never the barrier there; sub is.

³ medium when organizations:ListAccounts was denied. The tool cannot then prove the account is a stranger, and the finding says so.

A chain inside one cloud, where every hop on its own looks unremarkable:

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@, which is true and useless. frontdoor follows the roles/iam.serviceAccountTokenCreator edges to the end and reports the whole path, the weakest link on it, and which binding to remove.

And the case nothing else reports at all: a chain that leaves the cloud it started in.

▐ HOW FAR THEY GET ──────────────────────────────────────────

github.com/acme/api @ refs/heads/main → role/ci-deploy sts:AssumeRoleWithWebIdentity → [gcp] data-pipeline@acme-prod BigQuery datasets One repo compromise reaches BigQuery datasets.

Your AWS scanner stops at role/ci-deploy. Your GCP scanner sees a workload identity binding from "some AWS role" and has no idea a public CI platform is on the other end of it. Neither of them is wrong, and neither of them reports this path. frontdoor joins the two halves through the assumed-role ARN a GCP AWS-provider records, or through the numeric service-account id an AWS trust policy carries, and walks straight through the seam.

If only one cloud was scanned, no edge is drawn: an account we were never pointed at is genuinely outside, and inventing a node we know nothing about would be worse than stopping.

Chains are ranked by entry looseness × terminal sensitivity, never by length. At equal weight a cross-cloud path ranks above a same-cloud one. A two-hop chain from "any GitHub repository" into project owner beats a five-hop chain from one pinned branch into a log bucket.

The terminal is classified by what it actually holds, not just whether it can escalate: roles/bigquery.dataViewer is not a privilege escalation, and a tool that only looks for escalation would call that chain harmless.

Every finding carries the rule id, severity, the exact resource ARN, one sentence on what is wrong, one sentence on what an attacker could do, the policy text it rests on as evidence, and a fix. The fix includes a corrected Condition block built from the door's real issuer, org and repo.

"fix": { "summary": "Pin the subject claim to the exact identity you intend to trust.", "trust_policy": ""Condition": {\n "StringEquals": {\n "token.actions.githubusercontent.com:aud": "sts.amazonaws.com",\n "token.actions.githubusercontent.com:sub": "repo:YOUR_ORG/YOUR_REPO:ref:refs/heads/main"\n }\n}", "steps": ["Confirm which repository is supposed to use this role.", "..."] }

How this compares

The cloud security space is crowded and several of these tools are excellent. frontdoor is not trying to replace them, and pretending otherwise would be an easy claim to disprove.

Two things here are genuinely not available elsewhere in open source:

Cross-cloud trust paths (FD031). The AWS-to-GCP workload-identity attack is well documented and widely written about. No open-source tool detects it, because detecting it requires joining two clouds' views of the same identity: the assumed-role ARN inside a GCP provider subject, or a service account's numeric unique id inside an AWS trust policy. frontdoor does that join.

Path analysis with no infrastructure. Every tool above that follows paths wants a graph database first. That is a reasonable design for a platform, and the wrong one for something you run once to answer a question. frontdoor is a single static binary with no daemon, database or config file.

If you already run Prowler, run this alongside it. It answers a question Prowler does not ask.

OIDC providers issuer URL, registered audiences, thumbprints

SAML providers entityID and validity. The metadata document is never stored

Every IAM role trust policy parsed into structured doors, one per external principal

Subject claims GitHub Actions, GitLab CI, CircleCI, Terraform Cloud, Vercel, Buildkite, Bitbucket Pipelines, Google (AWS↔GCP federation)

GitHub immutable subjects repo:org@123456/repo@456789:..., the format repositories created after 15 July 2026 use. Read so the report shows plain names, with the numeric ids carried back into every suggested fix, because a condition written without them stops matching

Which claim names the tenant AWS's full shared-OIDC list, including the five providers where the tenant arrives in the audience or in sts:RoleSessionName rather than the subject. A role pinned the way those providers require has no subject condition at all, and is not reported as open

Cross-account trusts account id, sts:ExternalId presence, known-vendor labelling

What each door grants attached + inline policies flattened, privilege-escalation actions flagged with a reason

Organization layout so a sibling account is not reported as a stranger

IAM user access keys age and last-used, because federation plus static keys means two front doors

On GCP:

A GCP "door" is not one object. A provider says which outside identities exist; a service-account binding says which of them may become that account. Neither half means anything on its own, so frontdoor always joins them, and a binding naming principalSet://.../workloadIdentityPools/POOL/* is the GCP spelling of "any repository on GitHub".

Three GCP behaviours are deliberately not copied from the AWS rules, because a literal translation would flag correct configuration:

These two trust policies look the same in a console. They are not:

// Anyone with a GitHub account can assume this role. "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com" } }

// Only the main branch of one repository can. "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com", "token.actions.githubusercontent.com:sub": "repo:acme/api:ref:refs/heads/main" } }

frontdoor reports the first as ANY GitHub Actions tenant (FD001, critical) and the second as github.com/acme/api @ refs/heads/main (no finding).

It also handles a third case most tools get wrong: a sub condition written against a different issuer's namespace. AWS never puts that key in the request context, so a plain StringEquals evaluates false and the role can be assumed by nobody. That is a broken door, not an open one, reported as FD005 (medium), never as a wide-open critical.

Go toolchain (needs Go 1.26+)

go install github.com/secorvia/frontdoor/cmd/frontdoor@latest

Script: verifies the SHA-256 against the signed checksums file before

unpacking, and the cosign signature too if cosign is installed

curl -fsSL https://raw.githubusercontent.com/secorvia/frontdoor/main/install.sh | sh

Or build from source:

git clone https://github.com/secorvia/frontdoor cd frontdoor go build -o frontdoor ./cmd/frontdoor

Verifying a release

Release archives are signed keyless through the GitHub Actions OIDC identity, the same mechanism this tool audits, used the way it should be: the signature is bound to the exact workflow and ref that produced the artifact.

cosign verify-blob checksums.txt
--certificate checksums.txt.pem
--signature checksums.txt.sig
--certificate-identity-regexp 'https://github\.com/secorvia/frontdoor/\

正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。

打开原文
去社区讨论 →