{ "Conditions": { "IncludeAurora": { "Fn::Equals": [ { "Ref": "IncludeAuroraClusters" }, "Yes" ] }, "UseAllDatabases": { "Fn::Equals": [ { "Fn::Join": [ "", { "Ref": "DatabasesToUse" } ] }, "" ] }, "UseEncryption": { "Fn::Equals": [ { "Ref": "KMSKeyParameter" }, "" ] } }, "Description": "Resources copying RDS backups to another region", "Metadata": { "AWS::CloudFormation::Interface": { "ParameterGroups": [ { "Label": { "default": "Basic configuration" }, "Parameters": [ "TargetRegionParameter", "S3BucketParameter", "SourceZipParameter" ] }, { "Label": { "default": "Encryption - see https://github.com/pbudzon/aws-maintenance#encryption for details" }, "Parameters": [ "KMSKeyParameter" ] }, { "Label": { "default": "Optional: limit to specific RDS database(s)" }, "Parameters": [ "DatabasesToUse" ] }, { "Label": { "default": "Optional: Aurora support" }, "Parameters": [ "IncludeAuroraClusters", "ClustersToUse" ] } ], "ParameterLabels": { "ClustersToUse": { "default": "Aurora clusters to use for" }, "DatabasesToUse": { "default": "Databases to use for" }, "IncludeAuroraClusters": { "default": "Use for Aurora clusters" }, "KMSKeyParameter": { "default": "KMS Key in target region" }, "S3BucketParameter": { "default": "Name of S3 bucket" }, "SourceZipParameter": { "default": "Name of ZIP file" }, "TargetRegionParameter": { "default": "Target region" } } } }, "Parameters": { "ClustersToUse": { "Default": "", "Description": "Optional: If including Aurora clusters - comma-delimited list of Aurora Clusters to use for. Leave empty to use for all clusters in source region.", "Type": "String" }, "DatabasesToUse": { "Description": "Optional: comma-delimited list of RDS instance (not Aurora clusters!) names to use. Leave empty to use for all instances in source region.", "Type": "CommaDelimitedList" }, "IncludeAuroraClusters": { "AllowedValues": [ "Yes", "No" ], "Default": "No", "Description": "Choose 'Yes' if you have Aurora Clusters that you want to use this for, will add daily schedule.", "Type": "String" }, "KMSKeyParameter": { "Description": "KMS Key ARN in target region. Required if using encrypted RDS instances, optional otherwise.", "Type": "String" }, "S3BucketParameter": { "Description": "Name of the S3 bucket where you uploaded the source code zip", "Type": "String" }, "SourceZipParameter": { "Default": "backup-rds.zip", "Description": "Name of the zip file inside the S3 bucket", "Type": "String" }, "TargetRegionParameter": { "AllowedPattern": "^[a-z]+-[a-z]+-[0-9]+$", "ConstraintDescription": "The target region needs to be valid AWS region, for example: us-east-1", "Description": "Region where to store the copies of snapshots (for example: eu-central-1)", "Type": "String" } }, "Resources": { "AuroraBackupEvent": { "Condition": "IncludeAurora", "Properties": { "Description": "Copy Aurora clusters to another region", "ScheduleExpression": "rate(1 day)", "State": "ENABLED", "Targets": [ { "Arn": { "Fn::GetAtt": [ "LambdaBackupRDSFunction", "Arn" ] }, "Id": "backup_rds_function" } ] }, "Type": "AWS::Events::Rule" }, "EventsPermissionForLambda": { "Condition": "IncludeAurora", "Properties": { "Action": "lambda:invokeFunction", "FunctionName": { "Ref": "LambdaBackupRDSFunction" }, "Principal": "events.amazonaws.com", "SourceArn": { "Fn::GetAtt": [ "AuroraBackupEvent", "Arn" ] } }, "Type": "AWS::Lambda::Permission" }, "LambdaBackupRDSFunction": { "Properties": { "Code": { "S3Bucket": { "Ref": "S3BucketParameter" }, "S3Key": { "Ref": "SourceZipParameter" } }, "Description": "Copies RDS backups to another region", "Environment": { "Variables": { "CLUSTERS_TO_USE": { "Ref": "ClustersToUse" }, "KMS_KEY_ID": { "Ref": "KMSKeyParameter" }, "SOURCE_REGION": { "Ref": "AWS::Region" }, "TARGET_REGION": { "Ref": "TargetRegionParameter" } } }, "Handler": "backup-rds.lambda_handler", "MemorySize": 128, "Role": { "Fn::GetAtt": [ "LambdaBackupRDSRole", "Arn" ] }, "Runtime": "python3.6", "Timeout": 30 }, "Type": "AWS::Lambda::Function" }, "LambdaBackupRDSRole": { "Properties": { "AssumeRolePolicyDocument": { "Statement": [ { "Action": [ "sts:AssumeRole" ], "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] } } ] }, "Policies": [ { "PolicyDocument": { "Statement": [ { "Action": [ "rds:DescribeDbSnapshots", "rds:CopyDbSnapshot", "rds:DeleteDbSnapshot", "rds:DeleteDbClusterSnapshot", "rds:DescribeDbClusters", "rds:DescribeDbClusterSnapshots", "rds:CopyDBClusterSnapshot" ], "Effect": "Allow", "Resource": [ "*" ] }, { "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow", "Resource": [ "arn:aws:logs:*:*:*" ] }, { "Fn::If": [ "UseEncryption", { "Ref": "AWS::NoValue" }, { "Action": [ "kms:Create*", "kms:DescribeKey" ], "Effect": "Allow", "Resource": [ { "Ref": "KMSKeyParameter" } ] } ] } ] }, "PolicyName": "AccessToRDSAndLogs" } ] }, "Type": "AWS::IAM::Role" }, "RDSBackupEvent": { "Properties": { "Enabled": "true", "EventCategories": [ "backup" ], "SnsTopicArn": { "Ref": "RDSBackupTopic" }, "SourceIds": { "Fn::If": [ "UseAllDatabases", { "Ref": "AWS::NoValue" }, { "Ref": "DatabasesToUse" } ] }, "SourceType": "db-instance" }, "Type": "AWS::RDS::EventSubscription" }, "RDSBackupTopic": { "Properties": { "Subscription": [ { "Endpoint": { "Fn::GetAtt": [ "LambdaBackupRDSFunction", "Arn" ] }, "Protocol": "lambda" } ] }, "Type": "AWS::SNS::Topic" }, "SNSPermissionForLambda": { "Properties": { "Action": "lambda:invokeFunction", "FunctionName": { "Ref": "LambdaBackupRDSFunction" }, "Principal": "sns.amazonaws.com", "SourceArn": { "Ref": "RDSBackupTopic" } }, "Type": "AWS::Lambda::Permission" } } }