# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 # # Permission is hereby granted, free of charge, to any person obtaining a copy of this # software and associated documentation files (the "Software"), to deal in the Software # without restriction, including without limitation the rights to use, copy, modify, # merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AWSTemplateFormatVersion: 2010-09-09 Description: Solution that uses SSM Automation to create encrypted snapshots of RDS clusters and then copy those snapshots to a different AWS region for DR purposes. Parameters: DBClusterIdentifier: Type: String Description: DBClusterIdentifier of the RDS cluster to be backup MinLength: 1 MaxLength: 63 SourceRegion: Type: String Description: Region where the RDS cluster is located MinLength: 9 TargetRegion: Type: String Description: Region to copy the snapshot to MinLength: 9 KMSTargetKey: Type: String Description: KMS Key ID in Target AWS region MinLength: 1 Resources: CrossRegionSnapshotCopySSMAutomationRole: Type: AWS::IAM::Role Properties: RoleName: Fn::Join: - "-" - - "CRDR-SSMRole" - !Ref DBClusterIdentifier - Fn::Select: - 0 - Fn::Split: - "-" - Fn::Select: - 2 - Fn::Split: - "/" - !Ref AWS::StackId AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Action: - sts:AssumeRole Effect: Allow Principal: Service: - ssm.amazonaws.com Path: "/" Policies: - PolicyName: Fn::Join: - "-" - - "CRDR-SSMPolicy" - !Ref DBClusterIdentifier - Fn::Select: - 0 - Fn::Split: - "-" - Fn::Select: - 2 - Fn::Split: - "/" - !Ref AWS::StackId PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: ["rds:CreateDBClusterSnapshot"] Resource: - Fn::Join: - ":" - - "arn:aws:rds" - !Ref SourceRegion - !Ref AWS::AccountId - "cluster" - !Ref DBClusterIdentifier - Fn::Join: - ":" - - "arn:aws:rds" - !Ref SourceRegion - !Ref AWS::AccountId - "cluster-snapshot" - Fn::Join: - "-" - - !Ref DBClusterIdentifier - 'db-snapshot-*' - Effect: Allow Action: ["rds:DescribeDBClusterSnapshots"] Resource: - "*" - Effect: Allow Action: ["rds:CopyDBClusterSnapshot"] Resource: - Fn::Join: - ":" - - "arn:aws:rds" - !Ref SourceRegion - !Ref AWS::AccountId - "cluster-snapshot" - Fn::Join: - "-" - - !Ref DBClusterIdentifier - 'db-snapshot-*' - Fn::Join: - ":" - - "arn:aws:rds" - !Ref TargetRegion - !Ref AWS::AccountId - "cluster-snapshot" - Fn::Join: - "-" - - !Ref DBClusterIdentifier - 'db-snapshot-*' - Effect: Allow Action: ["kms:DescribeKey","kms:CreateGrant"] Resource: - Fn::Join: - ":" - - "arn:aws:kms" - !Ref TargetRegion - !Ref AWS::AccountId - Fn::Join: - "" - - "key/" - !Ref KMSTargetKey CrossRegionSnapshotCopySSMAutomation: Type: AWS::SSM::Document Properties: DocumentType: Automation Name: Fn::Join: - "-" - - "CRDR-SSMAutomation" - !Ref DBClusterIdentifier - Fn::Select: - 0 - Fn::Split: - "-" - Fn::Select: - 2 - Fn::Split: - "/" - !Ref AWS::StackId Content: description: Aurora RDS Cluster Snapshot and Copy Automation Document schemaVersion: '0.3' assumeRole: !GetAtt CrossRegionSnapshotCopySSMAutomationRole.Arn mainSteps: - name: CreateSnapshot action: 'aws:executeAwsApi' inputs: Service: rds Api: CreateDBClusterSnapshot DBClusterSnapshotIdentifier: Fn::Join: - "-" - - !Ref DBClusterIdentifier - 'db-snapshot-{{automation:EXECUTION_ID}}' DBClusterIdentifier: !Ref DBClusterIdentifier outputs: - Name: SnapShotId Selector: $.DBClusterSnapshot.DBClusterSnapshotIdentifier Type: String - Name: DBClusterId Selector: $.DBClusterSnapshot.DBClusterIdentifier Type: String - Name: DBClusterSnapshotArn Selector: $.DBClusterSnapshot.DBClusterSnapshotArn Type: String - name: waitForSnapshotCompletion action: 'aws:waitForAwsResourceProperty' inputs: Service: rds Api: DescribeDBClusterSnapshots DBClusterSnapshotIdentifier: Fn::Join: - "-" - - !Ref DBClusterIdentifier - 'db-snapshot-{{automation:EXECUTION_ID}}' DBClusterIdentifier: !Ref DBClusterIdentifier PropertySelector: '$.DBClusterSnapshots[0].Status' DesiredValues: - available - name: ExecuteCode action: 'aws:executeScript' inputs: Runtime: python3.7 Handler: script_handler InputPayload: snapshotid: '{{CreateSnapshot.SnapShotId}}' snapshotarn: '{{CreateSnapshot.DBClusterSnapshotArn}}' dbclusterid: '{{CreateSnapshot.DBClusterId}}' automationid: '{{automation:EXECUTION_ID}}' sourceregion: !Ref SourceRegion targetregion: !Ref TargetRegion kmstargetkey: !Ref KMSTargetKey Script: |- def script_handler(event, context): import boto3, json, os # Input parameters are provided by SSM document snapshotid = event.get("snapshotid") snapshotarn = event.get("snapshotarn") dbclusterid = event.get("dbclusterid") sourceregion = event.get("sourceregion") targetregion = event.get("targetregion") kmstargetkey = event.get("kmstargetkey") # Define Target region in the region_name.Following API # is expected to run in Target region. Hence, by setting region_name # to Target region, we achive that. client = boto3.client('rds', region_name=targetregion) response = client.copy_db_cluster_snapshot( SourceDBClusterSnapshotIdentifier=snapshotarn, TargetDBClusterSnapshotIdentifier=snapshotid, KmsKeyId=kmstargetkey, # KMS Key ID in Target region CopyTags=True, SourceRegion=sourceregion # This attribute will automatically generate presigned URL ) print(response) copystatus = response.get("DBClusterSnapshot").get("Status") print("Status of Copying of Snapshot:" + str(copystatus)) Outputs: AutomationDocument: Value: !Ref CrossRegionSnapshotCopySSMAutomation SSMAutomationRole: Value: !Ref CrossRegionSnapshotCopySSMAutomationRole