Hi re:Post,
This question is a continuation of post:
""Lambda-Function-RDS-Snapshot-Management" was working now python errors after minor change".
We understand why it errors (thank you!) but we just need some help in putting in the correct json code for the policy that Lambda uses to copy between regions via the KMS key.
Essentially Lambda does not have access to the KMS key used to encrypt the snapshot in the "us-west-1" region before copying over to the "us-west-2" region, I think.
SOURCE_REGION = "us-west-1" # N. California (system)
TARGET_REGION = "us-west-2" # Oregon (system)
We need to verify that our Lambda execution role (RL-Lambda-RDS-Snapshot-Management) has permissions to use the KMS key in the us-west-2 or maybe the us-west-1 region?
And I need to add the appropriate KMS permissions to my role's policy.
I'm not sure how to do that.
Below I've included the
First: role's policy JSON. Second: the lambda python code. Third: KMS JSON. Fourth:The error message.
My apologies if I've violated posting rules and guidance by including sensitive information.
- Role's Policy JSON: "RDS_Policy_Lamda_Manage_Snapshots" (note the misspell in "lamda", sorry!) Updated policy code, 20250911 12:15 eastern.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::<accountid>:role/*"
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt",
"kms:Encrypt",
"kms:GenerateDataKey",
"kms:DescribeKey",
"kms:CreateGrant",
"kms:RetireGrant"
],
"Resource": [
"arn:aws:kms:us-west-2:<accountid>:key/<keyID>",
"arn:aws:kms:us-west-1:<accountid>:key/us-west-1-rds-encrypt-key"
]
},
{
"Effect": "Allow",
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": [
"arn:aws:kms:us-west-2:<accountid>:key/<keyID>",
"arn:aws:kms:us-west-1:<accountid>:key/us-west-1-rds-encrypt-key"
],
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": true
}
}
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"rds:DescribeDBSnapshots",
"rds:CopyDBSnapshot",
"rds:DeleteDBSnapshot",
"rds:CrossRegionCommunication",
"lambda:ListFunctions",
"lambda:CreateFunction",
"access-analyzer:ListPolicyGenerations"
],
"Resource": [
"*"
]
}
]
}
- the lambda python code. "lambda_function.py" .Note the lambda is located in us-west-1, N. California, updated code below 20250911, 12pm est
import boto3
import os
from datetime import datetime
# Define regions
# SOURCE_REGION = "us-west-2" # Oregon
SOURCE_REGION = "us-west-1" # N. California
DEST_REGION = "us-west-2" # Oregon
NUM_SNAPSHOTS = 1 # Number of snapshots to process
def lambda_handler(event, context):
# Create RDS clients for both regions
source_rds = boto3.client('rds', region_name=SOURCE_REGION)
dest_rds = boto3.client('rds', region_name=DEST_REGION)
# Step 1: Delete oldest manual snapshots in destination region
delete_oldest_snapshots(dest_rds, NUM_SNAPSHOTS)
# Step 2: Copy latest system snapshots from source to destination
copy_latest_snapshots(source_rds, dest_rds, NUM_SNAPSHOTS)
return {
'statusCode': 200,
'body': f'Successfully processed {NUM_SNAPSHOTS} snapshots'
}
def delete_oldest_snapshots(dest_rds, count):
db_names = [
"db-urovant", "db-atlas"
]
# Get all manual snapshots in destination region
for db_name in db_names:
response = dest_rds.describe_db_snapshots(
DBInstanceIdentifier=db_name,
SnapshotType='manual'
)
# Sort snapshots by creation time (oldest first)
snapshots = sorted(response['DBSnapshots'], key=lambda s: s['SnapshotCreateTime'])
# Delete the oldest 'count' snapshots
for i, snapshot in enumerate(snapshots):
if i >= count:
break
snapshot_id = snapshot['DBSnapshotIdentifier']
print(f"Deleting snapshot: {snapshot_id}")
try:
dest_rds.delete_db_snapshot(DBSnapshotIdentifier=snapshot_id)
print(f"Successfully deleted snapshot: {snapshot_id}")
except Exception as e:
print(f"Error deleting snapshot {snapshot_id}: {str(e)}")
def copy_latest_snapshots(source_rds, dest_rds, count):
# Define the database names based on your example
# "amgen", "alpine"
db_names = [
"db-urovant", "db-atlas"
]
for db_name in db_names:
# Get all automated snapshots in source region
response = source_rds.describe_db_snapshots(
DBInstanceIdentifier=db_name,
SnapshotType='automated'
)
# Sort snapshots by creation time (newest first)
snapshots = sorted(response['DBSnapshots'],
key=lambda s: s['SnapshotCreateTime'],
reverse=True
)
# Get today's date for naming
today = datetime.now().strftime("%Y-%m-%d")
# Copy the newest 'count' snapshots
for i, snapshot in enumerate(snapshots[:count]):
if i >= count:
break
source_snapshot_id = snapshot['DBSnapshotIdentifier']
# Create target snapshot name
target_snapshot_id = f"copy-rds-{db_name}-{today}"
print(f"Copying snapshot {source_snapshot_id} to {target_snapshot_id}")
try:
# Create ARN for source snapshot
source_arn = snapshot['DBSnapshotArn']
# Copy the snapshot
dest_rds.copy_db_snapshot(
SourceDBSnapshotIdentifier=source_arn,
TargetDBSnapshotIdentifier=target_snapshot_id,
KmsKeyId="arn:aws:kms:us-west-2:<accountid>:key/<keyID>",
SourceRegion=SOURCE_REGION
)
print(f"Successfully initiated copy of {source_snapshot_id} to {target_snapshot_id}")
except Exception as e:
print(f"Error copying snapshot {source_snapshot_id}: {str(e)}")
- KMS JSON (alias "rds-cross-region-replication" )
{
"Version": "2012-10-17",
"Id": "key-consolepolicy-3",
"Statement": [
{
"Sid": "Enable IAM User Permissions",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<accountid>:root"
},
"Action": "kms:*",
"Resource": "*"
},
{
"Sid": "Allow access for Key Administrators",
"Effect": "Allow",
"Principal": {
"AWS": [
"arn:aws:iam::<accountid>:user/<userfirst.userlast>",
"userid",
"arn:aws:iam::<accountid>:user/<userfirst.userlast>"
]
},
"Action": [
"kms:Create*",
"kms:Describe*",
"kms:Enable*",
"kms:List*",
"kms:Put*",
"kms:Update*",
"kms:Revoke*",
"kms:Disable*",
"kms:Get*",
"kms:Delete*",
"kms:TagResource",
"kms:UntagResource",
"kms:ScheduleKeyDeletion",
"kms:CancelKeyDeletion",
"kms:ReplicateKey",
"kms:UpdatePrimaryRegion"
],
"Resource": "*"
},
{
"Sid": "Allow use of the key",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<accountid>:user/<userfirst.userlast>"
},
"Action": [
"kms:Encrypt",
"kms:Decrypt",
"kms:ReEncrypt*",
"kms:GenerateDataKey*",
"kms:DescribeKey"
],
"Resource": "*"
},
{
"Sid": "Allow attachment of persistent resources",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<accountid>:user/<userfirst.userlast>"
},
"Action": [
"kms:CreateGrant",
"kms:ListGrants",
"kms:RevokeGrant"
],
"Resource": "*",
"Condition": {
"Bool": {
"kms:GrantIsForAWSResource": "true"
}
}
}
]
}
- Finally, here is the error message:
An error occurred (KMSKeyNotAccessibleFault) when calling the CopyDBSnapshot operation: The source snapshot KMS key does not exist, is not enabled or you do not have permissions to access it
Again, thank you for your time and help!
Best Regards,
Donald
I think the piece I'm missing now is, "and that the KMS key policy allows it". So what would I need to add to the KMS (alias "rds-cross-region-replication") ?
Below is runtime error text:
START RequestId: 8b12aec7-4fec-478a-86b8-c7f2c70163ee Version: $LATEST Deleting snapshot: copy-rds-db-urovant-2025-08-30 Successfully deleted snapshot: copy-rds-db-urovant-2025-08-30 Deleting snapshot: copy-rds-db-atlas-2025-08-31 Successfully deleted snapshot: copy-rds-db-atlas-2025-08-31 Copying snapshot rds:db-urovant-2025-09-11-05-13-us-east-2 to copy-rds-db-urovant-2025-09-11 Error copying snapshot rds:db-urovant-2025-09-11-05-13-us-east-2: An error occurred (KMSKeyNotAccessibleFault) when calling the CopyDBSnapshot operation: The source snapshot KMS key does not exist, is not enabled or you do not have permissions to access it Copying snapshot rds:db-atlas-2025-09-11-05-10-us-east-2 to copy-rds-db-atlas-2025-09-11 Error copying snapshot rds:db-atlas-2025-09-11-05-10-us-east-2: An error occurred (KMSKeyNotAccessibleFault) when calling the CopyDBSnapshot operation: The source snapshot KMS key does not exist, is not enabled or you do not have permissions to access it END RequestId: 8b12aec7-4fec-478a-86b8-c7f2c70163ee REPORT RequestId: 8b12aec7-4fec-478a-86b8-c7f2c70163ee Duration: 7347.45 ms Billed Duration: 7658 ms Memory Size: 128 MB Max Memory Used: 91 MB Init Duration: 309.68 ms Request ID: 8b12aec7-4fec-478a-86b8-c7f2c70163ee
Are you using "rds-cross-region-replication" to encrypt the source snapshot? You should be able to check the ID of the KMS key used for encryption from the RDS snapshot screen in "us-west-1".
Is it correct that the KMS key used to encrypt the source snapshot is "mrk-6dae29119b094afaa3b9ed67c781ab3c"? Normally, when copying a snapshot across regions, it is decrypted before copying and then encrypted with the destination KMS key when copying. This is because KMS keys are region-specific resources. If "mrk-6dae29119b094afaa3b9ed67c781ab3c" is used to encrypt the source snapshot, there is an error in the ARN set in the Lambda IAM policy. If "mrk-6dae29119b094afaa3b9ed67c781ab3c" is a cross-region replication key, you will need to change the region code in the ARN to your respective region code. Therefore, please try changing the ARN of the KMS key specified in the resource section of the Lambda IAM policy as follows.
The resource edit did the trick. It works like a charm now! Thank you again Riku, you've been more than helpful and patient with this ongoing saga of mine ;). Best Regards, Donald
Good Morning Riku! Thank you for you advice and help! Okay so I will add the 2nd resource call in both places in my policies' JSON
], "Resource": [ "arn:aws:kms:us-west-2:<accountid>:key/<keyID>", "arn:aws:kms:us-west-1:<accountid>:key/us-west-1-rds-encrypt-key" ],
Such that it mimics what you've outlined in your reply. I'll let you know how it goes ! Thanks, Donald