Skip to content

Need help giving Lambda execution role access to decript and use KMS key for coping snaps between regions

0

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.

  1. 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": [
                "*"
            ]
        }
    ]
}
  1. 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)}")

  1. 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"
        }
      }
    }
  ]
}
  1. 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

1 Answer
1
Accepted Answer

Hello.

The Lambda IAM role only allows access to "arn:aws:kms:us-west-2:910286192445:key/mrk-6dae29119b094afaa3b9ed67c781ab3c", but I think you also need to configure access to the KMS key in "us-west-1".
In other words, you will need to configure access to the KMS key used to encrypt the source RDS snapshot in "us-west-1".
Please make sure that you configure the Lambda IAM role to have access to the KMS key used to encrypt the source RDS snapshot in "us-west-1" and that the KMS key policy allows it.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "iam:PassRole",
            "Resource": "arn:aws:iam::910286192445:role/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt",
                "kms:Encrypt",
                "kms:GenerateDataKey",
                "kms:DescribeKey",
                "kms:CreateGrant",
                "kms:RetireGrant"
            ],
            "Resource": [
                "arn:aws:kms:us-west-2:910286192445:key/mrk-6dae29119b094afaa3b9ed67c781ab3c",
                "arn:aws:kms:us-west-1:910286192445:key/us-west-1-rds-encrypt-key"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "kms:CreateGrant",
                "kms:ListGrants",
                "kms:RevokeGrant"
            ],
            "Resource": [
                "arn:aws:kms:us-west-2:910286192445:key/mrk-6dae29119b094afaa3b9ed67c781ab3c",
                "arn:aws:kms:us-west-1:910286192445: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": [
                "*"
            ]
        }
    ]
}
EXPERT

answered a year ago

  • 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.

                "Resource": [
                    "arn:aws:kms:us-west-2:910286192445:key/mrk-6dae29119b094afaa3b9ed67c781ab3c",
                    "arn:aws:kms:us-west-1:910286192445:key/mrk-6dae29119b094afaa3b9ed67c781ab3c"
                ]
    
  • 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

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.