aws-secretsmanager-cross-account-entry
Cross-account read of a secret that is credentials for a local identity is a foothold in this account.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'external': None}
CanReadSecret {'secret': None}
{'secret': None} CredentialsFor {'identity': None}
where
node_class(?secret) ==
Secret
?external.account != ?secret.account
?identity.account == ?secret.account
node_class(?identity) == Identity
emit
| source type | Identity |
|---|---|
| target type | Account |
| source | ?external |
| target | <account of ?secret> |
| permissions | secretsmanager:GetSecretValue kms:Decrypt |
| conditions | resource_policy key_permission |
| state logic | inherit_weakest(cross-account CanReadSecret, CredentialsFor): ACTIVE only if the cross-account read is ACTIVE (resource policy + CMK key policy both admit ?external) AND CredentialsFor is evidenced; otherwise CONDITIONAL with the union of the unmet gates; BLOCKED if the read is BLOCKED. |
Narrative
{external.name} can read {secret.name} cross-account, which holds credentials for {identity.name} in account {secret.account} - gaining a foothold there.
Raw rule rules/derived/aws/secretsmanager.yaml
id: aws-secretsmanager-cross-account-entry
emits: CanEnterAccount
description: Cross-account read of a secret that is credentials for a local identity is a foothold in
this account.
match:
- - external: null
- CanReadSecret
- secret: null
- - secret: null
- CredentialsFor
- identity: null
where:
- node_class(?secret) == Secret
- ?external.account != ?secret.account
- ?identity.account == ?secret.account
- node_class(?identity) == Identity
emit:
source_type: Identity
target_type: Account
source: ?external
target: <account of ?secret>
permissions:
- secretsmanager:GetSecretValue
- kms:Decrypt
conditions:
- resource_policy
- key_permission
state_logic: 'inherit_weakest(cross-account CanReadSecret, CredentialsFor): ACTIVE only if the cross-account
read is ACTIVE (resource policy + CMK key policy both admit ?external) AND CredentialsFor is evidenced;
otherwise CONDITIONAL with the union of the unmet gates; BLOCKED if the read is BLOCKED.'
confidence: min(contributing_confidences)
derived_from:
- <cross-account CanReadSecret edge_id>
- <CredentialsFor edge_id>
false_positive_note: Only a foothold when the stored credential authenticates as an identity IN the
secret's account (a local IAM key / role credential / DB login). A secret that is credentials for
a THIRD account or an external SaaS does not yield entry to THIS account. Inherits the CONDITIONAL(key_permission)
gate from the read.
narrative: "{external.name} can read {secret.name} cross-account, which holds credentials for {identity.name}\
\ in account {secret.account} \u2014 gaining a foothold there."