Skip to content

Commit c8320bd

Browse files
authored
feat(aws-s3-sqs): added logS3AccessLogs and S3BucketInterface (#499)
* added logS3AccessLogs and updated tests * empty commit * added logS3AccessLogs and S3BucketInterface
1 parent 9922938 commit c8320bd

File tree

7 files changed

+74
-190
lines changed

7 files changed

+74
-190
lines changed

source/patterns/@aws-solutions-constructs/aws-s3-sqs/README.md

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ _Parameters_
6262
|encryptionKey?|[`kms.Key`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kms.Key.html)|Optional imported encryption key to encrypt the SQS queue.|
6363
|encryptionKeyProps?|[`kms.KeyProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kms.KeyProps.html)|Optional user provided properties to override the default properties for the KMS encryption key.|
6464
|loggingBucketProps?|[`s3.BucketProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.BucketProps.html)|Optional user provided props to override the default props for the S3 Logging Bucket.|
65+
|logS3AccessLogs?| boolean|Whether to turn on Access Logging for the S3 bucket. Creates an S3 bucket with associated storage costs for the logs. Enabling Access Logging is a best practice. default - true|
6566

6667
## Pattern Properties
6768

@@ -72,6 +73,7 @@ _Parameters_
7273
|encryptionKey|[`kms.IKey`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-kms.IKey.html)|Returns an instance of kms.Key used for the SQS queue.|
7374
|s3Bucket?|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of the s3.Bucket created by the construct|
7475
|s3LoggingBucket?|[`s3.Bucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.Bucket.html)|Returns an instance of s3.Bucket created by the construct as the logging bucket for the primary bucket.|
76+
|s3BucketInterface|[`s3.IBucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.IBucket.html)|Returns an instance of s3.IBucket created by the construct.|
7577

7678
## Default settings
7779

source/patterns/@aws-solutions-constructs/aws-s3-sqs/lib/index.ts

+12-5
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,13 @@ export interface S3ToSqsProps {
103103
* @default - Default props are used
104104
*/
105105
readonly loggingBucketProps?: s3.BucketProps
106+
/**
107+
* Whether to turn on Access Logs for the S3 bucket with the associated storage costs.
108+
* Enabling Access Logging is a best practice.
109+
*
110+
* @default - true
111+
*/
112+
readonly logS3AccessLogs?: boolean;
106113
}
107114

108115
/**
@@ -114,6 +121,7 @@ export class S3ToSqs extends Construct {
114121
public readonly s3Bucket?: s3.Bucket;
115122
public readonly s3LoggingBucket?: s3.Bucket;
116123
public readonly encryptionKey?: kms.IKey;
124+
public readonly s3BucketInterface: s3.IBucket;
117125

118126
/**
119127
* @summary Constructs a new instance of the S3ToSqs class.
@@ -130,10 +138,6 @@ export class S3ToSqs extends Construct {
130138
let bucket: s3.Bucket;
131139
let enableEncryptionParam = props.enableEncryptionWithCustomerManagedKey;
132140

133-
if (props.existingBucketObj && props.bucketProps) {
134-
throw new Error('Cannot specify both bucket properties and an existing bucket');
135-
}
136-
137141
if (props.enableEncryptionWithCustomerManagedKey === undefined ||
138142
props.enableEncryptionWithCustomerManagedKey === true) {
139143
enableEncryptionParam = true;
@@ -143,13 +147,16 @@ export class S3ToSqs extends Construct {
143147
if (!props.existingBucketObj) {
144148
[this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, {
145149
bucketProps: props.bucketProps,
146-
loggingBucketProps: props.loggingBucketProps
150+
loggingBucketProps: props.loggingBucketProps,
151+
logS3AccessLogs: props.logS3AccessLogs
147152
});
148153
bucket = this.s3Bucket;
149154
} else {
150155
bucket = props.existingBucketObj;
151156
}
152157

158+
this.s3BucketInterface = bucket;
159+
153160
// Setup the dead letter queue, if applicable
154161
this.deadLetterQueue = defaults.buildDeadLetterQueue(this, {
155162
existingQueueObj: props.existingQueueObj,

source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.creatingNewQueue.expected.json

+11-90
Original file line numberDiff line numberDiff line change
@@ -37,90 +37,6 @@
3737
"UpdateReplacePolicy": "Retain",
3838
"DeletionPolicy": "Retain"
3939
},
40-
"tests3sqsS3LoggingBucket0B0BC86A": {
41-
"Type": "AWS::S3::Bucket",
42-
"Properties": {
43-
"AccessControl": "LogDeliveryWrite",
44-
"BucketEncryption": {
45-
"ServerSideEncryptionConfiguration": [
46-
{
47-
"ServerSideEncryptionByDefault": {
48-
"SSEAlgorithm": "AES256"
49-
}
50-
}
51-
]
52-
},
53-
"PublicAccessBlockConfiguration": {
54-
"BlockPublicAcls": true,
55-
"BlockPublicPolicy": true,
56-
"IgnorePublicAcls": true,
57-
"RestrictPublicBuckets": true
58-
},
59-
"VersioningConfiguration": {
60-
"Status": "Enabled"
61-
}
62-
},
63-
"UpdateReplacePolicy": "Delete",
64-
"DeletionPolicy": "Delete",
65-
"Metadata": {
66-
"cfn_nag": {
67-
"rules_to_suppress": [
68-
{
69-
"id": "W35",
70-
"reason": "This S3 bucket is used as the access logging bucket for another bucket"
71-
}
72-
]
73-
}
74-
}
75-
},
76-
"tests3sqsS3LoggingBucketPolicy3A15958C": {
77-
"Type": "AWS::S3::BucketPolicy",
78-
"Properties": {
79-
"Bucket": {
80-
"Ref": "tests3sqsS3LoggingBucket0B0BC86A"
81-
},
82-
"PolicyDocument": {
83-
"Statement": [
84-
{
85-
"Action": "*",
86-
"Condition": {
87-
"Bool": {
88-
"aws:SecureTransport": "false"
89-
}
90-
},
91-
"Effect": "Deny",
92-
"Principal": {
93-
"AWS": "*"
94-
},
95-
"Resource": [
96-
{
97-
"Fn::Join": [
98-
"",
99-
[
100-
{
101-
"Fn::GetAtt": [
102-
"tests3sqsS3LoggingBucket0B0BC86A",
103-
"Arn"
104-
]
105-
},
106-
"/*"
107-
]
108-
]
109-
},
110-
{
111-
"Fn::GetAtt": [
112-
"tests3sqsS3LoggingBucket0B0BC86A",
113-
"Arn"
114-
]
115-
}
116-
],
117-
"Sid": "HttpsOnly"
118-
}
119-
],
120-
"Version": "2012-10-17"
121-
}
122-
}
123-
},
12440
"tests3sqsS3BucketNotifications32539247": {
12541
"Type": "Custom::S3BucketNotifications",
12642
"Properties": {
@@ -194,11 +110,6 @@
194110
}
195111
]
196112
},
197-
"LoggingConfiguration": {
198-
"DestinationBucketName": {
199-
"Ref": "tests3sqsS3LoggingBucket0B0BC86A"
200-
}
201-
},
202113
"PublicAccessBlockConfiguration": {
203114
"BlockPublicAcls": true,
204115
"BlockPublicPolicy": true,
@@ -210,7 +121,17 @@
210121
}
211122
},
212123
"UpdateReplacePolicy": "Delete",
213-
"DeletionPolicy": "Delete"
124+
"DeletionPolicy": "Delete",
125+
"Metadata": {
126+
"cfn_nag": {
127+
"rules_to_suppress": [
128+
{
129+
"id": "W35",
130+
"reason": "This S3 bucket is created for unit/ integration testing purposes only."
131+
}
132+
]
133+
}
134+
}
214135
},
215136
"tests3sqsS3BucketPolicyA477877B": {
216137
"Type": "AWS::S3::BucketPolicy",

source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.creatingNewQueue.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { S3ToSqs, S3ToSqsProps } from "../lib";
1717
import * as kms from '@aws-cdk/aws-kms';
1818
import * as s3 from '@aws-cdk/aws-s3';
1919
import { generateIntegStackName } from '@aws-solutions-constructs/core';
20+
import * as defaults from '@aws-solutions-constructs/core';
2021

2122
// Setup
2223
const app = new App();
@@ -48,10 +49,17 @@ const props: S3ToSqsProps = {
4849
s3EventFilters: [filter],
4950
bucketProps: {
5051
removalPolicy: RemovalPolicy.DESTROY,
51-
}
52+
},
53+
logS3AccessLogs: false
5254
};
5355

54-
new S3ToSqs(stack, 'test-s3-sqs', props);
56+
const construct = new S3ToSqs(stack, 'test-s3-sqs', props);
57+
const s3Bucket = construct.s3Bucket as s3.Bucket;
58+
59+
defaults.addCfnSuppressRules(s3Bucket, [
60+
{ id: 'W35',
61+
reason: 'This S3 bucket is created for unit/ integration testing purposes only.' },
62+
]);
5563

5664
// Synth
5765
app.synth();

source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingQueue.expected.json

+11-90
Original file line numberDiff line numberDiff line change
@@ -181,90 +181,6 @@
181181
]
182182
}
183183
},
184-
"tests3sqsS3LoggingBucket0B0BC86A": {
185-
"Type": "AWS::S3::Bucket",
186-
"Properties": {
187-
"AccessControl": "LogDeliveryWrite",
188-
"BucketEncryption": {
189-
"ServerSideEncryptionConfiguration": [
190-
{
191-
"ServerSideEncryptionByDefault": {
192-
"SSEAlgorithm": "AES256"
193-
}
194-
}
195-
]
196-
},
197-
"PublicAccessBlockConfiguration": {
198-
"BlockPublicAcls": true,
199-
"BlockPublicPolicy": true,
200-
"IgnorePublicAcls": true,
201-
"RestrictPublicBuckets": true
202-
},
203-
"VersioningConfiguration": {
204-
"Status": "Enabled"
205-
}
206-
},
207-
"UpdateReplacePolicy": "Delete",
208-
"DeletionPolicy": "Delete",
209-
"Metadata": {
210-
"cfn_nag": {
211-
"rules_to_suppress": [
212-
{
213-
"id": "W35",
214-
"reason": "This S3 bucket is used as the access logging bucket for another bucket"
215-
}
216-
]
217-
}
218-
}
219-
},
220-
"tests3sqsS3LoggingBucketPolicy3A15958C": {
221-
"Type": "AWS::S3::BucketPolicy",
222-
"Properties": {
223-
"Bucket": {
224-
"Ref": "tests3sqsS3LoggingBucket0B0BC86A"
225-
},
226-
"PolicyDocument": {
227-
"Statement": [
228-
{
229-
"Action": "*",
230-
"Condition": {
231-
"Bool": {
232-
"aws:SecureTransport": "false"
233-
}
234-
},
235-
"Effect": "Deny",
236-
"Principal": {
237-
"AWS": "*"
238-
},
239-
"Resource": [
240-
{
241-
"Fn::Join": [
242-
"",
243-
[
244-
{
245-
"Fn::GetAtt": [
246-
"tests3sqsS3LoggingBucket0B0BC86A",
247-
"Arn"
248-
]
249-
},
250-
"/*"
251-
]
252-
]
253-
},
254-
{
255-
"Fn::GetAtt": [
256-
"tests3sqsS3LoggingBucket0B0BC86A",
257-
"Arn"
258-
]
259-
}
260-
],
261-
"Sid": "HttpsOnly"
262-
}
263-
],
264-
"Version": "2012-10-17"
265-
}
266-
}
267-
},
268184
"tests3sqsS3BucketNotifications32539247": {
269185
"Type": "Custom::S3BucketNotifications",
270186
"Properties": {
@@ -324,11 +240,6 @@
324240
}
325241
]
326242
},
327-
"LoggingConfiguration": {
328-
"DestinationBucketName": {
329-
"Ref": "tests3sqsS3LoggingBucket0B0BC86A"
330-
}
331-
},
332243
"PublicAccessBlockConfiguration": {
333244
"BlockPublicAcls": true,
334245
"BlockPublicPolicy": true,
@@ -340,7 +251,17 @@
340251
}
341252
},
342253
"UpdateReplacePolicy": "Delete",
343-
"DeletionPolicy": "Delete"
254+
"DeletionPolicy": "Delete",
255+
"Metadata": {
256+
"cfn_nag": {
257+
"rules_to_suppress": [
258+
{
259+
"id": "W35",
260+
"reason": "This S3 bucket is created for unit/ integration testing purposes only."
261+
}
262+
]
263+
}
264+
}
344265
},
345266
"tests3sqsS3BucketPolicyA477877B": {
346267
"Type": "AWS::S3::BucketPolicy",

source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/integ.existingQueue.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { App, Stack, RemovalPolicy } from "@aws-cdk/core";
1616
import { S3ToSqs, S3ToSqsProps } from "../lib";
1717
import * as defaults from '@aws-solutions-constructs/core';
1818
import { generateIntegStackName } from '@aws-solutions-constructs/core';
19+
import * as s3 from "@aws-cdk/aws-s3";
1920

2021
const app = new App();
2122

@@ -29,8 +30,16 @@ const props: S3ToSqsProps = {
2930
existingQueueObj: myQueue,
3031
bucketProps: {
3132
removalPolicy: RemovalPolicy.DESTROY,
32-
}
33+
},
34+
logS3AccessLogs: false
3335
};
3436

35-
new S3ToSqs(stack, 'test-s3-sqs', props);
37+
const construct = new S3ToSqs(stack, 'test-s3-sqs', props);
38+
const s3Bucket = construct.s3Bucket as s3.Bucket;
39+
40+
defaults.addCfnSuppressRules(s3Bucket, [
41+
{ id: 'W35',
42+
reason: 'This S3 bucket is created for unit/ integration testing purposes only.' },
43+
]);
44+
3645
app.synth();

source/patterns/@aws-solutions-constructs/aws-s3-sqs/test/test.s3-sqs.test.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ test("Test bad call with existingBucket and bucketProps", () => {
232232
});
233233
};
234234
// Assertion
235-
expect(app).toThrowError();
235+
expect(app).toThrowError('Error - Either provide bucketProps or existingBucketObj, but not both.\n');
236236
});
237237

238238
// --------------------------------------------------------------
@@ -266,4 +266,20 @@ test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => {
266266
Ref: "s3sqsS3LoggingBucketD877FC52"
267267
}
268268
});
269+
});
270+
271+
// --------------------------------------------------------------
272+
// s3 bucket with one content bucket and no logging bucket
273+
// --------------------------------------------------------------
274+
test('s3 bucket with one content bucket and no logging bucket', () => {
275+
const stack = new Stack();
276+
277+
new S3ToSqs(stack, 's3-sqs', {
278+
bucketProps: {
279+
removalPolicy: RemovalPolicy.DESTROY,
280+
},
281+
logS3AccessLogs: false
282+
});
283+
284+
expect(stack).toCountResources("AWS::S3::Bucket", 1);
269285
});

0 commit comments

Comments
 (0)