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

时间:2020-05-04 23:37:33

标签: aws-cdk ssm

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

我的团队决定使用SSM参数存储来存储配置,我们最终在环境帐户中使用了一些参数,例如我可以在部署时间内读取的VPC_ID(resources/vpc/id)=> {{ 1}}。

但是,其他参数仍存在于工具帐户中,例如我的环境帐户(ssm.StringParameter.valueForStringParameter中的帐户ID)和其他全局配置。我在获取这些值时遇到问题。

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

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

谢谢。

3 个答案:

答案 0 :(得分:1)

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

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

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

答案 1 :(得分:1)

您已经说过,对此没有本地支持。我还在跨帐户部署中使用CodePipeline,因此所有自动化参数或产品指定的参数都存储在受保护的帐户中,并且CodePipeline使用CloudFormation作为操作提供程序来部署资源。

不支持SSM参数的跨帐户解析,因此最后,我在CodePipeline中添加了一个额外的步骤(阶段),这只是CodeBuild项目,该项目在容器化环境中运行脚本,并且脚本然后将参数从自动化帐户“同步”到目标帐户。

答案 2 :(得分:1)

作为您管道的一部分,我将添加一个初步步骤来执行 Lambda。然后,Lambda 可以执行您希望获取所需的任何元数据/配置的任何查询。然后可以将该 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 的输出中检索值并将它们作为环境变量插入到 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 控制台来执行- 在测试它正确执行的同时进行编辑。

相关问题