Minimal KMS permissions to copy a database snapshot
I found another root cause for this, and another solution:
Just create, then delete, a RDS in the target region!
AWS RDS simply refused to copy a snapshot, no matter what I did to key policies, UNTIL I created a small, automatic RDS. Now any key works "out-of-box", even new ones without any policy change!
Now, I figured it out by trial and error. Since I don't like to do the same task more than once, I automated it (see script below).
This are the required permissions for copying a RDS snapshot:
["kms:CreateGrant","kms:DescribeKey"]
This is the script I used. Maybe it is useful for other people which have a similar problem. It is hacked together, so don't expect it to work out of the box.
#!/bin/bash
set -euo pipefail
unknown=(
kms:CancelKeyDeletion
kms:CreateAlias
kms:CreateAlias
kms:CreateGrant
kms:CreateKey
kms:Decrypt
kms:DeleteAlias
kms:DeleteAlias
kms:DescribeKey
kms:DisableKey
kms:DisableKeyRotation
kms:EnableKey
kms:EnableKeyRotation
kms:Encrypt
kms:GenerateRandom
kms:GenerateDataKey
kms:GenerateDataKeyWithoutPlaintext
kms:GetKeyPolicy
kms:GetKeyRotationStatus
kms:ListAliases
kms:ListGrants
kms:ListKeyPolicies
kms:ListKeys
kms:ListRetirableGrants
kms:PutKeyPolicy
kms:ReEncryptFrom
kms:ReEncryptTo
kms:RetireGrant
kms:RevokeGrant
kms:ScheduleKeyDeletion
kms:UpdateAlias
kms:UpdateAlias
kms:UpdateKeyDescription
)
required=()
KEY_ID=86a6300d-38f9-4892-b7a1-d8f821e8438c
export AWS_DEFAULT_OUTPUT=json
function check_copy {
permissions=$( echo -n "${required[*]} ${unknown[*]}" | jq -R -s 'split(" ")' )
policy=$( aws kms \
get-key-policy \
--key-id ${KEY_ID} \
--policy-name default \
| jq ".Policy" -r \
| jq ".Statement[1].Action |= ${permissions}"
)
aws kms \
put-key-policy \
--key-id ${KEY_ID} \
--policy-name default \
--policy "${policy}"
aws rds \
delete-db-snapshot \
--db-snapshot-identifier rds-backup-share-mysql-reencrypted \
|| true
(
set -x
AWS_ACCESS_KEY_ID=XXX \
AWS_SECRET_ACCESS_KEY=XXX \
aws rds \
copy-db-snapshot \
--source-db-snapshot-identifier rds-backup-share-mysql \
--target-db-snapshot-identifier rds-backup-share-mysql-reencrypted \
--kms-key-id alias/rds-snapshot-share \
|| return 1
aws rds \
wait db-snapshot-completed \
--db-snapshot-identifier rds-backup-share-mysql-reencrypted
) || return 1
return 0
}
check_copy
while [ ${#unknown[@]} -gt 0 ]
do
removed=${unknown[0]}
unknown=(${unknown[@]:1})
if ! check_copy
then
required+=($removed)
fi
echo "Required permissions so far: ${required[*]}"
echo "Unknown permissions so far: ${unknown[*]}"
done
echo -n "Minimal permissions: "
echo -n "${required[*]}" | jq -R -s -c 'split(" ")'
I'm also doing a copy of an RDS database snapshot, but using Powershell and my database is MS SQL. I'm getting the same error:
The target snapshot KMS key [<kms-arn>] does not exist,
is not enabled or you do not have permissions to access it.
I ended up here with my searches, checking my profile, credentials, roles, etc... but all seems good.
My mistake was not specifying the region in the Copy-RDSDBSnapshot
(in Powershell; equivalent to copy-db-snapshot
in CLI). Since I'm copying across regions for a Disaster Recovery scenario, I must specify the KmsKeyId of the target Region (as it will defer from the source Region). The source region us-east-1 is my default region, so executing this didn't work, it failed with the error above, since i'm not specify anything, it runs in my default region us-east-1 and therefore it can't find the us-west-2 key, just as the error say, it "does not exist" in that region, it's nothing to do with permissions:
Copy-RDSDBSnapshot -SourceDBSnapshotIdentifier $dBSnapshotArn `
-SourceRegion 'us-east-1' `
-TargetDBSnapshotIdentifier $targetSnapshotName `
-KmsKeyId 'arn:aws:kms:us-west-2:xxxxx:key/xxxxx' `
-CopyTag $true -OptionGroupName 'myOptionGroup'
Adding the so called "Common Parameter" Region
did the trick:
Copy-RDSDBSnapshot -SourceDBSnapshotIdentifier $dBSnapshotArn `
-SourceRegion 'us-east-1' `
-TargetDBSnapshotIdentifier $targetSnapshotName `
-KmsKeyId 'arn:aws:kms:us-west-2:xxxxx:key/xxxxx' `
-CopyTag $true -OptionGroupName 'myOptionGroup' `
-Region 'us-west-2' # <-- new line