diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md index 5fad7376c..c4dd29eec 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/README.md @@ -63,6 +63,7 @@ _Parameters_ |createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms| |logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|User provided props to override the default props for for the CloudWatchLogs LogGroup.| |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.| +|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| ## Pattern Properties @@ -76,7 +77,7 @@ _Parameters_ |cloudtrail|[`cloudtrail.Trail`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudtrail.Trail.html)|Returns an instance of the cloudtrail.Trail created by the construct| |cloudtrailBucket|[`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 for CloudTrail| |cloudtrailLoggingBucket|[`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 CloudTrail bucket.| - +|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.| ## Default settings Out of the box implementation of the Construct without any override will set the following defaults: diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/lib/index.ts index 6be97c6fd..00167ab9b 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/lib/index.ts @@ -48,7 +48,7 @@ export interface S3ToStepFunctionProps { * * @default - None */ - readonly eventRuleProps?: events.RuleProps; + readonly eventRuleProps?: events.RuleProps, /** * Whether to deploy a Trail in AWS CloudTrail to log API events in Amazon S3 * @@ -66,13 +66,20 @@ export interface S3ToStepFunctionProps { * * @default - Default props are used */ - readonly logGroupProps?: logs.LogGroupProps + readonly logGroupProps?: logs.LogGroupProps, /** * Optional user provided props to override the default props for the S3 Logging Bucket. * * @default - Default props are used */ - readonly loggingBucketProps?: s3.BucketProps + readonly loggingBucketProps?: s3.BucketProps, + /** + * Whether to turn on Access Logs for the S3 bucket with the associated storage costs. + * Enabling Access Logging is a best practice. + * + * @default - true + */ + readonly logS3AccessLogs?: boolean; } export class S3ToStepFunction extends Construct { @@ -84,6 +91,7 @@ export class S3ToStepFunction extends Construct { public readonly cloudtrail?: cloudtrail.Trail; public readonly cloudtrailBucket?: s3.Bucket; public readonly cloudtrailLoggingBucket?: s3.Bucket; + public readonly s3BucketInterface: s3.IBucket; /** * @summary Constructs a new instance of the S3ToStepFunction class. @@ -110,5 +118,6 @@ export class S3ToStepFunction extends Construct { this.cloudtrail = wrappedConstruct.cloudtrail; this.cloudtrailBucket = wrappedConstruct.cloudtrailBucket; this.cloudtrailLoggingBucket = wrappedConstruct.cloudtrailLoggingBucket; + this.s3BucketInterface = wrappedConstruct.s3BucketInterface; } } \ No newline at end of file diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.expected.json index 48191b50b..a089ce26c 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.expected.json @@ -176,273 +176,13 @@ } } }, - "tests3stepfunctiontests3stepfunctionWCloudTrailS3LoggingBucket449D5AB7": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - } - ] - } - } - }, - "tests3stepfunctiontests3stepfunctionWCloudTrailS3LoggingBucketPolicy7547A73F": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctiontests3stepfunctionWCloudTrailS3LoggingBucket449D5AB7" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3LoggingBucket449D5AB7", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3LoggingBucket449D5AB7", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LifecycleConfiguration": { - "Rules": [ - { - "NoncurrentVersionTransitions": [ - { - "StorageClass": "GLACIER", - "TransitionInDays": 90 - } - ], - "Status": "Enabled" - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctiontests3stepfunctionWCloudTrailS3LoggingBucket449D5AB7" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "tests3stepfunctiontests3stepfunctionWCloudTrailS3BucketPolicy9ACF9ADC": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - }, - { - "Action": "s3:GetBucketAcl", - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489", - "Arn" - ] - }, - "/AWSLogs/", - { - "Ref": "AWS::AccountId" - }, - "/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctiontests3stepfunctionWS3EventsTrailA0FDE626": { - "Type": "AWS::CloudTrail::Trail", - "Properties": { - "IsLogging": true, - "S3BucketName": { - "Ref": "tests3stepfunctiontests3stepfunctionWCloudTrailS3Bucket24C50489" - }, - "EnableLogFileValidation": true, - "EventSelectors": [ - { - "DataResources": [ - { - "Type": "AWS::S3::Object", - "Values": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctiontests3stepfunctionWS3Bucket9BE64924", - "Arn" - ] - }, - "/" - ] - ] - } - ] - } - ], - "IncludeManagementEvents": false, - "ReadWriteType": "All" - } - ], - "IncludeGlobalServiceEvents": true, - "IsMultiRegionTrail": true - }, - "DependsOn": [ - "tests3stepfunctiontests3stepfunctionWCloudTrailS3BucketPolicy9ACF9ADC" - ] - }, "tests3stepfunctiontests3stepfunctionWtests3stepfunctionWeventrulestepfunctionconstructStateMachineLogGroupE83EECDD": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": "/aws/vendedlogs/states/customloggingbuckettests3stepfunctionweventrulestepfunctionconstructstatemachinelog0a1bbb9b57e8" }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", "Metadata": { "cfn_nag": { "rules_to_suppress": [ diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.ts index 1077a673e..ea2e52654 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.customLoggingBucket.ts @@ -37,6 +37,10 @@ new S3ToStepFunction(stack, 'test-s3-step-function', { bucketName: 'custom-logging-bucket', encryption: BucketEncryption.S3_MANAGED, versioned: true - } + }, + logGroupProps: { + removalPolicy: RemovalPolicy.DESTROY + }, + deployCloudTrail: false }); app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.expected.json index 9ed449646..196b20070 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.expected.json @@ -37,268 +37,6 @@ } } }, - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3LoggingBucket0FE28A33": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - } - ] - } - } - }, - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3LoggingBucketPolicy9C7C6620": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3LoggingBucket0FE28A33" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3LoggingBucket0FE28A33", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3LoggingBucket0FE28A33", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LifecycleConfiguration": { - "Rules": [ - { - "NoncurrentVersionTransitions": [ - { - "StorageClass": "GLACIER", - "TransitionInDays": 90 - } - ], - "Status": "Enabled" - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3LoggingBucket0FE28A33" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3BucketPolicyA31EBB8B": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - }, - { - "Action": "s3:GetBucketAcl", - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::GetAtt": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1", - "Arn" - ] - }, - "/AWSLogs/", - { - "Ref": "AWS::AccountId" - }, - "/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWS3EventsTrail9D60BAC8": { - "Type": "AWS::CloudTrail::Trail", - "Properties": { - "IsLogging": true, - "S3BucketName": { - "Ref": "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3Bucket3EEB70B1" - }, - "EnableLogFileValidation": true, - "EventSelectors": [ - { - "DataResources": [ - { - "Type": "AWS::S3::Object", - "Values": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":s3:::", - { - "Ref": "existingScriptLocation845F3C51" - }, - "/" - ] - ] - } - ] - } - ], - "IncludeManagementEvents": false, - "ReadWriteType": "All" - } - ], - "IncludeGlobalServiceEvents": true, - "IsMultiRegionTrail": true - }, - "DependsOn": [ - "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWCloudTrailS3BucketPolicyA31EBB8B" - ] - }, "tests3stepfunctionpreexistingbucketconstructtests3stepfunctionpreexistingbucketconstructWtests3stepfunctionpreexistingbucketconstructWeventrulestepfunctionconstructStateMachineLogGroupF215071C": { "Type": "AWS::Logs::LogGroup", "Properties": { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts index fbeaa76c7..df9ba8e5e 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.pre-existing-bucket.ts @@ -35,7 +35,9 @@ const props: S3ToStepFunctionProps = { logGroupProps: { removalPolicy: RemovalPolicy.DESTROY }, + deployCloudTrail: false }; new S3ToStepFunction(stack, 'test-s3-step-function-pre-existing-bucket-construct', props); + app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.expected.json index 5c8d80a72..9f0b44ec5 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.expected.json @@ -1,89 +1,5 @@ { "Resources": { - "tests3stepfunctionconstructtests3stepfunctionconstructWS3LoggingBucket615E11F3": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - } - ] - } - } - }, - "tests3stepfunctionconstructtests3stepfunctionconstructWS3LoggingBucketPolicyC5059059": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWS3LoggingBucket615E11F3" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWS3LoggingBucket615E11F3", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWS3LoggingBucket615E11F3", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1": { "Type": "AWS::S3::Bucket", "Properties": { @@ -109,11 +25,6 @@ } ] }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWS3LoggingBucket615E11F3" - } - }, "PublicAccessBlockConfiguration": { "BlockPublicAcls": true, "BlockPublicPolicy": true, @@ -125,188 +36,23 @@ } }, "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, - "tests3stepfunctionconstructtests3stepfunctionconstructWS3BucketPolicy4513F8D8": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3LoggingBucketC008CB57": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", + "DeletionPolicy": "Delete", "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" + "reason": "This S3 bucket is created for unit/ integration testing purposes only." } ] } } }, - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3LoggingBucketPolicyEBACDA63": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3LoggingBucketC008CB57" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3LoggingBucketC008CB57", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3LoggingBucketC008CB57", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LifecycleConfiguration": { - "Rules": [ - { - "NoncurrentVersionTransitions": [ - { - "StorageClass": "GLACIER", - "TransitionInDays": 90 - } - ], - "Status": "Enabled" - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3LoggingBucketC008CB57" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketPolicy25F2E4B1": { + "tests3stepfunctionconstructtests3stepfunctionconstructWS3BucketPolicy4513F8D8": { "Type": "AWS::S3::BucketPolicy", "Properties": { "Bucket": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E" + "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1" }, "PolicyDocument": { "Statement": [ @@ -328,7 +74,7 @@ [ { "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E", + "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1", "Arn" ] }, @@ -338,103 +84,18 @@ }, { "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E", + "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1", "Arn" ] } ], "Sid": "HttpsOnly" - }, - { - "Action": "s3:GetBucketAcl", - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E", - "Arn" - ] - }, - "/AWSLogs/", - { - "Ref": "AWS::AccountId" - }, - "/*" - ] - ] - } } ], "Version": "2012-10-17" } } }, - "tests3stepfunctionconstructtests3stepfunctionconstructWS3EventsTrail64B14DA8": { - "Type": "AWS::CloudTrail::Trail", - "Properties": { - "IsLogging": true, - "S3BucketName": { - "Ref": "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketACD4E98E" - }, - "EnableLogFileValidation": true, - "EventSelectors": [ - { - "DataResources": [ - { - "Type": "AWS::S3::Object", - "Values": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWS3Bucket474FE3A1", - "Arn" - ] - }, - "/" - ] - ] - } - ] - } - ], - "IncludeManagementEvents": false, - "ReadWriteType": "All" - } - ], - "IncludeGlobalServiceEvents": true, - "IsMultiRegionTrail": true - }, - "DependsOn": [ - "tests3stepfunctionconstructtests3stepfunctionconstructWCloudTrailS3BucketPolicy25F2E4B1" - ] - }, "tests3stepfunctionconstructtests3stepfunctionconstructWtests3stepfunctionconstructWeventrulestepfunctionconstructStateMachineLogGroup9A7BB9BF": { "Type": "AWS::Logs::LogGroup", "Properties": { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts index 38afb27a1..4d9313f99 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-step-function/test/integ.s3-step-function-no-argument.ts @@ -16,6 +16,8 @@ import { App, Stack, RemovalPolicy } from "@aws-cdk/core"; import { S3ToStepFunction, S3ToStepFunctionProps } from "../lib"; import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; import { generateIntegStackName } from '@aws-solutions-constructs/core'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as defaults from '@aws-solutions-constructs/core'; const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); @@ -32,7 +34,16 @@ const props: S3ToStepFunctionProps = { logGroupProps: { removalPolicy: RemovalPolicy.DESTROY }, + logS3AccessLogs: false, + deployCloudTrail: false }; -new S3ToStepFunction(stack, 'test-s3-step-function-construct', props); +const construct = new S3ToStepFunction(stack, 'test-s3-step-function-construct', props); +const s3Bucket = construct.s3Bucket as s3.Bucket; + +defaults.addCfnSuppressRules(s3Bucket, [ + { id: 'W35', + reason: 'This S3 bucket is created for unit/ integration testing purposes only.' }, +]); + app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md index 398d08b2e..0d2a21619 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/README.md @@ -59,25 +59,27 @@ _Parameters_ |:-------------|:----------------|-----------------| |existingBucketObj?|[`s3.IBucket`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-s3.IBucket.html)|Existing instance of S3 Bucket object. If this is provided, then also providing bucketProps is an error. | |bucketProps?|[`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 Bucket.| -|stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props to override the default props for sfn.StateMachine| -|eventRuleProps?|[`events.RuleProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.RuleProps.html)|Optional user provided eventRuleProps to override the defaults| +|stateMachineProps|[`sfn.StateMachineProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachineProps.html)|User provided props to override the default props for sfn.StateMachine.| +|eventRuleProps?|[`events.RuleProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-events.RuleProps.html)|Optional user provided eventRuleProps to override the defaults.| |deployCloudTrail?|`boolean`|Whether to deploy a Trail in AWS CloudTrail to log API events in Amazon S3. Defaults to `true`.| -|createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms| +|createCloudWatchAlarms|`boolean`|Whether to create recommended CloudWatch alarms.| |logGroupProps?|[`logs.LogGroupProps`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.LogGroupProps.html)|Optional user provided props to override the default props for for the CloudWatchLogs LogGroup.| |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.| +|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| ## Pattern Properties | **Name** | **Type** | **Description** | |:-------------|:----------------|-----------------| -|stateMachine|[`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of sfn.StateMachine created by the construct| -|stateMachineLogGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the ILogGroup created by the construct for StateMachine| -|cloudwatchAlarms?|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of cloudwatch.Alarm created by the construct| -|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| +|stateMachine|[`sfn.StateMachine`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-stepfunctions.StateMachine.html)|Returns an instance of sfn.StateMachine created by the construct.| +|stateMachineLogGroup|[`logs.ILogGroup`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-logs.ILogGroup.html)|Returns an instance of the ILogGroup created by the construct for StateMachine.| +|cloudwatchAlarms?|[`cloudwatch.Alarm[]`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudwatch.Alarm.html)|Returns a list of cloudwatch.Alarm created by the construct.| +|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.| |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.| -|cloudtrail|[`cloudtrail.Trail`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudtrail.Trail.html)|Returns an instance of the cloudtrail.Trail created by the construct| -|cloudtrailBucket|[`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 for CloudTrail| +|cloudtrail|[`cloudtrail.Trail`](https://docs.aws.amazon.com/cdk/api/latest/docs/@aws-cdk_aws-cloudtrail.Trail.html)|Returns an instance of the cloudtrail.Trail created by the construct.| +|cloudtrailBucket|[`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 for CloudTrail.| |cloudtrailLoggingBucket|[`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 CloudTrail bucket.| +|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.| ## Default settings diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts index ea7f853de..484930cfb 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/lib/index.ts @@ -49,7 +49,7 @@ export interface S3ToStepfunctionsProps { * * @default - None */ - readonly eventRuleProps?: events.RuleProps; + readonly eventRuleProps?: events.RuleProps, /** * Whether to deploy a Trail in AWS CloudTrail to log API events in Amazon S3 * @@ -67,13 +67,20 @@ export interface S3ToStepfunctionsProps { * * @default - Default props are used */ - readonly logGroupProps?: logs.LogGroupProps + readonly logGroupProps?: logs.LogGroupProps, /** * Optional user provided props to override the default props for the S3 Logging Bucket. * * @default - Default props are used */ - readonly loggingBucketProps?: s3.BucketProps + readonly loggingBucketProps?: s3.BucketProps, + /** + * Whether to turn on Access Logs for the S3 bucket with the associated storage costs. + * Enabling Access Logging is a best practice. + * + * @default - true + */ + readonly logS3AccessLogs?: boolean; } export class S3ToStepfunctions extends Construct { @@ -85,6 +92,7 @@ export class S3ToStepfunctions extends Construct { public readonly cloudtrail?: cloudtrail.Trail; public readonly cloudtrailBucket?: s3.Bucket; public readonly cloudtrailLoggingBucket?: s3.Bucket; + public readonly s3BucketInterface: s3.IBucket; /** * @summary Constructs a new instance of the S3ToStepfunctions class. @@ -99,20 +107,19 @@ export class S3ToStepfunctions extends Construct { let bucket: s3.IBucket; - if (props.existingBucketObj && props.bucketProps) { - throw new Error('Cannot specify both bucket properties and an existing bucket'); - } - if (!props.existingBucketObj) { [this.s3Bucket, this.s3LoggingBucket] = defaults.buildS3Bucket(this, { bucketProps: props.bucketProps, - loggingBucketProps: props.loggingBucketProps + loggingBucketProps: props.loggingBucketProps, + logS3AccessLogs: props.logS3AccessLogs }); bucket = this.s3Bucket; } else { bucket = props.existingBucketObj; } + this.s3BucketInterface = bucket; + if (props.deployCloudTrail === undefined || props.deployCloudTrail) { [this.cloudtrailBucket, this.cloudtrailLoggingBucket] = defaults.buildS3Bucket(this, {}, 'CloudTrail'); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.expected.json index 47b278e81..062c119ed 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.expected.json @@ -176,273 +176,13 @@ } } }, - "tests3stepfunctionsCloudTrailS3LoggingBucket6C453FDC": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - } - ] - } - } - }, - "tests3stepfunctionsCloudTrailS3LoggingBucketPolicy7ECEA4CB": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionsCloudTrailS3LoggingBucket6C453FDC" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsCloudTrailS3LoggingBucket6C453FDC", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionsCloudTrailS3LoggingBucket6C453FDC", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionsCloudTrailS3BucketA4862EB5": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LifecycleConfiguration": { - "Rules": [ - { - "NoncurrentVersionTransitions": [ - { - "StorageClass": "GLACIER", - "TransitionInDays": 90 - } - ], - "Status": "Enabled" - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionsCloudTrailS3LoggingBucket6C453FDC" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "tests3stepfunctionsCloudTrailS3BucketPolicyFABF3402": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionsCloudTrailS3BucketA4862EB5" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsCloudTrailS3BucketA4862EB5", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionsCloudTrailS3BucketA4862EB5", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - }, - { - "Action": "s3:GetBucketAcl", - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::GetAtt": [ - "tests3stepfunctionsCloudTrailS3BucketA4862EB5", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsCloudTrailS3BucketA4862EB5", - "Arn" - ] - }, - "/AWSLogs/", - { - "Ref": "AWS::AccountId" - }, - "/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionsS3EventsTrailD0D47427": { - "Type": "AWS::CloudTrail::Trail", - "Properties": { - "IsLogging": true, - "S3BucketName": { - "Ref": "tests3stepfunctionsCloudTrailS3BucketA4862EB5" - }, - "EnableLogFileValidation": true, - "EventSelectors": [ - { - "DataResources": [ - { - "Type": "AWS::S3::Object", - "Values": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsS3Bucket2B08AD28", - "Arn" - ] - }, - "/" - ] - ] - } - ] - } - ], - "IncludeManagementEvents": false, - "ReadWriteType": "All" - } - ], - "IncludeGlobalServiceEvents": true, - "IsMultiRegionTrail": true - }, - "DependsOn": [ - "tests3stepfunctionsCloudTrailS3BucketPolicyFABF3402" - ] - }, "tests3stepfunctionstests3stepfunctionseventrulestepfunctionconstructStateMachineLogGroupB4555776": { "Type": "AWS::Logs::LogGroup", "Properties": { "LogGroupName": "/aws/vendedlogs/states/customloggingbuckettests3stepfunctionseventrulestepfunctionconstructstatemachineloga4e9bc58c9e9" }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete", "Metadata": { "cfn_nag": { "rules_to_suppress": [ diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.ts index 7b18dd21c..72bed7010 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.customLoggingBucket.ts @@ -37,6 +37,10 @@ new S3ToStepfunctions(stack, 'test-s3-stepfunctions', { bucketName: 'custom-logging-bucket', encryption: BucketEncryption.S3_MANAGED, versioned: true - } + }, + logGroupProps: { + removalPolicy: RemovalPolicy.DESTROY + }, + deployCloudTrail: false }); app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.expected.json index 9be6fd795..f0e083e0f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.expected.json @@ -37,268 +37,6 @@ } } }, - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3LoggingBucket02008411": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - } - ] - } - } - }, - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3LoggingBucketPolicyDD998565": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionspreexistingbucketconstructCloudTrailS3LoggingBucket02008411" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3LoggingBucket02008411", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3LoggingBucket02008411", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LifecycleConfiguration": { - "Rules": [ - { - "NoncurrentVersionTransitions": [ - { - "StorageClass": "GLACIER", - "TransitionInDays": 90 - } - ], - "Status": "Enabled" - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionspreexistingbucketconstructCloudTrailS3LoggingBucket02008411" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3BucketPolicy90D5D088": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - }, - { - "Action": "s3:GetBucketAcl", - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::GetAtt": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182", - "Arn" - ] - }, - "/AWSLogs/", - { - "Ref": "AWS::AccountId" - }, - "/*" - ] - ] - } - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionspreexistingbucketconstructS3EventsTrail79807AC0": { - "Type": "AWS::CloudTrail::Trail", - "Properties": { - "IsLogging": true, - "S3BucketName": { - "Ref": "tests3stepfunctionspreexistingbucketconstructCloudTrailS3Bucket40DD8182" - }, - "EnableLogFileValidation": true, - "EventSelectors": [ - { - "DataResources": [ - { - "Type": "AWS::S3::Object", - "Values": [ - { - "Fn::Join": [ - "", - [ - "arn:", - { - "Ref": "AWS::Partition" - }, - ":s3:::", - { - "Ref": "existingScriptLocation845F3C51" - }, - "/" - ] - ] - } - ] - } - ], - "IncludeManagementEvents": false, - "ReadWriteType": "All" - } - ], - "IncludeGlobalServiceEvents": true, - "IsMultiRegionTrail": true - }, - "DependsOn": [ - "tests3stepfunctionspreexistingbucketconstructCloudTrailS3BucketPolicy90D5D088" - ] - }, "tests3stepfunctionspreexistingbucketconstructtests3stepfunctionspreexistingbucketconstructeventrulestepfunctionconstructStateMachineLogGroup9D5E3E4D": { "Type": "AWS::Logs::LogGroup", "Properties": { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.ts index b5b598319..2423f215f 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.pre-existing-bucket.ts @@ -35,7 +35,10 @@ const props: S3ToStepfunctionsProps = { logGroupProps: { removalPolicy: RemovalPolicy.DESTROY }, + logS3AccessLogs: false, + deployCloudTrail: false }; new S3ToStepfunctions(stack, 'test-s3-stepfunctions-pre-existing-bucket-construct', props); + app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.expected.json b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.expected.json index f55c15e55..c01685134 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.expected.json +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.expected.json @@ -1,89 +1,5 @@ { "Resources": { - "tests3stepfunctionsconstructS3LoggingBucket706AEC25": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete", - "Metadata": { - "cfn_nag": { - "rules_to_suppress": [ - { - "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" - } - ] - } - } - }, - "tests3stepfunctionsconstructS3LoggingBucketPolicy4FEACD99": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionsconstructS3LoggingBucket706AEC25" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructS3LoggingBucket706AEC25", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructS3LoggingBucket706AEC25", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, "tests3stepfunctionsconstructS3Bucket78CA0724": { "Type": "AWS::S3::Bucket", "Properties": { @@ -109,11 +25,6 @@ } ] }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionsconstructS3LoggingBucket706AEC25" - } - }, "PublicAccessBlockConfiguration": { "BlockPublicAcls": true, "BlockPublicPolicy": true, @@ -125,188 +36,23 @@ } }, "UpdateReplacePolicy": "Delete", - "DeletionPolicy": "Delete" - }, - "tests3stepfunctionsconstructS3BucketPolicyC7A413B9": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionsconstructS3Bucket78CA0724" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructS3Bucket78CA0724", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructS3Bucket78CA0724", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionsconstructCloudTrailS3LoggingBucket3395ADC0": { - "Type": "AWS::S3::Bucket", - "Properties": { - "AccessControl": "LogDeliveryWrite", - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain", + "DeletionPolicy": "Delete", "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W35", - "reason": "This S3 bucket is used as the access logging bucket for another bucket" + "reason": "This S3 bucket is created for unit/ integration testing purposes only." } ] } } }, - "tests3stepfunctionsconstructCloudTrailS3LoggingBucketPolicy0F9D945F": { - "Type": "AWS::S3::BucketPolicy", - "Properties": { - "Bucket": { - "Ref": "tests3stepfunctionsconstructCloudTrailS3LoggingBucket3395ADC0" - }, - "PolicyDocument": { - "Statement": [ - { - "Action": "*", - "Condition": { - "Bool": { - "aws:SecureTransport": "false" - } - }, - "Effect": "Deny", - "Principal": { - "AWS": "*" - }, - "Resource": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructCloudTrailS3LoggingBucket3395ADC0", - "Arn" - ] - }, - "/*" - ] - ] - }, - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructCloudTrailS3LoggingBucket3395ADC0", - "Arn" - ] - } - ], - "Sid": "HttpsOnly" - } - ], - "Version": "2012-10-17" - } - } - }, - "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01": { - "Type": "AWS::S3::Bucket", - "Properties": { - "BucketEncryption": { - "ServerSideEncryptionConfiguration": [ - { - "ServerSideEncryptionByDefault": { - "SSEAlgorithm": "AES256" - } - } - ] - }, - "LifecycleConfiguration": { - "Rules": [ - { - "NoncurrentVersionTransitions": [ - { - "StorageClass": "GLACIER", - "TransitionInDays": 90 - } - ], - "Status": "Enabled" - } - ] - }, - "LoggingConfiguration": { - "DestinationBucketName": { - "Ref": "tests3stepfunctionsconstructCloudTrailS3LoggingBucket3395ADC0" - } - }, - "PublicAccessBlockConfiguration": { - "BlockPublicAcls": true, - "BlockPublicPolicy": true, - "IgnorePublicAcls": true, - "RestrictPublicBuckets": true - }, - "VersioningConfiguration": { - "Status": "Enabled" - } - }, - "UpdateReplacePolicy": "Retain", - "DeletionPolicy": "Retain" - }, - "tests3stepfunctionsconstructCloudTrailS3BucketPolicy2B5E1F0B": { + "tests3stepfunctionsconstructS3BucketPolicyC7A413B9": { "Type": "AWS::S3::BucketPolicy", "Properties": { "Bucket": { - "Ref": "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01" + "Ref": "tests3stepfunctionsconstructS3Bucket78CA0724" }, "PolicyDocument": { "Statement": [ @@ -328,7 +74,7 @@ [ { "Fn::GetAtt": [ - "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01", + "tests3stepfunctionsconstructS3Bucket78CA0724", "Arn" ] }, @@ -338,103 +84,18 @@ }, { "Fn::GetAtt": [ - "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01", + "tests3stepfunctionsconstructS3Bucket78CA0724", "Arn" ] } ], "Sid": "HttpsOnly" - }, - { - "Action": "s3:GetBucketAcl", - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01", - "Arn" - ] - } - }, - { - "Action": "s3:PutObject", - "Condition": { - "StringEquals": { - "s3:x-amz-acl": "bucket-owner-full-control" - } - }, - "Effect": "Allow", - "Principal": { - "Service": "cloudtrail.amazonaws.com" - }, - "Resource": { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01", - "Arn" - ] - }, - "/AWSLogs/", - { - "Ref": "AWS::AccountId" - }, - "/*" - ] - ] - } } ], "Version": "2012-10-17" } } }, - "tests3stepfunctionsconstructS3EventsTrail7D3B05A8": { - "Type": "AWS::CloudTrail::Trail", - "Properties": { - "IsLogging": true, - "S3BucketName": { - "Ref": "tests3stepfunctionsconstructCloudTrailS3Bucket2739BE01" - }, - "EnableLogFileValidation": true, - "EventSelectors": [ - { - "DataResources": [ - { - "Type": "AWS::S3::Object", - "Values": [ - { - "Fn::Join": [ - "", - [ - { - "Fn::GetAtt": [ - "tests3stepfunctionsconstructS3Bucket78CA0724", - "Arn" - ] - }, - "/" - ] - ] - } - ] - } - ], - "IncludeManagementEvents": false, - "ReadWriteType": "All" - } - ], - "IncludeGlobalServiceEvents": true, - "IsMultiRegionTrail": true - }, - "DependsOn": [ - "tests3stepfunctionsconstructCloudTrailS3BucketPolicy2B5E1F0B" - ] - }, "tests3stepfunctionsconstructtests3stepfunctionsconstructeventrulestepfunctionconstructStateMachineLogGroupE86C2CF5": { "Type": "AWS::Logs::LogGroup", "Properties": { diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.ts index 3c9fb702b..51f5e6350 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/integ.s3-stepfunctions-no-argument.ts @@ -16,6 +16,8 @@ import { App, Stack, RemovalPolicy } from "@aws-cdk/core"; import { S3ToStepfunctions, S3ToStepfunctionsProps } from "../lib"; import * as stepfunctions from '@aws-cdk/aws-stepfunctions'; import { generateIntegStackName } from '@aws-solutions-constructs/core'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as defaults from '@aws-solutions-constructs/core'; const app = new App(); const stack = new Stack(app, generateIntegStackName(__filename)); @@ -32,7 +34,16 @@ const props: S3ToStepfunctionsProps = { logGroupProps: { removalPolicy: RemovalPolicy.DESTROY }, + logS3AccessLogs: false, + deployCloudTrail: false }; -new S3ToStepfunctions(stack, 'test-s3-stepfunctions-construct', props); +const construct = new S3ToStepfunctions(stack, 'test-s3-stepfunctions-construct', props); +const s3Bucket = construct.s3Bucket as s3.Bucket; + +defaults.addCfnSuppressRules(s3Bucket, [ + { id: 'W35', + reason: 'This S3 bucket is created for unit/ integration testing purposes only.' }, +]); + app.synth(); diff --git a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/s3-stepfunctions.test.ts b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/s3-stepfunctions.test.ts index bbc27f4d2..7632dd420 100644 --- a/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/s3-stepfunctions.test.ts +++ b/source/patterns/@aws-solutions-constructs/aws-s3-stepfunctions/test/s3-stepfunctions.test.ts @@ -202,4 +202,24 @@ test('s3 bucket with bucket, loggingBucket, and auto delete objects', () => { Ref: "tests3stepfunctionsS3LoggingBucketF7586A92" } }); +}); + +// -------------------------------------------------------------- +// s3 bucket with one content bucket and no logging bucket +// -------------------------------------------------------------- +test('s3 bucket with no logging bucket', () => { + const stack = new cdk.Stack(); + const startState = new sfn.Pass(stack, 'StartState'); + + const construct = new S3ToStepfunctions(stack, 's3-stepfunctions', { + stateMachineProps: { + definition: startState + }, + bucketProps: { + removalPolicy: cdk.RemovalPolicy.DESTROY, + }, + logS3AccessLogs: false + }); + + expect(construct.s3LoggingBucket).toEqual(undefined); }); \ No newline at end of file