New rule: IAM roles trusting AWS accounts not synced by Cartography (external trust)
## Description
Add a rule that flags `AWSRole` nodes (in a synced account) whose trust policy
allows assumption by an `AWSPrincipal` belonging to an AWS account that Cartography
does **not** sync, i.e. an external account.
The sync already parses `AssumeRolePolicyDocument`, materializes
`(:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(:AWSPrincipal)`, and creates stub
`AWSAccount` / root-principal nodes for trusted external accounts, so this is a
rule-only change with no datamodel or intel work.
The reliable marker for "not synced" is `AWSAccount.inscope`: it is set to `true`
only for accounts actually in the sync scope; external stub accounts created from
trust-policy parsing do not have it.
Detection sketch:
```cypher
MATCH (a:AWSAccount {inscope: true})-[:RESOURCE]->(role:AWSRole)-[:TRUSTS_AWS_PRINCIPAL]->(p:AWSPrincipal)
MATCH (ext:AWSAccount)-[:RESOURCE]->(p)
WHERE coalesce(ext.inscope, false) <> true
RETURN role.arn, role.name, a.id AS account_id,
ext.id AS external_account_id, p.arn AS trusted_principal_arn
```
Output fields: role arn/name, role account id, external (unsynced) account id,
trusted principal arn.
Consider an allowlist hook (known third-party / partner account ids) as a
follow-up; ship the raw detection first.
## Motivation
Roles trusting accounts outside the synced perimeter are a silent
lateral-movement / persistence vector, often left over from one-off integrations
or audits. Keying off `inscope` rather than ARN string parsing makes the detection
robust: anything Cartography does not actually sync is treated as external. The
graph already encodes the relationship; surfacing it requires no new collection.
## Alternatives Considered
- Comparing the account id embedded in the principal ARN against the role's account
id: brittle and misses multi-account-in-scope setups. Using `inscope` directly
reflects what Cartography actually knows about.
- Modeling this as an attack path rather than a flat rule: deferred. A direct rule
is the smallest useful increment and composes with attack-path tooling later.
## Relevant Links
- `cartography/intel/aws/iam.py` (`transform_role_trust_policies`, `load_external_aws_accounts`)
- `cartography/models/aws/iam/role.py` (`TRUSTS_AWS_PRINCIPAL`)
- `cartography/models/aws/account.py` (`inscope` property)
0 条评论