跨AWS账户共享SecureString类型SSM参数解密值的问题
跨账户传递SSM SecureString解密值解决方案
问题原因
你拿到的{{resolve:ssm-secure:/CodeBuild/key:1}}是CDK/CloudFormation的延迟解析占位符——CDK在合成模板阶段不会解密SSM参数,而是把解析任务留给CloudFormation部署时处理。但跨账户场景下,CloudFormation默认没有权限访问AccountA的SSM参数,导致无法解析出实际值。
解决步骤
1. 配置AccountA的权限,允许AccountB访问
1.1 给SSM SecureString参数添加资源策略
在AccountA的CDK代码中,为目标SSM参数添加跨账户访问策略,允许AccountB的部署角色执行ssm:GetParameter和kms:Decrypt操作:
import * as ssm from 'aws-cdk-lib/aws-ssm'; import * as iam from 'aws-cdk-lib/aws-iam'; // AccountA中创建的SecureString参数 const secureParam = new ssm.StringParameter(this, 'CodeBuildKey', { parameterName: '/CodeBuild/key', stringValue: 'your-actual-secret', type: ssm.ParameterType.SECURE_STRING, }); // 添加跨账户访问策略 secureParam.addToResourcePolicy(new iam.PolicyStatement({ actions: ['ssm:GetParameter', 'kms:Decrypt'], principals: [new iam.AccountPrincipal('ACCOUNT_B_ID')], // 替换为AccountB的实际ID resources: [secureParam.parameterArn], }));
1.2 配置KMS密钥权限(如果用了自定义KMS密钥)
如果你的SSM参数是用自定义KMS密钥加密的,还需要给该KMS密钥添加权限,允许AccountB的角色解密:
import * as kms from 'aws-cdk-lib/aws-kms'; const customKmsKey = new kms.Key(this, 'CustomKey'); customKmsKey.addToResourcePolicy(new iam.PolicyStatement({ actions: ['kms:Decrypt'], principals: [new iam.AccountPrincipal('ACCOUNT_B_ID')], resources: ['*'], }));
2. 正确在Code Pipeline中传递参数
在AccountA的Code Pipeline部署Action中,直接传递SecretValue.ssmSecure类型的参数,不要试图提前解密:
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions'; import * as cdk from 'aws-cdk-lib'; const deployToAccountB = new codepipeline_actions.CloudFormationCreateUpdateStackAction({ actionName: 'Deploy_AccountB_Stack', stackName: 'AccountB-Target-Stack', templatePath: buildArtifact.atPath('cdk.out/AccountBStack.template.json'), parameterOverrides: { // 直接传递SecretValue,让CloudFormation在AccountB部署时解析 SecretParam: cdk.SecretValue.ssmSecure('/CodeBuild/key', '1'), }, account: 'ACCOUNT_B_ID', region: 'us-east-1', // 可指定自定义跨账户部署角色,确保权限足够 });
3. 在AccountB的栈中接收并使用解密值
在AccountB的CDK栈中,用SecretValue类型接收参数,在需要使用的地方通过unsafeUnwrap()传递(CloudFormation会在部署时替换为实际解密值):
import * as cdk from 'aws-cdk-lib'; import * as lambda from 'aws-cdk-lib/aws-lambda'; export class AccountBStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props: cdk.StackProps & { secretValue: cdk.SecretValue }) { super(scope, id, props); // 示例:将解密值传递给Lambda环境变量 new lambda.Function(this, 'SecretUsingLambda', { runtime: lambda.Runtime.NODEJS_18_X, handler: 'index.handler', code: lambda.Code.fromAsset('lambda-code'), environment: { SECRET_KEY: props.secretValue.unsafeUnwrap(), }, }); } }
关键注意点
- 不要在CDK代码中尝试提前解密(比如
unsafeUnwrap()在CDK合成阶段不会得到实际值,只会保留占位符),必须让CloudFormation在部署阶段解析。 - 确保Code Pipeline的执行角色或部署Action的角色,以及AccountB的CloudFormation部署角色,都有对应的权限访问AccountA的SSM参数和KMS密钥。
内容的提问来源于stack exchange,提问作者dossani
相关产品推荐
相关产品推荐

