aws-ebs-snapshot-exposes-credential
Reading snapshot data (CanReadData) that contains secrets (ContainsSecret) lets the principal extract and authenticate as the identity those secrets belong to - shorthand for the CanReadData → ContainsSecret → CredentialsFor chain into the CanReadSecret pivot. This rule feeds credential-chains.yaml: read-secret-yields-identity.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
{'principal': None}
CanReadData {'snapshot': None}
{'snapshot': None} ContainsSecret {'secret': None}
where
emit
| source type | Identity |
|---|---|
| target type | Secret |
| source | ?principal |
| target | ?secret |
| permissions | ebs:GetSnapshotBlock ebs:ListSnapshotBlocks |
| conditions | iam_permission key_permission |
| state logic | inherit_weakest(CanReadData, ContainsSecret): if CanReadData is CONDITIONAL (key_permission gate), then CONDITIONAL(key_permission); if ContainsSecret is POTENTIAL, then POTENTIAL (no one can read the data until forensic scan confirms the secret exists). Strongest case: ACTIVE only when both CanReadData is ACTIVE and ContainsSecret is ACTIVE. For path-finding into credential- chains.yaml:read-secret-yields-identity, this edge must be ACTIVE to unlock impersonation; POTENTIAL/CONDITIONAL contributions stall the chain. |
Narrative
{principal.name} can read the data stored in {snapshot.name} (via ebs:GetSnapshotBlock or volume mount), which contains credentials for {secret.name}. Reading the snapshot allows {principal.name} to extract and use the secret, feeding into the credential escalation chain (CanImpersonate → CanEscalateTo).
Raw rule rules/derived/aws/ebs.yaml
id: aws-ebs-snapshot-exposes-credential
emits: CanReadSecret
description: "Reading snapshot data (CanReadData) that contains secrets (ContainsSecret) lets the principal\
\ extract and authenticate as the identity those secrets belong to \u2014 shorthand for the CanReadData\
\ \u2192 ContainsSecret \u2192 CredentialsFor chain into the CanReadSecret pivot. This rule feeds credential-chains.yaml:\
\ read-secret-yields-identity."
match:
- - principal: null
- CanReadData
- snapshot: null
- - snapshot: null
- ContainsSecret
- secret: null
where:
- node_type(?snapshot) == Snapshot
- node_type(?secret) == Secret
emit:
source_type: Identity
target_type: Secret
source: ?principal
target: ?secret
permissions:
- ebs:GetSnapshotBlock
- ebs:ListSnapshotBlocks
conditions:
- iam_permission
- key_permission
state_logic: 'inherit_weakest(CanReadData, ContainsSecret): if CanReadData is CONDITIONAL (key_permission
gate), then CONDITIONAL(key_permission); if ContainsSecret is POTENTIAL, then POTENTIAL (no one can
read the data until forensic scan confirms the secret exists). Strongest case: ACTIVE only when both
CanReadData is ACTIVE and ContainsSecret is ACTIVE. For path-finding into credential- chains.yaml:read-secret-yields-identity,
this edge must be ACTIVE to unlock impersonation; POTENTIAL/CONDITIONAL contributions stall the chain.'
confidence: min(CanReadData.confidence, ContainsSecret.confidence)
derived_from:
- ?principal CanReadData ?snapshot
- ?snapshot ContainsSecret ?secret
linchpin_citations:
- "credential-chains.yaml:read-secret-yields-identity (consumes CanReadSecret \u2192 CanImpersonate\
\ \u2192 CanEscalateTo)"
false_positive_note: This rule links data access to credential extraction, feeding the credential chain.
It is only valuable when ContainsSecret is confirmed ACTIVE (via forensic evidence in /rules/explicit/aws-ebs.yaml,
not just structural probability). When ContainsSecret is not present or is unconfirmed, this chain
does not emit. The permissions list shows the EBS direct API permissions (ebs:GetSnapshotBlock); the
secret's CanReadSecret is derived from the data-read capability, not a separate IAM action. This CanReadSecret
edge is the input to credential-chains.yaml:read-secret-yields-identity, which then chains into CanImpersonate
and CanEscalateTo.
narrative: "{principal.name} can read the data stored in {snapshot.name} (via ebs:GetSnapshotBlock or\
\ volume mount), which contains credentials for {secret.name}. Reading the snapshot allows {principal.name}\
\ to extract and use the secret, feeding into the credential escalation chain (CanImpersonate \u2192\
\ CanEscalateTo)."