Skip to content

Commit

Permalink
Feat/multi org support (#668)
Browse files Browse the repository at this point in the history
## Why?

Adding support for Multi-Organization 'Enterprise' ADF Installations.
What?

## Description of changes:

- Added New Documentation Section on Multi-Org
- Added adf/org/stage parameter to all managed accounts
- Added method to read organization specific adfconfig.yml files.
- Updated Sample ADF Baseline Template with Custom Mappings based on organization parameter.


---

Co-authored-by: Andreas Falkenberg
Co-authored-by: Simon Kok
  • Loading branch information
alexevansigg authored Feb 5, 2024
1 parent bcc100e commit fac17ba
Show file tree
Hide file tree
Showing 12 changed files with 425 additions and 5 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@ template as its baseline.
contribute or build on top of ADF.
- Refer to the [Samples Guide](docs/samples-guide.md) for a detailed walk
through of the provided samples.
- Refer to the [Multi-Organization ADF Setup](docs/multi-organization-guide.md)
to use ADF in an enterprise-grade setup.
7 changes: 6 additions & 1 deletion docs/admin-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ config:
scm: # Source Control Management
auto-create-repositories: enabled # Optional
default-scm-branch: main # Optional
org:
stage: dev # Optional
```
In the above example the properties are categorized into `roles`, `regions`,
Expand Down Expand Up @@ -232,10 +234,13 @@ Config has five components in `main-notification-endpoint`, `scp`, `scm`,
and prod AWS Organization with its own ADF instance per AWS organization.
This approach allows for well-tested and stable prod AWS Organization
deployments. If set, a matching SSM parameter `/adf/org/stage` gets
created that you can reference in your buildspec files to allow for
created in the deployment and all target accounts.
You can reference it within your buildspec files to allow for
org-specific deployments; without hardcoding the AWS Organization stage in
your buildspec. If this variable is not set, the SSM parameter
`/adf/org/stage` defaults to "none".
More information about setting up ADF with multiple AWS Organizations can
be found in the [Multi-Organization Guide](multi-organization-guide.md)

- **default-scm-codecommit-account-id** allows you to configure the default
account id that should be used with all source-code management platforms
Expand Down
Binary file added docs/images/aws-multi-org-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/images/aws-multi-org-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
339 changes: 339 additions & 0 deletions docs/multi-organization-guide.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions src/lambda_codebase/account_bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ def configure_generic_account(sts, event, region, role):
bucket_name = parameter_store_deployment_account.fetch_parameter(
f'/cross_region/s3_regional_bucket/{region}',
)
org_stage = parameter_store_deployment_account.fetch_parameter(
'/adf/org/stage'
)
except (ClientError, ParameterNotFoundError):
raise GenericAccountConfigureError(
f'Account {event["account_id"]} cannot yet be bootstrapped '
Expand All @@ -79,6 +82,7 @@ def configure_generic_account(sts, event, region, role):
'deployment_account_id',
event['deployment_account_id'],
)
parameter_store_target_account.put_parameter('/adf/org/stage', org_stage)


def configure_master_account_parameters(event):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,29 @@
AWSTemplateFormatVersion: "2010-09-09"
Description: ADF CloudFormation Template (Global) for IAM in the Deployment Account

# Parameters:
# OrgStage can be set in the respective adfconfig file using the
# path config.org.stage
# OrgStage:
# Type: "AWS::SSM::Parameter::Value<String>"
# Description: A stage used to differentiate Multi-Organization ADF environments
# Default: /adf/org/stage

# Org StageCustom Mappings allows you to dynamically build different IAM
# Conditions / Principals ARN / Resource ARN per Organization applying Least
# Privilege Principals whilst retaining a Single Stack Definition for all
# environments.
# Example usage:
# !FindInMap[OrgStageMap: !Ref OrgStage, ExampleCustomProperty]
# Mappings:
# OrgStageMap:
# Dev:
# ExampleCustomProperty: 1234
# Int:
# ExampleCustomProperty: 5678
# Prod:
# ExampleCustomProperty: 9102

Resources:
CloudFormationDeploymentPolicy:
# This is the policy that will be used to deploy CloudFormation resources from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,28 @@ Parameters:
Description: Deployment Account ID
Default: deployment_account_id

# OrgStage can be set in the respective adfconfig file using the
# path config.org.stage
# OrgStage:
# Type: "AWS::SSM::Parameter::Value<String>"
# Description: A stage used to differentiate Multi-Org ADF environments
# Default: /adf/org/stage

# Org Stage Custom Mappings allows you to dynamically build different IAM
# Conditions / Principals ARN / Resource ARN per Organization applying
# least-privilege principles whilst retaining a Single Stack Definition for all
# environments.
# Example usage:
# !FindInMap[OrgStageMap: !Ref OrgStage, ExampleCustomProperty]
# Mappings:
# OrgStageMap:
# Dev:
# ExampleCustomProperty: 1234
# Int:
# ExampleCustomProperty: 5678
# Prod:
# ExampleCustomProperty: 9102

Resources:
CloudFormationDeploymentPolicy:
# This is the policy that will be used to deploy CloudFormation resources from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,20 @@ def _validate(self):

def _load_config_file(self):
"""
Loads the adfconfig.yml file and executes _parse_config
Checks for an Org Specific adfconfig.yml (adfconfig.{ORG_ID}.yml)
and uses that if it exists. Otherwise it uses the default adfconfig.yml
and executes _parse_config
"""
with open(self.config_path, encoding="utf-8") as config:
self.config_contents = yaml.load(config, Loader=yaml.FullLoader)
self._parse_config()
org_config_path = self.config_path.replace(".yml", f".{self.organization_id}.yml")
if os.path.exists(org_config_path):
with open(org_config_path, encoding="utf-8") as org_config_file:
LOGGER.info("Using organization specific ADF config: %s", org_config_path)
self.config_contents = yaml.load(org_config_file, Loader=yaml.FullLoader)
else:
LOGGER.info("Using default ADF config: %s", self.config_path)
with open(self.config_path, encoding="utf-8") as config:
self.config_contents = yaml.load(config, Loader=yaml.FullLoader)
self._parse_config()

def _parse_config(self):
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,15 @@ def worker_thread(
'bucket_name',
updated_kms_bucket_dict[region]['s3_regional_bucket'],
)

# Ensuring the stage parameter on the target account is up-to-date
parameter_store.put_parameter(
'/adf/org/stage',
config.config.get('org', {}).get(
'stage',
ADF_DEFAULT_ORG_STAGE,
)
)
cloudformation = CloudFormation(
region=region,
deployment_account_region=config.deployment_account_region,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ config:
default-scm-branch: master
# ^ The default branch is used when the pipeline does not specify a specific branch.
# If this parameter is not specified, it defaults to the "master" branch.
org:
stage: prod
# ^ This value will be set as an SSM Parameter named /adf/org/stage
# in both the deployment account and and all
# Target member accounts as part of the Bootstrap Statemachine.
# It is useful as a flag to drive Organization specific logic within
# IAM Role definitions/conditions as well as Build spec behavior.

extensions:
terraform:
Expand Down

0 comments on commit fac17ba

Please sign in to comment.