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

Allow accounts deployment_targets for deploy_method of scp #89

Open cabjas01 opened 2 years ago

cabjas01 commented 2 years ago

Problem Statement: We would like to deploy specific SCP's to specific accounts, however, when we put an account under deployment_targets of type scp, we get the SCP created, but not attached to the account.

Evidence of log showing no AccountId's: Starting execution of state machine: arn:aws:states:us-east-1::stateMachine:CustomControlTowerServiceControlPolicyMachine with input: {'RequestType': 'Create', 'ResourceProperties': {'PolicyDocument': {'Name': 'scp_deny-stuff', 'Description': 'Policy for deny stuff', 'PolicyURL': 'https://cfct-bucket[.]s3.us-east-1.amazonaws.com/_custom_ct_templates_staging/policies/scp_deny-stuff.json'}, 'AccountId': '', 'PolicyList': [], 'Operation': '', 'OUList': [], 'OUNameDelimiter': ':'}}}

Actual Result: scp is created, but not attached to any accounts.

Expected Result: If an account is listed under deployment_targets, the scp should get created and attached to that account.

Version: v2.2.0

How to reproduce, add the following to manifest.yaml.

rakshb commented 2 years ago

@cabjas01 Thanks for the request. We have added this to out backlog.

kiernan commented 2 years ago

This has been our experience as well. We are having to create the SCP's without any targets then attach them manually, as we don't wish to create an OU for every individual account that needs a custom SCP.

suankan commented 1 year ago

The code which processes deployment_targets lists is absolutely different when we use deploy_method: scp and deploy_method: stack_set.

For scp:

                attach_ou_list = set(
                    resource.deployment_targets.organizational_units)

                self.logger.debug(
                    "[manifest_parser.parse_scp_manifest_v2] attach_ou_list: {} ".format(
                        attach_ou_list))

                # Add ou id to final ou list
                final_ou_list = org_data.get_final_ou_list(attach_ou_list)

                state_machine_inputs.append(build.scp_sm_input(
                    final_ou_list,
                    resource,
                    policy_url))

We can see it can only process OUs....

For stack_set:

                if resource.deployment_targets.organizational_units:
                    accounts_in_ou = org.get_accounts_in_ou(
                        organizations_data.get("OuIdToAccountMap"),
                        organizations_data.get("OuNameToIdMap"),
                        resource.deployment_targets.organizational_units
                    )

                # convert account numbers to string type
                account_list = convert_list_values_to_string(
                    resource.deployment_targets.accounts)
                self.logger.info(">>>>>> ACCOUNT LIST")
                self.logger.info(account_list)

                sanitized_account_list = org.get_final_account_list(
                    account_list, organizations_data.get("AccountsInAllNestedOUs"),
                    accounts_in_ou, organizations_data.get("NameToAccountMap"))

                self.logger.info("Print merged account list - accounts in "
                                 "manifest + account under OU in manifest")
                self.logger.info(sanitized_account_list)

                if resource.deploy_method.lower() == 'stack_set':
                    sm_input = build.stack_set_state_machine_input_v2(
                        resource, sanitized_account_list)
                    state_machine_inputs.append(sm_input)

AWS guys, please bring this into order. The above causes significantly different behaviour for deploy_method: scp and deploy_method: stack_set, this issue and issue #126 are good examples.

Because from the end-user perspective, the yaml structure which we put into the manifest.yaml is the same for deploy_method: scp and deploy_method: stack_set. So naturally we expect these items to be processed in the same way, but in fact they are not.