sqs/events: Using an SQS queue as the target of an EB Rule leads to an incomplete KMS Key policy if the queue is encrypted with an imported key
- Dominant language
- TypeScript
- Stars
- 12.9k
- Forks
- 4.6k
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 74
Description
### Describe the bug
Consider the following minimal CDK snippet that creates a KMS key, an encrypted Event Bus, an encrypted SQS queue, an EB Rule for the Bus that targets the queue and a Lambda that consumes from that Queue:
```
const key = new kms.Key(this, "Key", {
removalPolicy: RemovalPolicy.DESTROY,
});
const eventBus = new events.EventBus(this, "EventBus", {
eventBusName: "EventBus",
kmsKey: key
});
const queue = new sqs.Queue(this, "Queue", {
queueName: "Queue",
encryption: sqs.QueueEncryption.KMS,
encryptionMasterKey: key, // kms.Key.fromKeyArn(this, "ImportedKey", key.keyArn),
});
new events.Rule(this, "Rule", {
eventBus: events.EventBus.fromEventBusArn(this, "ImportedEventBus", eventBus.eventBusArn),
ruleName: "Rule",
eventPattern: {
source: ["my.custom.source"]
},
targets: [new events_targets.SqsQueue(queue)]
});
const consumer = new lambda.Function(this, "Consumer", {
functionName: "Consumer",
logGroup: new LogGroup(this, "LogGroup", {
logGroupName: "/aws/lambda/Consumer",
removalPolicy: RemovalPolicy.DESTROY,
}),
runtime: lambda.Runtime.NODEJS_LATEST,
code: lambda.Code.fromInline("exports.handler = async (event) => { console.log(\"Event received:\", event); }"),
handler: "index.handler",
});
consumer.addEventSource(new lambda_event_sources.SqsEventSource(queue));
```
Sending events (`events.json`)
```
[
{
"Source": "my.custom.source",
"DetailType": "myDetailType",
"Detail": "{}",
"EventBusName": "EventBus"
}
]
```
to the Bus
```
aws events put-events --entries file://events.json
```
Works fine, the Lambda logs the received event.
Specifically take note of the generated KMS key policies:
```
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam:::root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:DescribeKey",
"kms:GenerateDataKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:events:::event-bus/EventBus",
"aws:SourceAccount": "",
"kms:EncryptionContext:aws:events:event-bus:arn": "arn:aws:events:::event-bus/EventBus"
}
}
},
{
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": ""
}
}
}
]
}
```
Now, instead of using the Key directly for SQS, change the construct to
```
const queue = new sqs.Queue(this, "Queue", {
queueName: "Queue",
encryption: sqs.QueueEncryption.KMS,
encryptionMasterKey: kms.Key.fromKeyArn(this, "ImportedKey", key.keyArn),
});
```
I.e., we "simulate" that the Key is imported, the CLI above stops working and the KMS key policies look like
```
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam:::root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:DescribeKey",
"kms:GenerateDataKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": "",
"aws:SourceArn": "arn:aws:events:::event-bus/EventBus",
"kms:EncryptionContext:aws:events:event-bus:arn": "arn:aws:events:::event-bus/EventBus"
}
}
}
]
}
```
i.e., the last statement
```
{
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:SourceAccount": ""
}
}
}
```
is missing altogether.
A workaround is to manually update the KMS key policy by adding the last statement.
### Regression Issue
- [ ] Select this option if this issue appears to be a regression.
### Last Known Working CDK Library Version
_No response_
### Expected Behavior
Both CDK constructs should lead to the same KMS key policy.
### Current Behavior
See above, the KMS key policy is missing a statement.
### Reproduction Steps
See above.
### Possible Solution
_No response_
### Additional Information/Context
_No response_
### AWS CDK Library version (aws-cdk-lib)
2.214.0
### AWS CDK CLI version
2.1029.1 (build b45b1ab)
### Node.js Version
v24.3.0
### OS
macOS Sequoia 15.6
### Language
TypeScript
### Language Version
_No response_
### Other information
_No response_
Contributor guide
Research direction
Start by synthesizing the supplied TypeScript reproduction and diff the KMS policies for direct versus imported keys. Trace the SQS/EventBridge target and imported-key handling in the CDK source; done when both forms emit the missing events.amazonaws.com permissions and a regression test covers the behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- aws, typescript
- Domain
- cloud, infrastructure, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100