| 
                      	
                        
                         Here’s an AWS CloudFormation template and deployment script to set up
Organizational Units
and
Accounts
for Prod and Dev for a new project or department. 
Deploying a CloudFormation stack from this template will require a user in the
Organization’s
management account
with the AdministratorAccess permission set. 
The created Organizational Unit (OU) and Account structure will look this: 
Organization Root [pre-existing]
  ╚═ Management Account [pre-existing]
  ╚═ Project Parent OU
     ╚═ Project Prod OU
        ╚═ Project Prod Account
     ╚═ Project Dev OU
        ╚═ Project Dev Account
The OUs are not strictly necessary, but they help to group the whole project
under a single OU, and to allow for other accounts to be added later within the
Prod and Dev OUs if necessary. 
The CloudFormation template looks like this: 
---
AWSTemplateFormatVersion: '2010-09-09'
Description: >
  Create AWS Organizational Units and an Accounts for a project.
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-organizations-organizationalunit.html
# https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-organizations-account.html
Parameters:
  OrganizationRootId:
    Type: String
    Description: ID of the root Organization of the management account.
    AllowedPattern: "^(r-[0-9a-z]{4,32})$"
  ProjectName:
    Type: String
    Description: Overall name for this project, used in OU and Account names.
    AllowedPattern: "^([a-zA-Z]+)$"
  EmailDomain:
    Type: String
    Description: Domain name for AWS Account email addresses.
    AllowedPattern: "^([a-zA-Z0-9]+).([a-zA-Z0-9\.]+)$"
Resources:
  ProjectParentOrganizationalUnit:
    Type: AWS::Organizations::OrganizationalUnit
    Properties:
      Name: !Sub "${ProjectName}ParentOU"
      ParentId: !Ref OrganizationRootId
  ProdOrganizationalUnit:
    Type: AWS::Organizations::OrganizationalUnit
    Properties:
      Name: !Sub "${ProjectName}ProdOU"
      ParentId: !Ref ProjectParentOrganizationalUnit
  ProdAccount:
    Type: AWS::Organizations::Account
    Properties:
      AccountName: !Sub "${ProjectName}Prod"
      Email: !Sub "${ProjectName}_aws_prod@${EmailDomain}"
      RoleName: !Sub "${ProjectName}ProdAdmin"
      ParentIds:
        - !Ref ProdOrganizationalUnit
  DevOrganizationalUnit:
    Type: AWS::Organizations::OrganizationalUnit
    Properties:
      Name: !Sub "${ProjectName}DevOU"
      ParentId: !Ref ProjectParentOrganizationalUnit
  DevAccount:
    Type: AWS::Organizations::Account
    Properties:
      AccountName: !Sub "${ProjectName}Dev"
      Email: !Sub "${ProjectName}_aws_dev@${EmailDomain}"
      RoleName: !Sub "${ProjectName}DevAdmin"
      ParentIds:
        - !Ref DevOrganizationalUnit
Outputs:
  ProjectParentOrganizationalUnitArn:
    Description: ARN of the Project Parent Organizational Unit
    Value: !GetAtt ProjectParentOrganizationalUnit.Arn
  ProdOrganizationalUnitArn:
    Description: ARN of the Prod Organizational Unit
    Value: !GetAtt ProdOrganizationalUnit.Arn
  ProdAccountArn:
    Description: ARN of the Prod Account
    Value: !GetAtt ProdAccount.Arn
  DevOrganizationalUnitArn:
    Description: ARN of the Dev Organizational Unit
    Value: !GetAtt DevOrganizationalUnit.Arn
  DevAccountArn:
    Description: ARN of the Dev Account
    Value: !GetAtt DevAccount.Arn
 Here’s a sample deployment script to deploy the above template: 
#!/usr/bin/env bash
set -e, -u, -x, -o pipefail
PARENT_PATH=$( cd "$(dirname "${BASH_SOURCE[0]}")" || exit; pwd -P )
TEMPLATE_PATH="${PARENT_PATH}/cloudformation.yml"
PARAMS_PATH="${PARENT_PATH}/config/organizational.params"
ls "${TEMPLATE_PATH}"
if [ ! -f "${TEMPLATE_PATH}" ]; then
  echo "Cloudformation template file is missing"
fi
ls "${PARAMS_PATH}"
if [ ! -f "${PARAMS_PATH}" ]; then
  echo "Params file is missing"
fi
if [ -z ${AWS_PROFILE+x} ]; then
  echo "AWS_PROFILE is not set"
  exit 1
fi
# shellcheck disable=SC1090
source "${PARAMS_PATH}"
if [ -z ${OrganizationRootId+x} ]; then
  echo "OrganizationRootId is not set"
  exit 1
fi
# shellcheck disable=SC2154
echo "OrganizationRootId: ${OrganizationRootId}"
# shellcheck disable=SC2154
echo "ProjectName: ${ProjectName}"
# https://docs.aws.amazon.com/cli/latest/reference/cloudformation/deploy/
# shellcheck disable=SC2046
aws cloudformation deploy \
  --profile "${AWS_PROFILE}" \
  --template-file "${PARENT_PATH}/cloudformation.yml" \
  --stack-name "${ProjectName}-Organizational" \
  --parameter-overrides OrganizationRootId="${OrganizationRootId}" $(cat "${PARAMS_PATH}")
 That requires a params file at ./config/organizational.params, which provides
the ProjectName and EmailDomain params, for example: 
ProjectName=FoobarProject
EmailDomain=kensiosoftware.co.uk
 This assumes that a catch-all email is set up on the specified domain, so that
the CloudFormation template can make up specific email addresses for each
account. 
                        
                         
                        View post:
                        
                        	Creating AWS Organizational Units and Accounts for Prod and Dev in CloudFormation
                        
                       |