仅需最小化的KMS权限即可复制数据库快照

36

我正在尝试为使用 KMS 加密密钥进行 aws rds copy-db-snapshot 设置最小权限:

$ 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 <kms-arn>

(所有在<>中的内容都被我删除了,其中还包含有效值。)

很不幸,我得到了这个错误:

An error occurred (KMSKeyNotAccessibleFault) when calling the CopyDBSnapshot operation: The target snapshot KMS key [<kms-arn>] does not exist, is not enabled or you do not have permissions to access it.

目前我允许执行以下操作:

  "Action": [
    "kms:ReEncrypt*",
    "kms:ListKeys",
    "kms:ListAliases",
    "kms:GenerateDataKey*",
    "kms:Encrypt",
    "kms:DescribeKey",
    "kms:Decrypt"
  ],

如果我用kms:*{code}替换它,它就可以工作,所以肯定是一个权限问题。

我尝试使用CloudTrail找出正确的权限,但它只包含相同无用的错误信息。

所以我的实际问题是:

  • CopyDBSnapshot需要哪些最小的KMS权限?
  • 是否有一种通用的方法来确定所需的权限?每次通过谷歌搜索所需的权限都很费时间。

编辑:这是启用了--debug选项的日志输出底部部分:

2017-08-22 17:15:37,521 - MainThread - botocore.endpoint - DEBUG - Sending http request: <PreparedRequest [POST]>
2017-08-22 17:15:37,522 - MainThread - botocore.vendored.requests.packages.urllib3.connectionpool - INFO - Starting new HTTPS connection (1): rds.eu-west-1.amazonaws.com
2017-08-22 17:15:37,927 - MainThread - botocore.vendored.requests.packages.urllib3.connectionpool - DEBUG - "POST / HTTP/1.1" 400 437
2017-08-22 17:15:37,934 - MainThread - botocore.parsers - DEBUG - Response headers: {'x-amzn-requestid': 'c097fe4e-874c-11e7-a56a-9d1acedaf516', 'content-type': 'text/xml', 'content-length': '437', 'date': 'Tue, 22 Aug 2017 15:15:37 GMT', 'connection': 'close'}
2017-08-22 17:15:37,936 - MainThread - botocore.parsers - DEBUG - Response body:
b'<ErrorResponse xmlns="http://rds.amazonaws.com/doc/2014-10-31/">\n  <Error>\n    <Type>Sender</Type>\n    <Code>KMSKeyNotAccessibleFault</Code>\n    <Message>The target snapshot KMS key [<kms-arn>] does not exist, is not enabled or you do not have permissions to access it. </Message>\n  </Error>\n  <RequestId>c097fe4e-874c-11e7-a56a-9d1acedaf516</RequestId>\n</ErrorResponse>\n'
2017-08-22 17:15:37,938 - MainThread - botocore.hooks - DEBUG - Event needs-retry.rds.CopyDBSnapshot: calling handler <botocore.retryhandler.RetryHandler object at 0x7f9c7ce84860>
2017-08-22 17:15:37,939 - MainThread - botocore.retryhandler - DEBUG - No retry needed.
2017-08-22 17:15:37,952 - MainThread - awscli.clidriver - DEBUG - Exception caught in main()
Traceback (most recent call last):
  File "/usr/lib/python3.6/site-packages/awscli/clidriver.py", line 200, in main
    return command_table[parsed_args.command](remaining, parsed_args)
  File "/usr/lib/python3.6/site-packages/awscli/clidriver.py", line 338, in __call__
    return command_table[parsed_args.operation](remaining, parsed_globals)
  File "/usr/lib/python3.6/site-packages/awscli/clidriver.py", line 508, in __call__
    call_parameters, parsed_globals)
  File "/usr/lib/python3.6/site-packages/awscli/clidriver.py", line 627, in invoke
    client, operation_name, parameters, parsed_globals)
  File "/usr/lib/python3.6/site-packages/awscli/clidriver.py", line 639, in _make_client_call
    **parameters)
  File "/usr/lib/python3.6/site-packages/botocore/client.py", line 310, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/usr/lib/python3.6/site-packages/botocore/client.py", line 599, in _make_api_call
    raise error_class(parsed_response, operation_name)
botocore.errorfactory.KMSKeyNotAccessibleFault: An error occurred (KMSKeyNotAccessibleFault) when calling the CopyDBSnapshot operation: The target snapshot KMS key [<kms-arn>] does not exist, is not enabled or you do not have permissions to access it. 
2017-08-22 17:15:37,955 - MainThread - awscli.clidriver - DEBUG - Exiting with rc 255

An error occurred (KMSKeyNotAccessibleFault) when calling the CopyDBSnapshot operation: The target snapshot KMS key [<kms-arn>] does not exist, is not enabled or you do not have permissions to access it.

备注:我在AWS论坛上进行了一次跨贴:https://forums.aws.amazon.com/thread.jspa?messageID=801745


你能在aws rds命令中添加--debug并发布吗? - Rodrigo Murillo
我添加了实际HTTP请求的调试输出。 - svenwltr
你尝试过使用托管策略作为指定自己策略的替代方案吗?请尝试将以下策略添加到角色中:参见 arn:aws:iam::aws:policy/AWSKeyManagementServicePowerUser - Rodrigo Murillo
是的,试错是解决这个问题的一种方法。我希望有人已经知道答案或者能够给我提示如何更好地调试。也许AWS有一个很棒的隐藏文档(哈哈),我还没有找到它。这不是第一次出现这种问题了。不幸的是,看起来我又得自己解决这个问题了。 - svenwltr
我知道每次都是一样的套路。;-) 我目前的想法是首先寻找一个托管策略,然后从那里开始处理。但似乎没有关于基于操作的权限的权威参考。我也对这个特定案例很感兴趣。如果你找到解决方案,请发帖,我也会这样做。 - Rodrigo Murillo
显示剩余3条评论
6个回答

66

现在,我通过试错找到了答案。由于我不喜欢重复相同的任务,所以我自动化了它(请参见下面的脚本)。

这是复制RDS快照所需的权限:

["kms:CreateGrant","kms:DescribeKey"]
这是我使用的脚本,也许对其他遇到类似问题的人有用。它被拼凑在一起,所以不要指望可以直接运行。

这是我使用的脚本,也许对其他遇到类似问题的人有用。它被拼凑在一起,所以不要指望可以直接运行。

#!/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(" ")'

5
值得注意的是,您需要为源KMS密钥和目标KMS密钥都使用这些。 - sihil

9
我找到了另一个导致这个问题的根本原因和解决方案:
只需在目标地区创建然后删除一个RDS即可!
AWS RDS拒绝复制快照,不管我如何更改密钥策略,直到我创建了一个小型的自动RDS。现在任何密钥都可以“开箱即用”,甚至没有进行任何策略更改的新密钥!

2
我也碰到了这个 bug,浪费了 3 个小时。谢谢你的提示! - Ka.
4
值得注意的是,RDS仅适用于对称密钥。非对称密钥将无法使用,但您将不会收到明确的错误信息。 - Ka.
@Ka。这对我来说是个解决方法,谢谢!AWS的错误信息非常模糊。 - AWS Cloud Architect Rob

3

除了其他答案提到的权限外,一定要使用对称加密密钥。 AWS的错误信息并不清楚其含义,并且当您尝试使用非对称密钥执行应该使用对称密钥的操作时,会出现同样的错误信息。


2
如果这是一次性事件(可能是从另一个账户复制/克隆RDS),并且您愿意使用AWS控制台,则可以按照以下步骤操作:
  1. 进入快照所在的账户(源)并进入KMS,创建一个自定义的KMS(重要的是要添加目标账户/目的地账户)用于此KMS enter image description here
  2. 进入RDS控制台,快照-->选择快照-->点击操作(右上角)-->复制快照(确保使用您创建的新KMS密钥而不是默认密钥)
  3. 一旦新的快照可用,进入快照-->选择新创建的快照-->操作-->共享快照-->添加目标/目的地账户
  4. 进入目标账户,点击-->与我共享 enter image description here
  5. 进入操作(仍在目标/目的地账户上),点击-->创建复制快照
  6. 完成后,进入操作并恢复快照

完全感谢 AWS 文档 https://aws.amazon.com/premiumsupport/knowledge-center/share-encrypted-rds-snapshot-kms-key/


2

我也在使用Powershell复制一个RDS数据库快照,但我的数据库是MS SQL。我遇到了同样的错误:

The target snapshot KMS key [<kms-arn>] does not exist, 
is not enabled or you do not have permissions to access it.

我的搜索结果带我来到这里,检查我的个人资料、证书、角色等,一切看起来都很好。

我的错误在于没有在 Copy-RDSDBSnapshot 中指定区域(使用Powershell时;相当于CLI中的 copy-db-snapshot)。由于我正在为灾难恢复方案跨区域复制,因此我必须指定目标区域的 KmsKeyId(因为它与源区域不同)。源区域 us-east-1 是我的默认区域,所以执行此操作时失败了,因为我没有指定任何内容,它在我的默认区域 us-east-1 中运行,因此它找不到 us-west-2 密钥,就像错误所说的那样,在该区域中“不存在”,这与权限无关:

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就解决了问题:

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

在您的情况下,需要为CLI调用要求Region是预期的,因为1)您的配置文件中默认区域可能不是us-west-2 2)您在KmsKeyId的值中引用了us-west-2,而命令的上下文似乎是“从源复制快照”。为了保持一致性,我以相同的方式复制EC2 EBS快照(在我的情况下,通过boto3客户端针对目标区域)。 - mxmader

0
我试图使用boto3将数据库集群快照(主要是Aurora集群)从一个区域复制到另一个区域,但我查看了所有答案,但我仍然遇到了与问题中提到的相同的错误。在boto3的copy_db_cluster_snapshot API的参数中,我们无法指定快照的目标区域。
因此,我写下这篇文章,以便任何遇到使用copy_db_cluster_snapshot方法将其复制到另一个区域的问题的人可以按照这个指南进行操作。
我有一个Lambda函数,代码如下: 快照的目标区域 = us-west-2 快照的源区域 = us-east-1
以下几点很重要: 1. boto3.client应该指定目标区域,这样当您在云跟踪中检查时,请求会发送到目标区域。 2. kms-key-id应该是目标区域中的kms的kms-key-id。 3. SourceDBClusterSnapshotIdentifier - 它应该是要复制的快照的完整快照arn。
    def copy_to_other_region_lambda_handler(event, context):
        client = boto3.client('rds','us-west-2')
        response = client.copy_db_cluster_snapshot(
            SourceDBClusterSnapshotIdentifier='arn:aws:rds:us-east-1:account-id:cluster-snapshot:source',
            TargetDBClusterSnapshotIdentifier='target-snapshot',
            CopyTags=True,
            SourceRegion='us-east-1',
            KmsKeyId='arn:aws:kms:us-west-2:account-id:key/key-id'
        )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接