【问题标题】:CloudFormation Cross-Region ReferenceCloudFormation 跨区域参考
【发布时间】:2020-05-03 14:10:06
【问题描述】:

当您在同一区域内运行多个 CloudFormation 堆栈时,您可以使用 CloudFormation Outputs 跨堆栈共享引用

但是,正如该文档强调的那样,输出不能用于跨区域引用。

您不能跨区域创建跨堆栈引用。您可以使用内部函数 Fn::ImportValue 仅导入已在同一区域内导出的值。

您如何在 CloudFormation 中跨区域引用值?

举个例子,我在us-east-1 中部署了一个Route 53 hosted zone。但是,我在 us-west-2 中有一个后端,我想创建一个 DNS-validated ACM certificate,它需要引用托管区域才能创建适当的 CNAME 来证明所有权。

我将如何从us-west-2 中引用在us-east-1 中创建的托管区域ID?

【问题讨论】:

    标签: amazon-web-services amazon-cloudformation aws-cloudformation-custom-resource


    【解决方案1】:

    cdk库已经更新,需要修改代码如下:

    import { Construct } from '@aws-cdk/core';
    import { AwsCustomResource, AwsSdkCall } from '@aws-cdk/custom-resources';
    import iam = require("@aws-cdk/aws-iam");
    
    interface SSMParameterReaderProps {
      parameterName: string;
      region: string;
    }
    
    export class SSMParameterReader extends AwsCustomResource {
      constructor(scope: Construct, name: string, props: SSMParameterReaderProps) {
        const { parameterName, region } = props;
    
        const ssmAwsSdkCall: AwsSdkCall = {
          service: 'SSM',
          action: 'getParameter',
          parameters: {
            Name: parameterName
          },
          region,
          physicalResourceId: {id:Date.now().toString()} // Update physical id to always fetch the latest version
        };
    
        super(scope, name, { onUpdate: ssmAwsSdkCall,policy:{
            statements:[new iam.PolicyStatement({
            resources : ['*'],
            actions   : ['ssm:GetParameter'],
            effect:iam.Effect.ALLOW,
          }
          )]
        }});
      }
    
      public getParameterValue(): string {
        return this.getResponseField('Parameter.Value').toString();
      }
    }
    

    【讨论】:

      【解决方案2】:

      我发现这样做的最简单方法是将您要共享的引用(即在本例中为您的托管区域 ID)写入 Systems Manager Parameter Store,然后在单独区域的“子”堆栈中引用该值使用custom resource

      幸运的是,如果您的模板是使用 Cloud Development Kit (CDK) 创建的,这将非常容易。

      对于要从 SSM 读取的自定义资源,您可以使用如下内容:

      // ssm-parameter-reader.ts
      
      import { Construct } from '@aws-cdk/core';
      import { AwsCustomResource, AwsSdkCall } from '@aws-cdk/custom-resources';
      
      interface SSMParameterReaderProps {
        parameterName: string;
        region: string;
      }
      
      export class SSMParameterReader extends AwsCustomResource {
        constructor(scope: Construct, name: string, props: SSMParameterReaderProps) {
          const { parameterName, region } = props;
      
          const ssmAwsSdkCall: AwsSdkCall = {
            service: 'SSM',
            action: 'getParameter',
            parameters: {
              Name: parameterName
            },
            region,
            physicalResourceId: Date.now().toString() // Update physical id to always fetch the latest version
          };
      
          super(scope, name, { onUpdate: ssmAwsSdkCall });
        }
      
        public getParameterValue(): string {
          return this.getData('Parameter.Value').toString();
        }
      }
      
      

      要将托管区域 id 写入参数存储,您可以简单地执行以下操作:

      // route53.ts (deployed in us-east-1)
      
      import { PublicHostedZone } from '@aws-cdk/aws-route53';
      import { StringParameter } from '@aws-cdk/aws-ssm';
      
      export const ROUTE_53_HOSTED_ZONE_ID_SSM_PARAM = 'ROUTE_53_HOSTED_ZONE_ID_SSM_PARAM';
      
      /**
       * Other Logic
       */
      
      const hostedZone = new PublicHostedZone(this, 'WebsiteHostedZone', { zoneName: 'example.com' });
      
      new StringParameter(this, 'Route53HostedZoneIdSSMParam', {
        parameterName: ROUTE_53_HOSTED_ZONE_ID_SSM_PARAM,
        description: 'The Route 53 hosted zone id for this account',
        stringValue: hostedZone.hostedZoneId
      });
      

      最后,您可以使用我们刚刚创建的自定义资源从该区域的参数存储中读取该值,并使用它在us-west-2 中创建证书。

      // acm.ts (deployed in us-west-2)
      
      import { DnsValidatedCertificate } from '@aws-cdk/aws-certificatemanager';
      import { PublicHostedZone } from '@aws-cdk/aws-route53';
      
      import { ROUTE_53_HOSTED_ZONE_ID_SSM_PARAM } from './route53';
      import { SSMParameterReader } from './ssm-parameter-reader';
      
      /**
       * Other Logic
       */
      
      const hostedZoneIdReader = new SSMParameterReader(this, 'Route53HostedZoneIdReader', {
        parameterName: ROUTE_53_HOSTED_ZONE_ID_SSM_PARAM,
        region: 'us-east-1'
      });
      const hostedZoneId: string = hostedZoneIdReader.getParameterValue();
      const hostedZone = PublicHostedZone.fromPublicHostedZoneId(this, 'Route53HostedZone', hostedZoneId);
      
      const certificate = new DnsValidatedCertificate(this, 'ApiGatewayCertificate', { 'pdx.example.com', hostedZone });
      

      【讨论】:

      • 像魅力一样工作。我将其用于全球加速器,因为这需要来自不同地区的 arns
      • 如何用无服务器框架之类的东西做类似的事情??
      • @Marzouk 是的。无服务器框架提供免费仪表板,该仪表板具有称为输出的功能,可让您在部署时导出值,如 CloudFormation ARN 等,然后使用 ${outputs} 语法导入它们。更多详情:serverless.com/framework/docs/dashboard/output-variables
      • 很遗憾,如果存储中的参数发生变化,我不相信 cloudformation 会检测到这一点并使用更新的值重新部署。
      猜你喜欢
      • 1970-01-01
      • 2020-06-17
      • 1970-01-01
      • 2021-06-09
      • 1970-01-01
      • 2018-12-13
      • 1970-01-01
      • 2018-04-08
      • 2015-03-04
      相关资源
      最近更新 更多