# This is modified from https://github.com/aws-quickstart/quickstart-bitnami-wordpress/blob/master/templates/copy-lambdas.template --- AWSTemplateFormatVersion: '2010-09-09' Description: This template creates an S3 bucket in the same region where the stack is launched and copy the Lambda functions code from original bucket to the new bucket. (qs-1op312ie1) Metadata: cfn-lint: config: ignore_checks: - W9002 - W9003 - W9006 Parameters: LogBucket: Type: String Description: Log Bucket QSS3BucketName: AllowedPattern: "^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$" ConstraintDescription: Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Default: aws-quickstart Description: S3 bucket name for the Quick Start assets. Quick Start bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String QSS3BucketRegion: Default: 'us-east-1' Description: 'The AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value.' Type: String QSS3KeyPrefix: AllowedPattern: "^[0-9a-zA-Z-/]*$" ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Default: quickstart-codepipeline-bluegreen-deployment/ Description: S3 key prefix for the Quick Start assets. Quick Start key prefix can include numbers, lowercase letters, uppercase letters, hyphens (-), and forward slash (/). Type: String QSTagKey: Type: String Description: Tag key to identify resources from this Quick Start QSTagValue: Type: String Description: Tag value to identify resources from this Quick Start Mappings: Storage: LambdaZips: LogPrefix: lambda-zips/ Conditions: UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart'] Resources: CopyObjects: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt CopyObjectsFunction.Arn DestBucket: !Ref LambdaZipsBucket Objects: - functions/packages/ACMCert/lambda.zip SourceBucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Prefix: !Ref QSS3KeyPrefix CopyObjectsFunction: Type: AWS::Lambda::Function Properties: Code: ZipFile: | import json import logging import threading import boto3 import cfnresponse def copy_objects(source_bucket, dest_bucket, prefix, objects): s3 = boto3.client('s3') for o in objects: key = prefix + o copy_source = { 'Bucket': source_bucket, 'Key': key } s3.copy_object(CopySource=copy_source, Bucket=dest_bucket, Key=key) def delete_objects(bucket): client = boto3.client('s3') print("Collecting data from" + bucket) paginator = client.get_paginator('list_object_versions') result = paginator.paginate(Bucket=bucket) objects = [] for page in result: try: for k in page['Versions']: objects.append({'Key':k['Key'],'VersionId': k['VersionId']}) try: for k in page['DeleteMarkers']: version = k['VersionId'] key = k['Key'] objects.append({'Key': key,'VersionId': version}) except: pass print("deleting objects") client.delete_objects(Bucket=bucket, Delete={'Objects': objects}) except: pass print("bucket already empty") def timeout(event, context): logging.error('Execution is about to time out, sending failure response to CloudFormation') cfnresponse.send(event, context, cfnresponse.FAILED, {}, None) def handler(event, context): # make sure we send a failure to CloudFormation if the function is going to timeout timer = threading.Timer((context.get_remaining_time_in_millis() / 1000.00) - 0.5, timeout, args=[event, context]) timer.start() print('Received event: %s' % json.dumps(event)) status = cfnresponse.SUCCESS try: source_bucket = event['ResourceProperties']['SourceBucket'] dest_bucket = event['ResourceProperties']['DestBucket'] prefix = event['ResourceProperties']['Prefix'] objects = event['ResourceProperties']['Objects'] if event['RequestType'] == 'Delete': delete_objects(dest_bucket) else: copy_objects(source_bucket, dest_bucket, prefix, objects) except Exception as e: logging.error('Exception: %s' % e, exc_info=True) status = cfnresponse.FAILED finally: timer.cancel() cfnresponse.send(event, context, status, {}, None) Description: Copies objects from a source S3 bucket to a destination S3 bucket Handler: index.handler Role: !GetAtt CopyObjectsRole.Arn Runtime: python3.7 Tags: - Key: !Ref QSTagKey Value: !Ref QSTagValue Timeout: 600 CopyObjectsRole: Properties: AssumeRolePolicyDocument: Statement: - Action: sts:AssumeRole Effect: Allow Principal: Service: lambda.amazonaws.com Version: '2012-10-17' ManagedPolicyArns: - !Sub 'arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Path: "/" Policies: - PolicyDocument: Statement: - Action: - s3:GetObject Effect: Allow Resource: !Sub - arn:${AWS::Partition}:s3:::${S3Bucket}/${QSS3KeyPrefix}* - S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] - Action: - s3:PutObject - s3:DeleteObject - s3:GetObject - s3:ListBucket - s3:ListBucketVersions - s3:DeleteObjectVersion - s3:GetObjectVersion - s3:GetBucketVersioning Effect: Allow Resource: - !Sub arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}* - !Sub arn:${AWS::Partition}:s3:::${LambdaZipsBucket} Version: '2012-10-17' PolicyName: object-copier Type: AWS::IAM::Role LambdaZipsBucket: Type: AWS::S3::Bucket Properties: AccessControl: Private BucketEncryption: ServerSideEncryptionConfiguration: - ServerSideEncryptionByDefault: SSEAlgorithm: AES256 LoggingConfiguration: DestinationBucketName: !Ref LogBucket LogFilePrefix: !FindInMap [ Storage, LambdaZips, LogPrefix ] Tags: - Key: !Ref QSTagKey Value: !Ref QSTagValue VersioningConfiguration: Status: Enabled LambdaZipsBucketPolicy: DependsOn: CleanupLambdaZipsBucket Type: AWS::S3::BucketPolicy Properties: Bucket: !Ref LambdaZipsBucket PolicyDocument: Version: 2012-10-17 Id: LambdaZipsBucketPolicy Statement: - Sid: ForceSSL Effect: Deny Principal: "*" Action: s3:* Resource: !Sub arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/* Condition: Bool: "aws:SecureTransport": "false" CleanupLambdaZipsBucket: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/clean-bucket.template - S3Region: !If [UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion] S3Bucket: !If [UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName] Parameters: Bucket: !Ref LambdaZipsBucket QSTagKey: !Ref QSTagKey QSTagValue: !Ref QSTagValue Tags: - Key: !Ref QSTagKey Value: !Ref QSTagValue Outputs: LambdaZipsBucket: Description: S3 Bucket for the Lambda Function Code Value: !Ref LambdaZipsBucket