Skip to content

Commit

Permalink
Add eventRuleDlqKey (and revert version numbers)
Browse files Browse the repository at this point in the history
  • Loading branch information
biffgaut committed Jan 31, 2025
1 parent 4d409e1 commit e705f3b
Show file tree
Hide file tree
Showing 8 changed files with 458 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,9 @@ constructStack.getEncryptionKey().addToResourcePolicy(policyStatement);
|existingEventBusInterface?|[`events.IEventBus`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events.IEventBus.html)| Optional user-provided custom EventBus for construct to use. Providing both this and `eventBusProps` results an error.|
|eventBusProps?|[`events.EventBusProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events.EventBusProps.html)|Optional user-provided properties to override the default properties when creating a custom EventBus. Setting this value to `{}` will create a custom EventBus using all default properties. If neither this nor `existingEventBusInterface` is provided the construct will use the `default` EventBus. Providing both this and `existingEventBusInterface` results an error.|
|eventRuleProps|[`events.RuleProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events.RuleProps.html)|User provided eventRuleProps to override the defaults. |
|targetProps?|[`eventtargets.SqsQueueProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events_targets.SqsQueueProps.html)|Optional user provided properties to define the SQS target on the Event Rule. If you specify a deadLetterQueue for the rule here, you are responsible for adding a resource polic. to the queue allowing events.amazonaws.com permission to SendMessage, GetQueueUrl and GetQueueAttributes. Yo. cannot send a DLQ in this property and set deployRuleDlq to true. Default is undefined and all system defaults are used.|
|deployRuleDlq?|boolean|Whether to deploy a DLQ for the Event Rule. If set to `true`, this DLQ will receive any messages that can't be delivered to the target SQS queue. Defaults to `false`.|
|targetProps?|[`eventtargets.SqsQueueProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events_targets.SqsQueueProps.html)|Optional user provided properties to define the SQS target on the Event Rule. If you specify a deadLetterQueue for the rule here, you are responsible for adding a resource polic. to the queue allowing events.amazonaws.com permission to SendMessage, GetQueueUrl and GetQueueAttributes. You cannot send a DLQ in this property and set deployEventRuleDlq to true. Default is undefined and all system defaults are used.|
|eventRuleDlqKeyProps|[kms.KeyProps](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_kms.KeyProps.html)|Optional properties to define the key created to protect the ruleDlq. Only valid if deployRuleDlq is set to true. Defaults to CloudFormation defaults.|
| deployEventRuleDlq?|boolean|Whether to deploy a DLQ for the Event Rule. If set to `true`, this DLQ will receive any messages that can't be delivered to the target SQS queue. Defaults to `false`.|
|existingQueueObj?|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.Queue.html)|An optional, existing SQS queue to be used instead of the default queue. Providing both this and `queueProps` will cause an error.|
|queueProps?|[`sqs.QueueProps`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.QueueProps.html)|User provided props to override the default props for the SQS Queue. |
|enableQueuePurging?|`boolean`|Whether to grant additional permissions to the Lambda function enabling it to purge the SQS queue. Defaults to `false`.|
Expand All @@ -133,7 +134,8 @@ constructStack.getEncryptionKey().addToResourcePolicy(policyStatement);
|:-------------|:----------------|-----------------|
|eventBus?|[`events.IEventBus`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events.IEventBus.html)|Returns the instance of events.IEventBus used by the construct|
|eventsRule|[`events.Rule`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_events.Rule.html)|Returns an instance of events.Rule created by the construct|
|eventRuleDlq?|`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.Queue.html)|If the client set deployRuleDlq to 'true', then this value will contain the DLQ set up for the rule.|
|eventRuleDlq?|`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.Queue.html)|If the client sets deployEventRuleDlq to 'true', then this value will contain the DLQ set up for the rule.|
|eventRuleDlqKey|[kms.IKey](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_kms.IKey.html)|The key created to encrypt the eventRuleDlq.|
|sqsQueue|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.Queue.html)|Returns an instance of sqs.Queue created by the construct|
|encryptionKey?|[`kms.Key`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_kms.Key.html)|Returns an instance of kms Key used for the SQS queue.|
|deadLetterQueue?|[`sqs.Queue`](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_sqs.Queue.html)|Returns an instance of the dead-letter SQS queue created by the pattern.|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,14 @@ export interface EventbridgeToSqsProps {
*
* @default - false
*/
readonly deployRuleDlq?: boolean;
readonly deployEventRuleDlq?: boolean;
/**
* Properties to define the key created to protect the ruleDlq
* Only valid if deployRuleDlq is set to true
*
* @default - default props are used
*/
readonly eventRuleDlqKeyProps?: kms.KeyProps;
/**
* Existing instance of SQS queue object, providing both this and queueProps will cause an error.
*
Expand Down Expand Up @@ -124,6 +131,7 @@ export class EventbridgeToSqs extends Construct {
public readonly eventsRule: events.Rule;
public readonly encryptionKey?: kms.IKey;
public readonly eventRuleDlq?: sqs.Queue;
public readonly eventRuleDlqKey?: kms.IKey;

/**
* @summary Constructs a new instance of the EventbridgeToSqs class.
Expand All @@ -139,9 +147,12 @@ export class EventbridgeToSqs extends Construct {
defaults.CheckEventBridgeProps(props);
// SqsQueueProps does not implement any common interface, so is unique to this construct,
// so we will check it here rather than in core
if ((props.targetProps?.deadLetterQueue) && (props.deployRuleDlq)) {
if ((props.targetProps?.deadLetterQueue) && (props.deployEventRuleDlq)) {
throw new Error('Cannot specify both targetProps.deadLetterQueue and deployDeadLetterQueue == true\n');
}
if (props.eventRuleDlqKeyProps && !props.deployEventRuleDlq) {
throw new Error('Cannot specify eventRuleDlqKeyProps without setting deployEventRuleDlq=true\n');
}

let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey;
if (props.enableEncryptionWithCustomerManagedKey === undefined ||
Expand All @@ -165,14 +176,21 @@ export class EventbridgeToSqs extends Construct {
this.deadLetterQueue = buildQueueResponse.dlq;

let constructEventTargetProps: eventtargets.SqsQueueProps = {};
// TODO: Add a check that we not deploying a new one and using a provided one (DLQ)

if (defaults.CheckBooleanWithDefault(props.deployRuleDlq, false)) {
this.eventRuleDlq = defaults.buildQueue(this, 'ruleDlq', {
if (defaults.CheckBooleanWithDefault(props.deployEventRuleDlq, false)) {

const buildRuleDlqResponse = defaults.buildQueue(this, 'ruleDlq', {
deployDeadLetterQueue: false,
enableEncryptionWithCustomerManagedKey: enableEncryptionParam,
encryptionKey: this.encryptionKey,
}).queue;
encryptionKeyProps: props.eventRuleDlqKeyProps
});

this.eventRuleDlq = buildRuleDlqResponse.queue;
const ruleDlqKey = buildRuleDlqResponse.key;
ruleDlqKey?.grantEncryptDecrypt(new ServicePrincipal('events.amazonaws.com'));
this.eventRuleDlqKey = ruleDlqKey;

// TODO: Update docs on encrpytWithCustomerMasterKey

constructEventTargetProps = defaults.consolidateProps(constructEventTargetProps, { deadLetterQueue: this.eventRuleDlq });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,7 @@ test('Check that rule dlq is created when requested', () => {
eventRuleProps: {
schedule: events.Schedule.rate(cdk.Duration.minutes(5))
},
deployRuleDlq: true
deployEventRuleDlq: true
};
const testConstruct = new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props);
expect(testConstruct.eventRuleDlq).toBeDefined();
Expand Down Expand Up @@ -644,7 +644,7 @@ test('Check that client cannot submit their own Rule DLQ and ask for a DLQ to be
eventRuleProps: {
schedule: events.Schedule.rate(cdk.Duration.minutes(5))
},
deployRuleDlq: true,
deployEventRuleDlq: true,
targetProps: {
deadLetterQueue: {} as sqs.Queue
}
Expand All @@ -654,3 +654,55 @@ test('Check that client cannot submit their own Rule DLQ and ask for a DLQ to be
};
expect(app).toThrowError('Cannot specify both targetProps.deadLetterQueue and deployDeadLetterQueue == true\n');
});

test('Test that the construct uses provided eventRuleDlgKey properties', () => {
const stack = new cdk.Stack();
const props: EventbridgeToSqsProps = {
eventRuleProps: {
schedule: events.Schedule.rate(cdk.Duration.minutes(5))
},
eventRuleDlqKeyProps: {
alias: 'test-alias'
},
deployEventRuleDlq: true,
};
new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props);
const template = Template.fromStack(stack);
template.hasResourceProperties("AWS::KMS::Alias", {
AliasName: "alias/test-alias",
TargetKeyId: {
"Fn::GetAtt": [
Match.stringLikeRegexp("testeventbridgesqsruleDlqKey.*"),
"Arn"
]
}
});
});

test('Thest that the eventRuleDlqKey is exposed as a property', () => {
const stack = new cdk.Stack();
const props: EventbridgeToSqsProps = {
eventRuleProps: {
schedule: events.Schedule.rate(cdk.Duration.minutes(5))
},
deployEventRuleDlq: true,
};
const testConstruct = new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props);
expect(testConstruct.eventRuleDlqKey).toBeDefined();
});

test('Test that an error is thrown when eventRuleDlqKeyProps are provided but deployEventRuleDlq is not true', () => {
const stack = new cdk.Stack();
const props: EventbridgeToSqsProps = {
eventRuleProps: {
schedule: events.Schedule.rate(cdk.Duration.minutes(5))
},
eventRuleDlqKeyProps: {
alias: 'test-alias'
},
};
const app = () => {
new EventbridgeToSqs(stack, 'test-eventbridge-sqs', props);
};
expect(app).toThrowError('Cannot specify eventRuleDlqKeyProps without setting deployEventRuleDlq=true\n');
});
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "39.0.0",
"files": {
"c8bcea9c40e35cbce6c3f7b2773147c387557f313756f0cd69e7f9dda062ceab": {
"1b987658e020bc5bb91c28188d302de48a98e534e39808f44580279068526530": {
"source": {
"path": "evtsqs-rule-dlq.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "c8bcea9c40e35cbce6c3f7b2773147c387557f313756f0cd69e7f9dda062ceab.json",
"objectKey": "1b987658e020bc5bb91c28188d302de48a98e534e39808f44580279068526530.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,71 @@
]
}
},
"constructqueueKey0638E1FB": {
"Type": "AWS::KMS::Key",
"Properties": {
"EnableKeyRotation": true,
"KeyPolicy": {
"Statement": [
{
"Action": "kms:*",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
},
"Resource": "*"
},
{
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*"
],
"Condition": {
"StringEquals": {
"aws:SourceAccount": {
"Ref": "AWS::AccountId"
}
}
},
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Resource": "*"
}
],
"Version": "2012-10-17"
}
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
},
"constructqueue481DC1EC": {
"Type": "AWS::SQS::Queue",
"Properties": {
"KmsMasterKeyId": "alias/aws/sqs",
"KmsMasterKeyId": {
"Fn::GetAtt": [
"constructqueueKey0638E1FB",
"Arn"
]
},
"RedrivePolicy": {
"deadLetterTargetArn": {
"Fn::GetAtt": [
Expand Down Expand Up @@ -164,12 +225,9 @@
"sqs:SendMessage"
],
"Condition": {
"ArnEquals": {
"aws:SourceArn": {
"Fn::GetAtt": [
"constructEventsRule43880ADB",
"Arn"
]
"StringEquals": {
"aws:SourceAccount": {
"Ref": "AWS::AccountId"
}
}
},
Expand All @@ -194,10 +252,76 @@
]
}
},
"constructruleDlqKey4F9EAB36": {
"Type": "AWS::KMS::Key",
"Properties": {
"EnableKeyRotation": true,
"KeyPolicy": {
"Statement": [
{
"Action": "kms:*",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
},
"Resource": "*"
},
{
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey*",
"kms:ReEncrypt*"
],
"Effect": "Allow",
"Principal": {
"Service": "events.amazonaws.com"
},
"Resource": "*"
}
],
"Version": "2012-10-17"
}
},
"UpdateReplacePolicy": "Retain",
"DeletionPolicy": "Retain"
},
"constructruleDlqKeyAliasF2A45A01": {
"Type": "AWS::KMS::Alias",
"Properties": {
"AliasName": "alias/test-alias",
"TargetKeyId": {
"Fn::GetAtt": [
"constructruleDlqKey4F9EAB36",
"Arn"
]
}
}
},
"constructruleDlq7D359AE9": {
"Type": "AWS::SQS::Queue",
"Properties": {
"KmsMasterKeyId": "alias/aws/sqs"
"KmsMasterKeyId": {
"Fn::GetAtt": [
"constructruleDlqKey4F9EAB36",
"Arn"
]
}
},
"UpdateReplacePolicy": "Delete",
"DeletionPolicy": "Delete"
Expand Down
Loading

0 comments on commit e705f3b

Please sign in to comment.