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
360 stars 205 forks source link

SSM parameters and dependencies between stack sets #32

Closed kolomied closed 3 years ago

kolomied commented 4 years ago

I may be seriously confused regarding intended scenario for ssm_parameters manifest property.

My understanding is that it is supposed to help with dependencies between stack sets. Here is a simple example with two stack sets:

I expect that I can save output variable from stack instance in SSM parameter within Account/Region where the stack instance is deployed, so it can be consumed by different stack sets, like below:

image

My expectation is that I can achieve this with the following manifest:

---
region: eu-west-1
version: 2020-01-01

cloudformation_resources:
  - name: network-stackset
    template_file: templates/network.template
    parameter_file: parameters/network.json
    ssm_parameters:
      - name: /org/member/VpcId
        value: $[output_VpcId]
    deploy_method: stack_set
    deploy_to_ou:
      - Custom
    regions:
      - eu-west-1
      - eu-central-1  
  - name: app-stackset
    template_file: templates/app.template
    parameter_file: parameters/app.json
    deploy_method: stack_set
    deploy_to_ou: 
      - Custom
    regions:
      - eu-west-1
      - eu-central-1 

However, what I observe is that /org/member/VpcId SSM parameter is created in master account/region - the account where the solution is deployed (the one with Control Tower enabled). No SSM parameters are created in member accounts, therefore app-stackset deployment fails as it relies on these parameters.

I tracked the issue down to the following lines (note that SSM client is created with default parameters, which means current - master - account and region):

https://github.com/awslabs/aws-control-tower-customizations/blob/b006bd8342ebf03b9458ec11e794ecb3bbba7845/source/state_machine_handler.py#L1010-L1016

Also, may be related to this problem - when Step Function exports CFN output variables to save them in SSM, it does so for the first Account/Region pair returned, which looks incorrect:

https://github.com/awslabs/aws-control-tower-customizations/blob/b006bd8342ebf03b9458ec11e794ecb3bbba7845/source/state_machine_handler.py#L1033-L1037

For now I have to manage SSM parameters manually within CFN templates without relying on the manifest file support. Please let me know if my understanding of the issue is correct - happy to help with PR to address it.

kolomied commented 4 years ago

I also tried the approach outlined in Appendix A: Using alfred helper in the CloudFormation parameter files.

I see the same issue there - parameter substitution code in /source/manifest/cfn_params_handler.py tries to access SSM parameters in the master account/region, not in account/region where stack instance should be deployed.

The only way that works for me is a fallback to CloudFormation default parameter values in the template (with the obvious disadvantage that I have to modify the template):

---
AWSTemplateFormatVersion: '2010-09-09'
Description: Dev Template to test overrideparams
Parameters:
  VpcId:
    Type: 'AWS::SSM::Parameter::Value<String>'
    Default: '/org/member/VpcId'

In this case CloudFormation retrieves the parameters during deployment time from the region where stack instance is deployed.

groverlalit commented 4 years ago

Hello @kolomied, The alfred functionality does store the SSM parameter key/value pair in the master account. Since you are deploying this in multiple regions alfred function may not help you with your use case.

I agree with your approach to store the VPC id in the local account and region using AWS::SSM::Parameter resource in the stack 1 and use CFN parameter type "'AWS::SSM::Parameter::Value'" in the stack 2 to obtain the value from the local account and region.

kolomied commented 4 years ago

@groverlalit Thank you for the response.

Could you also share the intended use case for ssm_parameters manifest property - it is not clear from the documentation when it can be useful.

jdonboch commented 4 years ago

I am also confused by the documentation as they reference the ability to store outputs using ssm_parameters section but then Appendix A does not cite using this feature at all. I would think Appendix A would showcase how the alfred retriever would work with the ssm_parameters section. Are these two things compatible?

groverlalit commented 3 years ago

@jdonboch @kolomied Thanks for the feedback.

We understand that Appendix A in the developer guide currently does not refer to the ssm_parameters section of the manifest to the alfred helper but to a generic SSM parameter resource. We have updated our backlog to update the documentation.

To answer your question, yes they are compatible. As we know that a new parameter store key value pair can be created by following methods:

  1. ssm_parameters (in manifest.yaml)
  2. ssm parameter resource embedded in the the CFN template
  3. adding parameter store key value using AWS Console, AWS CLI or AWS SDK.

As long as the SSM parameter exists in the region in the Org master account where the solution is deployed, the alfred helper can read it and replace the parameter value in the parameters.json file.

Hope this helps.

zoellner commented 3 years ago

@groverlalit could you explain what the developer guide is trying to tell us in the note that says

Note: The SSM parameter key name may contain a value other than output. For example, if the name is /org/environment-name, the value may production.

Could you give a full example of how to get from a template with outputs to another template that uses that output as a parameter?

groverlalit commented 3 years ago

@zoellner Using the example configuration deployed with the solution (S3 or CodeCommit).

If you need the application id from stackset-1 to be passed as parameter to the stackset-2.

Snipper of manifest.yaml (note: incorrect indentation) # Control Tower Custom CloudFormation Resources cloudformation_resources: - name: stackset-1 template_file: templates/create-ssm-parameter-keys-1.template parameter_file: parameters/create-ssm-parameter-keys-1.json deploy_method: stack_set deploy_to_account: # :type: list - <ACCOUNT_NAME> # and/or - <ACCOUNT_NUMBER> ssm_parameters: - name: /org/member/test-ssm/app-id << Puts the value value: $[output_ApplicationId] regions: - <REGION_NAME>

- name: stackset-2 template_file: templates/create-ssm-parameter-keys-2.template parameter_file: parameters/create-ssm-parameter-keys-2.json deploy_method: stack_set deploy_to_ou: # :type: list - <OU_NAME> deploy_to_account: # :type: list - <ACCOUNT_NAME> # and/or - <ACCOUNT_NUMBER> regions: # :type: list - <REGION_NAME>

You can modify the example-configuration/parameters/create-ssm-parameter-keys-2.json file as follows.

[ { "ParameterKey": "ApplicationId", "ParameterValue": "$[alfred_ssm_/org/member/test-ssm/app-id]" << Gets the value } ...cut...

Hope this helps. Thanks.

xmik commented 3 years ago

I tried using ssm_parameters in a manner described above and also here:

  ssm_parameters:
    - name: "/test/cfct_output/test1"
      value: "123"

and the Build stage of the CfCT pipeline failed with:

ERROR - ["Key 'ssm_parameters' was not defined. Path: '/resources/0'"] 

Environment

camtauxe commented 11 months ago

I think this issue should remain open, as the existing documentation on Alfred is either incomplete or incorrect, and following it does not lead to a working solution.

It's also worth pointing out that, in manifest v2, the ssm_parameters field needs to be renamed to export_outputs.