首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >AWS:跨账户资源访问和资源参考

AWS:跨账户资源访问和资源参考
EN

Stack Overflow用户
提问于 2021-11-04 19:44:24
回答 1查看 3K关注 0票数 3

我在Secrets Manager中有一个秘密的密钥-值对,在us-east-1中是1。这个秘密是使用客户管理的KMS密钥加密的-让我们称之为KMS-Account-1。所有这些都是通过控制台创建的。

现在我们转到CDK。我们有cdk.pipelines.CodePipeline,它将Lambda部署到多个阶段/环境--所以首先部署到{ Account-2, us-east-1 },然后部署到{ Account-3, eu-west-1 }等等。这已经完成了。

上面所有阶段/环境中的lambda代码,现在需要更改为使用Account-1的us-east-1 SecretsManager中的秘密键值对,方法是通过secretsmanager客户端获取它。该代码可能应该如下所示(python):

代码语言:javascript
复制
client = boto3.session.Session().client(
    service_name = 'secretsmanager',
    region_name = 'us-east-1'
)
resp = client.get_secret_value(
    SecretId='arn:aws:secretsmanager:us-east-1:<ACCOUNT-1>:secret:name/of/the/secret'
)
secret = json.loads(resp['SecretString'])

在不同的帐户和地区(即。(环境)将具有与上面完全相同的代码,因为需要从us-east-1中的Account-1获取这个秘密。

  1. 首先,我希望这在概念上是可能的。是那么回事吗?
  2. 接下来,如何更改cdk代码以方便这一点?代码管道中的代码部署如何获得导入这个自定义kms键和SecretManager' secret的权限,并为cdk管道创建的lambdas跨帐户访问应用正确的权限?

有人能给我指点吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-11-08 16:40:35

这有点棘手,因为CloudFormation和CDK不允许跨帐户/跨阶段引用,因为据我理解,CloudFormation导出不能跨帐户工作。所有这些“集中”资源模式都属于这一类--即。由其他阶段引用的一个帐户(或CDK中的一个阶段)中的资源。

如果资源是在CDK上下文之外创建的(比如通过控制台),那么您也可以在CDK代码中对名称/arns/等进行硬编码,这样就足够了。

  1. 对于有能力保存基于资源的策略的资源,它更简单,因为您可以直接将跨帐户访问权限附加到它们,再一次通过控制台脱机,因为您无论如何都在手动维护它。每次在管道中添加一个阶段(帐户)时,您将需要转到资源并手动添加跨帐户权限。
  2. 对于没有基于资源的策略的资源,比如SSM (例如,SSM),事情有点迂回,因为您需要创建一个角色,这个角色可以被假定为跨帐户,然后访问该资源。在这种情况下,您还必须单独维护IAM角色,并在向CDK管道添加阶段时手动将信任策略更新到其他帐户。然后,像往常一样硬编码CDK代码中的角色arn,在一些CustomResource lambda中假设它并使用它。

如果创建也是在CDK代码本身(即。由CloudFormation管理--不是通过控制台/aws单独完成的)。在这种情况下,很多时候您不会“知道”确切的ARN,因为物理id将由CloudFormation生成,并且很可能是ARN的一部分。即使是自己影响物理id(比如硬编码桶名),也不可能在所有情况下都解决它。例如:KMS ARNsSecretManager ARNsARN的末尾附加唯一的ids或某种散列。

与其尝试解决所有这些问题,最好还是保持不变,让CFn生成它选择的任意名称/arn。要引用这些构造/ARN,只需将它们放入源/中心帐户中的SSM参数中即可。据我所知,SSM没有基于资源的策略。因此,另外在cdk中创建一个角色来信任cdk代码中的帐户。一旦完成,就没有更多的维护--每次向CDK添加新的环境/帐户时(假设这里是一个cdk管道),您将创建的“循环”构造将自动将新帐户添加到信任关系中。

现在,您需要做的就是将这个角色-arn和SSM参数名称分发到其他阶段。选择一个显式角色名称和SSM参数。给定滚动名的手动ARN构造非常简单。因此,将CDK代码周围的这个和SSM参数分发到其他阶段(编译时间字符串而不是引用)。在目标阶段,创建自定义资源(AWSCustomResource),由AwsSdkCall lambda支持,以简单地承担此角色-arn并调用AwsSdkCall检索SSM参数值。这些值可以是任何东西,比如您的KMS ARN、秘书经理的完整ARN等等,您很难猜到。现在只需使用这些。

迂回的方式做一件简单的事情,但到目前为止,这是我所能做的一切,使这个工作。

代码语言:javascript
复制
#You need to maintain this list no matter what you do - so it's nothing extra
all_other_accounts = [ <list of accounts that this cdk deploys to> ]

account_principals = [iam.AccountPrincipal(a) for a in all_other_account]
role = iam.Role(
   assumed_by = iam.CompositePrincipal(*account_principals), #auto-updated as you change the list above
   role_name = some_explicit_name,
   ...
)
role_arn = f'arn:aws:iam::<account-of-this-stack>:role/{some_explicit_name}'

kms0 = kms.Key(...)
kms0.grant_decrypt(role)
# Because KMS also needs explicit resource policy even if role policy allows access to it
kms0.add_to_role_policy(iam.PolicyStatement(principals = [iam.ArnPrincipal(role_arn)], actions = ...))

kms1 = kms.Key(...)
kms1.grant_decrypt(role)
kms0.add_to_role_policy(... same as above ...)

secrets0 = secretsmanager.Secret(...) #maybe this is based off kms0
secrets0.grant_read(role)
secrets1 = secretsmanager.Secret(...) #maybe this is based off kms1
secrets1.grant_read(role)

# You can turn all this into a loop ofc.
ssm0 = ssm.StingParameter(self, '...', parameter_name = 'kms0_arn', string_value = kms0.key_arn, ...)
ssm0.grant_read(role)
ssm1 = ssm.StingParameter(self, '...', parameter_name = 'kms1_arn', string_value = kms1.key_arn, ...)
ssm1.grant_read(role)
ssm2 = ssm.StingParameter(self, '...', parameter_name = 'secrets0_arn', string_value = secrets0.secret_full_arn, ...)
ssm2.grant_read(role)
...

#Now simply pass around the role and ssm parameter names
for env in environments:
   MyApplicationStage(self, <...>, ..., role_arn = role_arn, params = [ 'kms0_arn', 'kms1_arn', ... ], ...)

然后在目标阶段:

代码语言:javascript
复制
for parm in params:
   fn = AwsSdkCall('ssm', 'get_parameter', { "Name": param }, ...)
   acr = AwsCustomResource(..., on_create = fn, on_update = fn, ...)
   collect['param'] = acr.get_response_field('Parameter.Value')

现在,对收集到的工件做您想做的任何事情,包括将它们作为环境变量提供给您的主服务lambda (将在部署时解决这些问题)。

记住,它们都是标记,只有在部署时才能解决,但是对于任何资源来说都是如此,无论是否通过自定义资源,这都不重要。

这是一种通用模式,在任何情况下都适用。

(问这个问题的GitHub链接,我也在那里回答过)

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/69844990

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档