GeekTopia


Never Stop Learning

Automating The Cross Region Copy Of RDS Snapshots

If you would like to see the TLDR; version of this article please click TLDR;


Video Instruction

Yoube Video Instructions


AWS RDS automated snapshots are an easy “set it and forget it” method for managing your database backups. Often it is perfectly acceptable to allow the AWS RDS team to manage all of your backups. In fact, it is perfectly acceptable for a small blog like mine What happens when this does not meet your business continuance or disaster recovery needs. Sure your data is stored in multiple availability zones for a given area, but when you need to move your RDS backups to the other side of the country, where do you start?

The Architecture

I have seen many different methods deployed as a work around this issue. Most of these methods include running a lambda script every few hours that builds a list of all of the snapshots in a given region and checks it against a list of snapshots that have been copied to the target region. The script will then copy the difference. I think I have a better way that does not need to rely on a predetermined time for a script to run, but instead will copy the snapshot as soon as it has been created.

When a snapshot of an RDS instance has started or is completed, and event is issued to Cloud Watch Events. Cloud Watch events can in turn check our rule set, and if a given event matches our rule set, it can perform an action on our behalf. On of those actions is my favorite.. Lambda.

Application Work Flow
Automated Snapshot Copy Workflow

The Implementation


Step 1: Iam Permissions

Step 1 begins with creating an IAM role that lambda will assume to execute. This role needs permissions to copy an RDS snapshot to the destination region. If you already have a role with these permissions used to invoke lambda functions, skip to step 2.

In the IAM portion of the AWS Web console, start creating a new policy. This policy only needs permissions to copyDBSnapshots. You can restrict this to a single RDS instance, or choose all instances depending on your needs.

Create IAM Policy

Next we will create a new role. From the left hand menu select Roles, then click Create Role

On the next menu, choose the service that can assume this role. In this case we will choose Lambda as lambda will assume this role to copy the snapshots. Clicking Next will reveal a menu to select a policy to attach to this role. We will need two policies. The first is the policy created in the previous step, the second is “AWSLambdaBasicExecutionRole”. This policy will allow our new role to write the logs generated by lambda in to CloudWatch.

Continue the wizard to tag and name the role according to your naming and tagging standards

Step 2: Creating the Lambda Function

Let’s create a new lambda function using the Lambda portion of the AWS Web Console. Provide a good name, Python 3.7 and choose the existing role we just created in the previous step.

Create Lambda Function
Create Lambda Function

Using the inline editor, paste the following code into the lambda function.


# Written By GeekTopia
#
# Copy RDS Automated snapshots to a new region upon creation
# --Free to use under all conditions
# --Script is provied as is. No Warranty, Express or Implied

import json
import boto3

destinationRegion = "us-east-1"

def lambda_handler(event, context):
    
    sourceRegion = event['region']
    
    rds = boto3.client('rds',region_name=destinationRegion)
  
    #Build the Snapshot ARN - Always use the ARN when copying snapshots across region. 
    sourceSnapshotARN = event['detail']['SourceArn']
    sourceSnapshotARN= sourceSnapshotARN.replace(":db:",":snapshot:")
    
    #build a new snapshot name
    sourceSnapshotIdentifer = event['detail']['SourceIdentifier']
    targetSnapshotIdentifer ="{0}-ManualCopy".format(sourceSnapshotIdentifer)
    targetSnapshotIdentifer = targetSnapshotIdentifer.replace(":","-")

    #Execute copy
    try:
        copy = rds.copy_db_snapshot(SourceDBSnapshotIdentifier=sourceSnapshotARN,TargetDBSnapshotIdentifier=targetSnapshotIdentifer,SourceRegion=sourceRegion)
        print("Started Copy of Snapshot {0} in {2} to {1} in {3} ".format(sourceSnapshotIdentifer,targetSnapshotIdentifer,sourceRegion,destinationRegion))
    
    except ClientError as ex:
        if ex.response['Error']['Code'] == 'DBSnapshotAlreadyExists':
            print("Snapshot  {0} already exist".format(targetSnapshotIdentifer))
        else:
            print("ERROR: {0}".format(ex.response['Error']['Code']))

    return {
        'statusCode': 200,
        'body': json.dumps('Opearation Complete')
    }   
                                            

Review line 10 of the function code


destinationRegion = "us-east-1"                        
                    

Set this to the region of your choice. Optionally, if you are comfortable with lambda configuration and python code, you modify this code to move this variable to the global variable space and configure the Key and Value pair of your choosing. If you are not sure, just set the region inside the quotes and make no further changes.

In the top right hand corner, click the save button to save the Lambda function.

Save Button
Save Button

Do not test this function as it will fail when executed from the web console. This lambda function will be invoked from CloudWach with a specific event document. Since our web console does not contain an event document to match the one that will be issued from cloudwatch, this script will fail while trying to get the region from the event document.

Step 3: Build The Cloud Watch Rule To Invoke Lambda

In this step, we are going to build a Cloud Watch Rule with a very specific filter. This filter will ensure that our lambda function is only invoked when the RDS backup has been created.

For the final steps Navigate to the CloudWatch tab in the AWS Console. On the left hand menu select “Rules” then Click “Create Rule”.

CloudWatch Rule Creation

This menu has many options, but I have done the work for you so there is no need to fill out any of the options. Simply click the “Edit” Link above the “Event Pattern Preview” Box. Replace any text in the box with the following filter. Then Click Save.


{
    "source": [
        "aws.rds"
    ],
    "detail-type": ["RDS DB Snapshot Event"],
    "detail": {
       "Message":["Automated snapshot created"]
     }
}
                    

On the right hand menu, select “Add Target” and select the lambda function created in step 2 and click “Configure Details”.

Name the Cloud Watch Rule, pand provide a description per your naming conventions. Click “Create Rule” and you are done!

Now when CloudWatch receives an event that backup creation has complete, it will invoke the lambda function and your snapshot will be copied to the new region. It is that simple!

References Used