aws-kinesis-read-stream-data-fanout
kinesis:RegisterStreamConsumer + kinesis:SubscribeToShard enables reading from a stream via the enhanced fan-out path (push-based), equivalent to GetRecords-based polling.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?stream) ==
GenericMessaging
?stream.provider_type == 'AWS::Kinesis::Stream'
?principal has EFFECTIVE kinesis:RegisterStreamConsumer on ?stream ARN
?principal has EFFECTIVE kinesis:SubscribeToShard on consumer ARNs for ?stream
emit
| source type | Identity |
|---|---|
| target type | Messaging |
| source | ?principal |
| target | ?stream |
| permissions | kinesis:RegisterStreamConsumer kinesis:SubscribeToShard |
| conditions | iam_permission resource_policy key_permission |
| state logic | ACTIVE when BOTH kinesis:RegisterStreamConsumer and kinesis:SubscribeToShard are confirmed EFFECTIVE on the stream ARN (and consumer ARNs respectively). RegisterStreamConsumer alone does not grant read access (it only creates a consumer ARN). SubscribeToShard alone is also insufficient without a registered consumer. The principal must hold both to achieve read capability. If the stream uses KMS encryption (EncryptionType: KMS), the principal also needs kms:Decrypt — same key_permission gate as rule 3. CONDITIONAL(key_permission) when encryption is present but decrypt is unconfirmed. |
Narrative
{principal.name} has kinesis:RegisterStreamConsumer and kinesis:SubscribeToShard on {stream.name} and can read records via the enhanced fan-out path. By registering a consumer and subscribing to the stream via that consumer, {principal.name} can read record batches, enabling data exfiltration or credential harvest if records carry sensitive content.
Raw rule rules/derived/aws/kinesis.yaml
id: aws-kinesis-read-stream-data-fanout
emits: CanReadData
description: kinesis:RegisterStreamConsumer + kinesis:SubscribeToShard enables reading from a stream via
the enhanced fan-out path (push-based), equivalent to GetRecords-based polling.
match:
- - principal: null
- HasPermission
- stream: null
where:
- node_type(?stream) == GenericMessaging
- ?stream.provider_type == 'AWS::Kinesis::Stream'
- ?principal has EFFECTIVE kinesis:RegisterStreamConsumer on ?stream ARN
- ?principal has EFFECTIVE kinesis:SubscribeToShard on consumer ARNs for ?stream
emit:
source_type: Identity
target_type: Messaging
source: ?principal
target: ?stream
permissions:
- kinesis:RegisterStreamConsumer
- kinesis:SubscribeToShard
conditions:
- iam_permission
- resource_policy
- key_permission
state_logic: "ACTIVE when BOTH kinesis:RegisterStreamConsumer and kinesis:SubscribeToShard are confirmed\
\ EFFECTIVE on the stream ARN (and consumer ARNs respectively). RegisterStreamConsumer alone does\
\ not grant read access (it only creates a consumer ARN). SubscribeToShard alone is also insufficient\
\ without a registered consumer. The principal must hold both to achieve read capability. If the stream\
\ uses KMS encryption (EncryptionType: KMS), the principal also needs kms:Decrypt \u2014 same key_permission\
\ gate as rule 3. CONDITIONAL(key_permission) when encryption is present but decrypt is unconfirmed."
confidence: min(contributing_confidences) * 0.9
derived_from:
- ?principal HasPermission ?stream (kinesis:RegisterStreamConsumer + kinesis:SubscribeToShard effective
permission)
- "credential-chains:decrypt-gates-secret-read (KMS-encrypted stream gate \u2014 cited not re-derived)"
false_positive_note: "BOTH permissions are REQUIRED together; neither alone grants read access. RegisterStreamConsumer\
\ creates the consumer ARN artifact; SubscribeToShard uses that consumer to open the push subscription.\
\ An attacker must have both. This is the enhanced fan-out (push) variant of rule 3's GetRecords polling.\
\ Like rule 3, KMS encryption gates the capability until kms:Decrypt is confirmed. A consumer created\
\ by someone else (shared consumer ARN) may not be leverageable depending on access \u2014 assume\
\ the attacker creates their own consumer via RegisterStreamConsumer. If only one of the two permissions\
\ is confirmed, do not emit ACTIVE \u2014 downgrade to CONDITIONAL or block."
narrative: '{principal.name} has kinesis:RegisterStreamConsumer and kinesis:SubscribeToShard on {stream.name}
and can read records via the enhanced fan-out path. By registering a consumer and subscribing to the
stream via that consumer, {principal.name} can read record batches, enabling data exfiltration or
credential harvest if records carry sensitive content.'