繁体   English   中英

CloudFormation 跨区域参考

[英]CloudFormation Cross-Region Reference

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

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

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

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

例如,我在us-east-1中部署了一个Route 53 托管区域 但是,我在us-west-2中有一个后端,我想创建一个DNS 验证的 ACM 证书,该证书需要对托管区域的引用,以便能够创建适当的 CNAME 来证明所有权。

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

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

幸运的是,如果您的模板是使用云开发工具包 (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 });

cdk库更新了,avove的代码需要改成如下:

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();
  }
}

projen生成的项目中使用cdkv2版本2.56.0更新 2023-01-16 (因此遵守 eslint 规则和格式化的最佳实践等):

import {
  aws_iam as iam,
  custom_resources as cr,
} from 'aws-cdk-lib';
import { Construct } from 'constructs';

interface SSMParameterReaderProps {
  parameterName: string;
  region: string;
}

export class SSMParameterReader extends cr.AwsCustomResource {
  constructor(scope: Construct, name: string, props: SSMParameterReaderProps) {
    const { parameterName, region } = props;

    const ssmAwsSdkCall: cr.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();
  }
};

无法编辑上面的帖子...

CDK 2.x

有一个名为crossRegionReferences的新 Stack 属性,您可以启用它来添加跨区域引用。 就这么简单:

const stack = new Stack(app, 'Stack', {
  crossRegionReferences: true,
});

在幕后,这通过使用自定义资源和系统管理器来执行类似于上述答案的操作。 来自CDK 文档

跨区域引用?
启用此标志以允许本机跨区域堆栈引用。

启用此功能将在生产堆栈和消费堆栈中创建 CloudFormation 自定义资源以执行导出/导入

此功能目前处于试验阶段

来自CDK 核心 package README的更多详细信息:

您可以启用 Stack 属性crossRegionReferences以访问不同堆栈区域中的资源。 启用此功能标志后,可以执行一些操作,例如在us-east-2中创建 CloudFront 分配并在us-east-1中创建 ACM 证书。

当 AWS CDK 确定资源位于不同的堆栈不同的区域时,它将通过在生产堆栈中创建自定义资源来“导出”值,该资源在消费区域为每个导出的值创建 SSM 参数。 将使用名称“/cdk/exports/${consumingStackName}/${export-name}”创建参数。 为了将导出“导入”到使用堆栈中, SSM 动态引用用于引用创建的 SSM 参数。

为了模仿强引用,还在消费堆栈中创建了一个自定义资源,将 SSM 参数标记为“已导入”。 成功导入参数后,生产堆栈无法更新该值。

CDK 1.x

如果您使用的是 CDK 1.x,请继续使用其他人共享的解决方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM