解决AWS CDK CloudFormation堆栈之间的周期性依赖关系

时间:2020-02-19 19:06:44

标签: amazon-web-services amazon-cloudformation aws-cdk

上下文,我有一个CDK应用程序,使用以下设置有两个堆栈:

Stack_A:
    StateMachine_A
    Lambda_A
    S3Bucket_A
    IAMRole_A

Stack_B:
    StateMachine_B
    SageMakerTrainJob_B
    IAMRole_B

StateMachine_A使用执行角色IAMRole_A运行Lambda_A。 StateMachine_A中的一个单独步骤将数据写入S3Bucket_A。 StateMachine_B使用执行角色IAMRole_B运行SageMakerTrainJob_B。 Lambda_A的目的是开始执行StateMachine_B,它的SageMakerTrainJob_B需要从S3Bucket_A中读取。因此,我们必须配置以下权限:

  • IAMRole_A需要对StateMachine_B的startExecution权限。
  • IAMRole_B需要对S3Bucket_A的读取权限。

我们试图通过在Stack_A上的Stack_B中创建直接依赖项来在CDK中对此模型化,并使用Stack_B定义中对IAMRole_A和S3Bucket_A的引用来授予所需的代码权限。但是,这会产生以下错误:

Error: 'Stack_B' depends on 'Stack_A' (dependency added using stack.addDependency()). Adding this dependency (Stack_A -> Stack_B/IAMRole_B/Resource.Arn) would create a cyclic reference.

同样,尝试在另一个方向上对依赖关系建模会产生相同的错误:

Error: 'Stack_A' depends on 'Stack_B' (dependency added using stack.addDependency()). Adding this dependency (Stack_B -> Stack_A/S3Bucket_A/Resource.Arn) would create a cyclic reference.

有没有使用代码依赖项解决此问题的方法?对于这种情况,是否有建议的最佳做法?我们考虑过的一些选项包括:

  • 使用依赖于两者的第三个堆栈,以使Stack_A和Stack_B能够访问彼此的资源。
  • 为每个堆栈中的必要资源创建其他访问角色,并在CDK之外的某个地方维护Lambda / SageMaker角色的承担角色权限。
  • 将它们全部放在一个堆栈中。对于组织而言不是很好,并且确实使资源紧密耦合在一起-我们可能不希望StateMachine_A成为将来StateMachine_B的唯一入口点。

此外,我发现在CodeCommit/CodePipelineAPIGateway/Lambda的CDK开发过程中,存在类似的问题。这是一个相关的错误,还是我们只是试图做一些不被支持的事情?

1 个答案:

答案 0 :(得分:4)

循环引用总是很棘手。这不是CDK独有的问题。当您从逻辑上解释问题时,您会看到事情开始崩溃的地方。 CloudFormation必须创建另一个资源依赖的任何资源,然后才能创建依赖资源。没有一种解决方案可以适合所有方法,但是我会给出一些可行的想法。

  1. 将共享资源提升到另一个堆栈。在您的情况下,两个堆栈都需要使用S3存储桶,因此如果这两个堆栈都在运行的堆栈中,则可以创建S3存储桶,在堆栈B中使用导出/导入来引用S3存储桶,并使用和导出/ import在堆栈A中引用S3存储桶和B中的状态机。
  2. 在权限中使用通配符。通常,您可以知道资源的名称或名称的足够多,以便在您的权限中使用通配符。您希望保持权限的范围狭窄,但是通常部分名称匹配就足够了。当然,请谨慎使用此选项。另外请记住,您可以命名许多资源。许多人不愿意这样做,有些资源则不应该(例如S3存储桶),但是我经常发现命名更容易。
  3. 创建一个自定义资源以将事物捆绑在一起。如果您具有无法解决的真正循环依赖关系(即使在同一堆栈中),则可能需要使用自定义资源为您完成工作。最好的例子是S3 bucket events