aws-kinesis-cross-account-publish-trust
A Kinesis stream resource policy granting kinesis:PutRecord(s) to a principal in another account is cross-account publish trust, enabling that external principal to trigger the stream's Lambda consumer.
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'
node_type(?stream_policy) == ResourcePolicy
?stream_policy grants kinesis:PutRecord or kinesis:PutRecords to a Principal whose account != account(?stream)
emit
| source type | ResourcePolicy |
|---|---|
| target type | Account |
| source | ?stream_policy |
| target | <the external AWS account named in the stream resource policy> |
| permissions | kinesis:PutRecord kinesis:PutRecords |
| conditions | resource_policy condition_expression |
| state logic | ACTIVE when the stream resource policy unconditionally grants kinesis:PutRecord or kinesis:PutRecords to a named external principal with no conditions beyond aws:PrincipalArn identity scoping. CONDITIONAL (condition_expression) when scoped by aws:SourceAccount, aws:SourceVpc, aws:PrincipalOrgID, or other conditions the external principal must satisfy. BLOCKED by an SCP or explicit deny in the stream-owner's account that prevents cross-account PutRecord. State never exceeds the weakest contributor. This edge ONLY asserts the cross-boundary publish trust; CanEnterAccount requires messaging-chains + can-control to roll up the CanWriteData + CanTrigger + CanExecuteAs chain separately. |
Narrative
The resource policy on Kinesis stream {stream.name} grants kinesis:PutRecord or kinesis:PutRecords to a principal in a foreign AWS account. That external principal can publish records to this stream. If a Lambda event-source-mapping is active on {stream.name}, the external principal can trigger the bound Lambda consumer inside {stream.name}'s account (the full chain - messaging- chains + can-control - rolls this up to CanEnterAccount).
Raw rule rules/derived/aws/kinesis.yaml
id: aws-kinesis-cross-account-publish-trust
emits: CrossAccountTrust
description: A Kinesis stream resource policy granting kinesis:PutRecord(s) to a principal in another
account is cross-account publish trust, enabling that external principal to trigger the stream's Lambda
consumer.
match:
- - stream_policy: null
- HasPolicy
- stream: null
where:
- node_type(?stream) == GenericMessaging
- ?stream.provider_type == 'AWS::Kinesis::Stream'
- node_type(?stream_policy) == ResourcePolicy
- ?stream_policy grants kinesis:PutRecord or kinesis:PutRecords to a Principal whose account != account(?stream)
emit:
source_type: ResourcePolicy
target_type: Account
source: ?stream_policy
target: <the external AWS account named in the stream resource policy>
permissions:
- kinesis:PutRecord
- kinesis:PutRecords
conditions:
- resource_policy
- condition_expression
state_logic: ACTIVE when the stream resource policy unconditionally grants kinesis:PutRecord or kinesis:PutRecords
to a named external principal with no conditions beyond aws:PrincipalArn identity scoping. CONDITIONAL
(condition_expression) when scoped by aws:SourceAccount, aws:SourceVpc, aws:PrincipalOrgID, or other
conditions the external principal must satisfy. BLOCKED by an SCP or explicit deny in the stream-owner's
account that prevents cross-account PutRecord. State never exceeds the weakest contributor. This edge
ONLY asserts the cross-boundary publish trust; CanEnterAccount requires messaging-chains + can-control
to roll up the CanWriteData + CanTrigger + CanExecuteAs chain separately.
confidence: min(contributing_confidences)
derived_from:
- ?stream_policy HasPolicy ?stream (kinesis:GetResourcePolicy evidence)
- messaging-chains:messaging-resource-policy-cross-boundary-trust (provider-agnostic form)
- "can-control:enter-account-via-assume (downstream CanEnterAccount \u2014 cited not re-derived)"
false_positive_note: "This rule asserts ONLY the cross-boundary publishing TRUST from the resource policy.\
\ CanEnterAccount is NOT emitted here \u2014 it requires the separate chain: foreign-principal CanWriteData\
\ stream \u2192 (rule 1) CanTrigger consumer \u2192 messaging-chains rule 2 CanExecuteAs \u2192 can-control\
\ CanEnterAccount. Honor aws:PrincipalOrgID / aws:SourceAccount conditions as real controls: a policy\
\ scoped to a specific sibling account is not open cross-account access (downgrade to CONDITIONAL).\
\ A read-only cross-account grant (kinesis:GetRecords / kinesis:GetShardIterator to a foreign account)\
\ does NOT feed this rule \u2014 that is cross-account read trust, a different threat model (CanReadData\
\ / CanExfiltrate, handled by data-plane rules)."
narrative: "The resource policy on Kinesis stream {stream.name} grants kinesis:PutRecord or kinesis:PutRecords\
\ to a principal in a foreign AWS account. That external principal can publish records to this stream.\
\ If a Lambda event-source-mapping is active on {stream.name}, the external principal can trigger\
\ the bound Lambda consumer inside {stream.name}'s account (the full chain \u2014 messaging- chains\
\ + can-control \u2014 rolls this up to CanEnterAccount)."