DEV Community

How to Re-Encrypt Aurora Snapshots with a CMK for Cross-Account Migration

When we rebuilt our AWS Organizations account structure, we needed to migrate the Aurora data from the old account to the new one as-is.

However, the Aurora cluster in the old account was encrypted using the AWS-managed key (aws/rds). After some investigation, we learned that aws/rds cannot be shared across accounts, meaning we couldn’t simply copy the snapshot to the new account...

To address this, we created customer-managed keys (CMKs) in both the old and new accounts, re-encrypted the snapshot using the CMK in the old account, and then copied/restored it to the new account.

We ran into several subtle issues with KMS key policies, so here is a complete step-by-step record for future reference.

Overall Flow

Step Account Description
1 Old Create CMK for snapshot encryption
2 Old Create Aurora snapshot
3 Old Copy snapshot with re-encryption using old CMK
4 Old Share CMK-encrypted snapshot with new account
5 New Create CMK for re-encryption in new account
6 New Re-encrypt copied snapshot with new CMK
7 New Restore Aurora from CMK-encrypted snapshot

Architecture

Steps

1. Create a CMK for snapshot encryption in the old account

Create a CMK in the same region as the Aurora cluster.
Here is the key policy required for cross-account snapshot sharing.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AllowOldAccountAdmin",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<OLD_ACCOUNT_ID>:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "AllowUseFromOldAccountViaRDS",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<OLD_ACCOUNT_ID>:root"
      },
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:ReEncryptFrom",
        "kms:ReEncryptTo",
        "kms:GenerateDataKey*",
        "kms:DescribeKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "rds.<REGION>.amazonaws.com"
        }
      }
    },
    {
      "Sid": "AllowUseFromNewAccountViaRDS",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<NEW_ACCOUNT_ID>:root"
      },
      "Action": [
        "kms:Decrypt",
        "kms:ReEncryptFrom",
        "kms:DescribeKey",
        "kms:CreateGrant"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "rds.<REGION>.amazonaws.com"
        }
      }
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Note 1: Why ReEncryptFrom / ReEncryptTo are required

To share Aurora snapshots across accounts, encryption must transition through multiple layers.

aws/rds → old CMK → new CMK

ReEncryptFrom is needed to decrypt the existing key, and is used during.

  • AllowUseFromOldAccountViaRDS → decrypting snapshot encrypted with aws/rds
  • AllowUseFromNewAccountViaRDS → decrypting snapshot encrypted with old CMK

ReEncryptTo is needed to encrypt data with the new key.

  • Used during Step 3 to re-encrypt with old CMK

Note 2: Creating a CMK via the AWS Console

Refer to the following screenshots.

2. Create an Aurora snapshot

From console or CLI.

aws rds create-db-cluster-snapshot \
  --db-cluster-snapshot-identifier <snapshot> \
  --db-cluster-identifier <cluster>
Enter fullscreen mode Exit fullscreen mode

3. Copy and re-encrypt snapshot using the old account’s CMK

aws rds copy-db-cluster-snapshot \
  --source-db-cluster-snapshot-identifier arn:aws:rds:REGION:OLD_ACCOUNT:cluster-snapshot:my-snap \
  --target-db-cluster-snapshot-identifier my-snap-cmk \
  --kms-key-id arn:aws:kms:REGION:OLD_ACCOUNT:key/<CMK-old>
Enter fullscreen mode Exit fullscreen mode

4. Share the CMK-encrypted snapshot with the new account

aws rds modify-db-cluster-snapshot-attribute \
  --db-cluster-snapshot-identifier my-snap-cmk \
  --attribute-name restore \
  --values-to-add NEW_ACCOUNT_ID
Enter fullscreen mode Exit fullscreen mode

Once shared successfully, the new account should see the snapshot.

5. Create a new CMK in the new account

This CMK will be used to re-encrypt the snapshot again.
To re-encrypt the snapshot using the new CMK, you need to grant the ReEncryptTo permission in the key policy.

Key policy example.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Enable IAM User Permissions",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<NEW_ACCOUNT_ID>:root"
      },
      "Action": "kms:*",
      "Resource": "*"
    },
    {
      "Sid": "Allow rds.amazonaws.com to use the key",
      "Effect": "Allow",
      "Principal": {
        "Service": "rds.amazonaws.com"
      },
      "Action": [
        "kms:ReEncryptTo",
        "kms:GenerateDataKey*",
        "kms:Encrypt",
        "kms:DescribeKey",
        "kms:Decrypt",
        "kms:CreateGrant"
      ],
      "Resource": "*"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

6. Copy and re-encrypt the shared snapshot using the new CMK

You then copy the snapshot again using the new CMK.
Internally, the encrypted data is extracted using the old CMK’s ReEncryptFrom permission, and then re-encrypted using the new CMK’s ReEncryptTo permission.

aws rds copy-db-cluster-snapshot \
  --source-db-cluster-snapshot-identifier arn:aws:rds:REGION:OLD_ACCOUNT:cluster-snapshot:my-snap-cmk \
  --target-db-cluster-snapshot-identifier my-snap-new \
  --kms-key-id arn:aws:kms:REGION:NEW_ACCOUNT:key/<CMK-new>
Enter fullscreen mode Exit fullscreen mode

7. Restore Aurora from the re-encrypted snapshot in the new account

After that, restore the Aurora cluster from the snapshot you created.

If you are restoring it using Terraform, the configuration will look like this.

resource "aws_rds_cluster" "example" {
  cluster_identifier  = "example-cluster"
  snapshot_identifier = "arn:aws:rds:REGION:NEW_ACCOUNT:cluster-snapshot:my-snap-new"
  kms_key_id          = aws_kms_key.db.arn
  engine              = "aurora-mysql"
}

resource "aws_rds_cluster_instance" "example_instances" {
  count              = 2
  identifier         = "example-cluster-${count.index}"
  cluster_identifier = aws_rds_cluster.example.id
  instance_class     = "db.r8g.large"
  engine             = aws_rds_cluster.example.engine
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

If you foresee migrating from a single-account setup to a multi-account structure, it’s much easier to use a CMK from the beginning. While it does cost more, it can save a huge amount of migration and operational effort later — making it well worth the investment.

Top comments (0)