aws-solutions / aws-control-tower-customizations

The Customizations for AWS Control Tower solution combines AWS Control Tower and other highly-available, trusted AWS services to help customers more quickly set up a secure, multi-account AWS environment using AWS best practices.
https://docs.aws.amazon.com/controltower/latest/userguide/cfct-overview.html
Apache License 2.0
355 stars 205 forks source link

Improved support for multi-region resource deployments #113

Open adamspicer opened 2 years ago

adamspicer commented 2 years ago

When you have a manifest resource that needs to be deployed across multiple regions, AND we need to store an output from the stack in the SSM parameters, we end up having to duplicate the entire manifest resource in CfCT so that the SSM parameter for each region can be unique. As a result, let's say we need to deploy the resource to 3 regions, we've now created 3 manifest resource entries that only differ in their name and the SSM parameter used to store the output. This results in entries that look similar to the following:

  - name: baseline-tgw-us-east-1
    resource_file: templates/baseline-tgw.yaml
    deploy_method: stack_set
    deployment_targets: 
      accounts:
        - 777788889999 # Networking account ID
    export_outputs:
      - name: /baseline/TransitGatewayId/us-east-1
        value: $[output_TGWId]
    regions:
      - us-east-1

  - name: baseline-tgw-us-west-2
    resource_file: templates/baseline-tgw.yaml
    deploy_method: stack_set
    deployment_targets: 
      accounts:
        - 777788889999 # Networking account ID
    export_outputs:
      - name: /baseline/TransitGatewayId/us-west-2
        value: $[output_TGWId]
    regions:
      - us-east-2

  - name: baseline-tgw-spoke-us-east-1
    resource_file: templates/baseline-tgw-spoke.yaml
    parameters:
      - parameter_key: TransitGatewayId
        parameter_value: $[alfred_ssm_/baseline/TransitGatewayId/us-east-1] 
    deploy_method: stack_set
    deployment_targets: 
      organizational_units:
        - workloads
    regions:
      - us-east-1

  - name: baseline-tgw-spoke-us-west-2
    resource_file: templates/baseline-tgw-spoke.yaml
    parameters:
      - parameter_key: TransitGatewayId
        parameter_value: $[alfred_ssm_/baseline/TransitGatewayId/us-west-2] 
    deploy_method: stack_set
    deployment_targets: 
      organizational_units:
        - workloads
    regions:
      - us-west-2

As projects grow and region usage increases, this causes the manifest file to be unnecessarily bloated.

Recommendation One recommendation would be for CfCT to automatically (by convention) concatenate a region to the end of the path for the export name. In addition, when referencing the export via alfred, add support for a pseudo parameter "${AWS::Region}". So considering the example above, I can simplify my manifest by not having to duplicate resource blocks just because I want to use outputs from multiple regions within the same manifest resource block.

The same example above can then be simplified as shown below.

  - name: baseline-tgw
    resource_file: templates/baseline-tgw.yaml
    deploy_method: stack_set
    deployment_targets: 
      accounts:
        - 777788889999 # Networking account ID
    export_outputs:
      - name: /baseline/TransitGatewayId    # NOTE: This implicitly adds the executing region's path to the export name
        value: $[output_TGWId]
    regions:
      - us-east-1
      - us-west-2

  - name: baseline-tgw-spoke
    resource_file: templates/baseline-tgw-spoke.yaml
    parameters:
      - parameter_key: TransitGatewayId
        parameter_value: $[alfred_ssm_/baseline/TransitGatewayId/{AWS::Region}]   # NOTE: alfred helper swaps {AWS::Region} with the executing region
    deploy_method: stack_set
    deployment_targets: 
      organizational_units:
        - workloads
    regions:
      - us-east-1
      - us-west-2

Additional context One thought might be to add support for a pseudo parameter "${AWS::Region}" in the export_outputs section. But I'd argue against that and make it an implicit convention by default. It will then keep all output params that are exported to CfCT to have the region specific path to the outputs. This can help prevent issues when manifest resources are deployed to multiple regions and their export values are being overridden by the last stack to execute.

stumins commented 2 years ago

Hey @adamspicer,

I understand the underlying issue w.r.t the hub-spoke deployment model you are using - thanks for providing a detailed use-case and examples with your enhancement request. I've created a backlog item for the team to explore improving the multi-account UX here.