aws-secretsmanager-cross-account-entry

Cross-account read of a secret that is credentials for a local identity is a foothold in this account.

derived aws emits CanEnterAccount

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 typeIdentity
target typeAccount
source?external
target<account of ?secret>
permissionssecretsmanager:GetSecretValue kms:Decrypt
conditionsresource_policy key_permission
state logicinherit_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."
move · open · esc close