如何使用 AWS CDK 从两个不同的账户获取 SSM 参数

How to fetch SSM Parameters from two different accounts using AWS CDK

我有一个场景,我正在使用 CodePipeline 将我的 cdk 项目从一个工具帐户部署到多个环境帐户。 我的管道部署方式是通过 运行 cdk deploy 来自 CodeBuild 作业。

我的团队决定使用 SSM Parameter Store 来存储配置,我们最终在环境帐户中找到了一些参数,例如我可以读取的 VPC_ID (resources/vpc/id)部署时间 => ssm.StringParameter.valueForStringParameter.

但是,其他参数存在于工具帐户中,例如来自我的环境帐户 (environment/nonprod/account/id) 和其他全局配置的帐户 ID。我无法获取这些值。

目前,我能想到的唯一方法是使用一个步骤读取上一步中的所有这些值并将它们加载到上下文值中。

这个问题有更优雅的方法吗?我希望我可以指定从哪个帐户获取 SSM 值。有任何想法吗?

谢谢。

据我所知,没有本地方法可以实现您所描述的内容。如果有办法我也想知道。我相信您可以为此目的使用由 lambda 烘焙的 CloudFormation 自定义资源。

您可以将参数传递给 lambda 请求并从 lambda 响应中获取信息。

有关详细信息,请参阅 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources-lambda.html, https://www.2ndwatch.com/blog/a-step-by-step-guide-on-using-aws-lambda-backed-custom-resources-with-amazon-cfts/ and https://docs.aws.amazon.com/cdk/api/latest/docs/custom-resources-readme.html

正如您已经说过的,没有对此的原生支持。我还在跨账户部署中使用 CodePipeline,因此所有自动化参数或产品指定参数都存储在安全账户中,CodePipeline 使用 CloudFormation 作为操作提供者部署资源。

SSM 参数的跨账户解析不受支持,所以最后,我在我的 CodePipeline 中添加了一个额外的步骤(阶段),它只是一个 CodeBuild 项目,它在容器化的环境中运行脚本环境和脚本然后 "syncs" 从自动化帐户到目标帐户的参数。

作为您管道的一部分,我将添加一个初步步骤来执行 Lambda。 Lambda 然后可以执行您希望获得所需的任何 metadata/config 的任何查询。然后可以将该 Lambda 的输出传递到 CodeBuild 步骤。

例如在 Lambda 中:

export class ConfigFetcher {

  codepipeline = new AWS.CodePipeline();

  async fetchConfig(event: CodePipelineEvent, context : Context) : Promise<void> {

    // Retrieve the Job ID from the Lambda action
    const jobId = event['CodePipeline.job'].id;

    // now get your config by executing whatever queries you need, even cross-account, via the SDK
    // we assume that the answer is in the variable someValue
    const params = {
      jobId: jobId,
      outputVariables: {
        MY_CONFIG: someValue,
      },
    };
    // now tell CodePipeline you're done
    await this.codepipeline.putJobSuccessResult(params).promise().catch(err => {
      console.error('Error reporting build success to CodePipeline: ' + err);
      throw err;
    });
 
    // make sure you have some sort of catch wrapping the above to post a failure to CodePipeline
// ...
  }
}

const configFetcher = new ConfigFetcher();

exports.handler = async function fetchConfigMetadata(event: CodePipelineEvent, context : Context): Promise<void> {
  return configFetcher.fetchConfig(event, context);
};

假设您使用 CDK 创建管道,那么您的 Lambda 步骤将使用如下方式创建:

const fetcherAction = new LambdaInvokeAction({
  actionName: 'FetchConfigMetadata',
  lambda: configFetcher,
  variablesNamespace: 'ConfigMetadata',
});

注意 variablesNamespace 的用法:我们稍后需要参考它,以便从 Lambda 的输出中检索值并将它们作为 env 变量插入到 CodeBuild 环境中。

现在是我们的 CodeBuild 定义,再次假设我们使用 CDK 创建:

new CodeBuildAction({
  // ...
  environmentVariables: {
    MY_CONFIG: {
      type: BuildEnvironmentVariableType.PLAINTEXT,
      value: '#{ConfigMetadata.MY_CONFIG}',
    },
  },

我们可以在 CodeBuild 中随意调用变量,但请注意 ConfigMetadata.MY_CONFIG 需要匹配 Lambda 的命名空间和输出值。

您可以让您的 lambda 执行任何您想要的操作以检索它需要的任何数据 - 如果需要,它只需要获得适当的权限才能访问其他 AWS 帐户,您可以使用角色承担来完成。使用 Lambda 作为管道步骤比在管道中使用 CodeBuild 步骤快很多,而且更容易更改:如果您在 Typescript/JS 或 Python 中编写 Lambda 代码,您甚至可以使用AWS 控制台进行就地编辑,同时您测试它是否正确执行。

这个问题已经有一年了,但我发现从您的 tools/deployment 帐户检索参数的更简单方法是 specify them as env variables in your buildspec file。 CodeBuild 将始终从您的工作 运行 所在的任何帐户中提取这些信息(在这个问题的场景中是工具帐户)。

要从目标环境帐户中提取参数,最好使用问题作者建议的CDK SSM approach