|
114 | 114 | "Ref": "tests3stepfunctiontests3stepfunctionWS3LoggingBucketB716417C"
|
115 | 115 | }
|
116 | 116 | },
|
117 |
| - "NotificationConfiguration": { |
118 |
| - "EventBridgeConfiguration": { |
119 |
| - "EventBridgeEnabled": true |
120 |
| - } |
121 |
| - }, |
122 | 117 | "PublicAccessBlockConfiguration": {
|
123 | 118 | "BlockPublicAcls": true,
|
124 | 119 | "BlockPublicPolicy": true,
|
|
179 | 174 | }
|
180 | 175 | }
|
181 | 176 | },
|
| 177 | + "tests3stepfunctiontests3stepfunctionWS3BucketNotificationsC4380C1D": { |
| 178 | + "Type": "Custom::S3BucketNotifications", |
| 179 | + "Properties": { |
| 180 | + "ServiceToken": { |
| 181 | + "Fn::GetAtt": [ |
| 182 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691", |
| 183 | + "Arn" |
| 184 | + ] |
| 185 | + }, |
| 186 | + "BucketName": { |
| 187 | + "Ref": "tests3stepfunctiontests3stepfunctionWS3Bucket9BE64924" |
| 188 | + }, |
| 189 | + "NotificationConfiguration": { |
| 190 | + "EventBridgeConfiguration": {} |
| 191 | + }, |
| 192 | + "Managed": true |
| 193 | + } |
| 194 | + }, |
182 | 195 | "tests3stepfunctiontests3stepfunctionWtests3stepfunctionWeventrulestepfunctionconstructStateMachineLogGroupE83EECDD": {
|
183 | 196 | "Type": "AWS::Logs::LogGroup",
|
184 | 197 | "Properties": {
|
|
461 | 474 | "Statistic": "Maximum",
|
462 | 475 | "Threshold": 1
|
463 | 476 | }
|
| 477 | + }, |
| 478 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC": { |
| 479 | + "Type": "AWS::IAM::Role", |
| 480 | + "Properties": { |
| 481 | + "AssumeRolePolicyDocument": { |
| 482 | + "Statement": [ |
| 483 | + { |
| 484 | + "Action": "sts:AssumeRole", |
| 485 | + "Effect": "Allow", |
| 486 | + "Principal": { |
| 487 | + "Service": "lambda.amazonaws.com" |
| 488 | + } |
| 489 | + } |
| 490 | + ], |
| 491 | + "Version": "2012-10-17" |
| 492 | + }, |
| 493 | + "ManagedPolicyArns": [ |
| 494 | + { |
| 495 | + "Fn::Join": [ |
| 496 | + "", |
| 497 | + [ |
| 498 | + "arn:", |
| 499 | + { |
| 500 | + "Ref": "AWS::Partition" |
| 501 | + }, |
| 502 | + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" |
| 503 | + ] |
| 504 | + ] |
| 505 | + } |
| 506 | + ] |
| 507 | + } |
| 508 | + }, |
| 509 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36": { |
| 510 | + "Type": "AWS::IAM::Policy", |
| 511 | + "Properties": { |
| 512 | + "PolicyDocument": { |
| 513 | + "Statement": [ |
| 514 | + { |
| 515 | + "Action": "s3:PutBucketNotification", |
| 516 | + "Effect": "Allow", |
| 517 | + "Resource": "*" |
| 518 | + } |
| 519 | + ], |
| 520 | + "Version": "2012-10-17" |
| 521 | + }, |
| 522 | + "PolicyName": "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", |
| 523 | + "Roles": [ |
| 524 | + { |
| 525 | + "Ref": "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC" |
| 526 | + } |
| 527 | + ] |
| 528 | + }, |
| 529 | + "Metadata": { |
| 530 | + "cfn_nag": { |
| 531 | + "rules_to_suppress": [ |
| 532 | + { |
| 533 | + "id": "W12", |
| 534 | + "reason": "Bucket resource is '*' due to circular dependency with bucket and role creation at the same time" |
| 535 | + } |
| 536 | + ] |
| 537 | + } |
| 538 | + } |
| 539 | + }, |
| 540 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db8347ECC3691": { |
| 541 | + "Type": "AWS::Lambda::Function", |
| 542 | + "Properties": { |
| 543 | + "Description": "AWS CloudFormation handler for \"Custom::S3BucketNotifications\" resources (@aws-cdk/aws-s3)", |
| 544 | + "Code": { |
| 545 | + "ZipFile": "import boto3 # type: ignore\nimport json\nimport logging\nimport urllib.request\n\ns3 = boto3.client(\"s3\")\n\nEVENTBRIDGE_CONFIGURATION = 'EventBridgeConfiguration'\n\nCONFIGURATION_TYPES = [\"TopicConfigurations\", \"QueueConfigurations\", \"LambdaFunctionConfigurations\"]\n\ndef handler(event: dict, context):\n response_status = \"SUCCESS\"\n error_message = \"\"\n try:\n props = event[\"ResourceProperties\"]\n bucket = props[\"BucketName\"]\n notification_configuration = props[\"NotificationConfiguration\"]\n request_type = event[\"RequestType\"]\n managed = props.get('Managed', 'true').lower() == 'true'\n stack_id = event['StackId']\n\n if managed:\n config = handle_managed(request_type, notification_configuration)\n else:\n config = handle_unmanaged(bucket, stack_id, request_type, notification_configuration)\n\n put_bucket_notification_configuration(bucket, config)\n except Exception as e:\n logging.exception(\"Failed to put bucket notification configuration\")\n response_status = \"FAILED\"\n error_message = f\"Error: {str(e)}. \"\n finally:\n submit_response(event, context, response_status, error_message)\n\ndef handle_managed(request_type, notification_configuration):\n if request_type == 'Delete':\n return {}\n return notification_configuration\n\ndef handle_unmanaged(bucket, stack_id, request_type, notification_configuration):\n external_notifications = find_external_notifications(bucket, stack_id)\n\n if request_type == 'Delete':\n return external_notifications\n\n def with_id(notification):\n notification['Id'] = f\"{stack_id}-{hash(json.dumps(notification, sort_keys=True))}\"\n return notification\n\n notifications = {}\n for t in CONFIGURATION_TYPES:\n external = external_notifications.get(t, [])\n incoming = [with_id(n) for n in notification_configuration.get(t, [])]\n notifications[t] = external + incoming\n\n if EVENTBRIDGE_CONFIGURATION in notification_configuration:\n notifications[EVENTBRIDGE_CONFIGURATION] = notification_configuration[EVENTBRIDGE_CONFIGURATION]\n elif EVENTBRIDGE_CONFIGURATION in external_notifications:\n notifications[EVENTBRIDGE_CONFIGURATION] = external_notifications[EVENTBRIDGE_CONFIGURATION]\n\n return notifications\n\ndef find_external_notifications(bucket, stack_id):\n existing_notifications = get_bucket_notification_configuration(bucket)\n external_notifications = {}\n for t in CONFIGURATION_TYPES:\n external_notifications[t] = [n for n in existing_notifications.get(t, []) if not n['Id'].startswith(f\"{stack_id}-\")]\n\n if EVENTBRIDGE_CONFIGURATION in existing_notifications:\n external_notifications[EVENTBRIDGE_CONFIGURATION] = existing_notifications[EVENTBRIDGE_CONFIGURATION]\n\n return external_notifications\n\ndef get_bucket_notification_configuration(bucket):\n return s3.get_bucket_notification_configuration(Bucket=bucket)\n\ndef put_bucket_notification_configuration(bucket, notification_configuration):\n s3.put_bucket_notification_configuration(Bucket=bucket, NotificationConfiguration=notification_configuration)\n\ndef submit_response(event: dict, context, response_status: str, error_message: str):\n response_body = json.dumps(\n {\n \"Status\": response_status,\n \"Reason\": f\"{error_message}See the details in CloudWatch Log Stream: {context.log_stream_name}\",\n \"PhysicalResourceId\": event.get(\"PhysicalResourceId\") or event[\"LogicalResourceId\"],\n \"StackId\": event[\"StackId\"],\n \"RequestId\": event[\"RequestId\"],\n \"LogicalResourceId\": event[\"LogicalResourceId\"],\n \"NoEcho\": False,\n }\n ).encode(\"utf-8\")\n headers = {\"content-type\": \"\", \"content-length\": str(len(response_body))}\n try:\n req = urllib.request.Request(url=event[\"ResponseURL\"], headers=headers, data=response_body, method=\"PUT\")\n with urllib.request.urlopen(req) as response:\n print(response.read().decode(\"utf-8\"))\n print(\"Status code: \" + response.reason)\n except Exception as e:\n print(\"send(..) failed executing request.urlopen(..): \" + str(e))\n" |
| 546 | + }, |
| 547 | + "Handler": "index.handler", |
| 548 | + "Role": { |
| 549 | + "Fn::GetAtt": [ |
| 550 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC", |
| 551 | + "Arn" |
| 552 | + ] |
| 553 | + }, |
| 554 | + "Runtime": "python3.7", |
| 555 | + "Timeout": 300 |
| 556 | + }, |
| 557 | + "DependsOn": [ |
| 558 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleDefaultPolicy2CF63D36", |
| 559 | + "BucketNotificationsHandler050a0587b7544547bf325f094a3db834RoleB6FB88EC" |
| 560 | + ], |
| 561 | + "Metadata": { |
| 562 | + "cfn_nag": { |
| 563 | + "rules_to_suppress": [ |
| 564 | + { |
| 565 | + "id": "W58", |
| 566 | + "reason": "Lambda functions has the required permission to write CloudWatch Logs. It uses custom policy instead of arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole with tighter permissions." |
| 567 | + }, |
| 568 | + { |
| 569 | + "id": "W89", |
| 570 | + "reason": "This is not a rule for the general case, just for specific use cases/industries" |
| 571 | + }, |
| 572 | + { |
| 573 | + "id": "W92", |
| 574 | + "reason": "Impossible for us to define the correct concurrency for clients" |
| 575 | + } |
| 576 | + ] |
| 577 | + } |
| 578 | + } |
464 | 579 | }
|
465 | 580 | },
|
466 | 581 | "Mappings": {
|
|
0 commit comments