Skip to content

Commit d9979cf

Browse files
feat: AWS multi-account IAC setup with scripts for custom usage (#1)
1 parent 6964127 commit d9979cf

File tree

81 files changed

+3737
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

81 files changed

+3737
-0
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Lint and Test Infrastructure Setup
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- synchronize
8+
- reopened
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
lint-and-test-infra-code:
15+
runs-on: ubuntu-latest
16+
strategy:
17+
matrix:
18+
python-version: ["3.10", "3.11", "3.12", "3.13"]
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
23+
- name: Get Terraform and Terragrunt Versions
24+
id: get-versions
25+
run: |
26+
TERRAFORM_VERSION=$(grep "terraform_version" ${GITHUB_WORKSPACE}/root.hcl | head -1 | awk -F'"' '{print $2}' | sed 's/~> //' | sed -E 's/([0-9]+\.[0-9]+)\.[0-9x]+/\1.0/')
27+
28+
TERRAGRUNT_VERSION=$(grep "terragrunt_version" ${GITHUB_WORKSPACE}/root.hcl | head -1 | awk -F'"' '{print $2}' | sed 's/~> //' | sed -E 's/([0-9]+\.[0-9]+)\.[0-9x]+/\1.0/')
29+
30+
echo "terraform_version=$TERRAFORM_VERSION" >> $GITHUB_OUTPUT
31+
echo "terragrunt_version=$TERRAGRUNT_VERSION" >> $GITHUB_OUTPUT
32+
33+
- name: Setup Terraform
34+
uses: hashicorp/setup-terraform@v3
35+
with:
36+
terraform_version: ${{ steps.get-versions.outputs.terraform_version }}
37+
38+
- name: Setup Terragrunt
39+
run: |
40+
wget -q https://github.com/gruntwork-io/terragrunt/releases/download/v${{ steps.get-versions.outputs.terragrunt_version }}/terragrunt_linux_amd64 -O /tmp/terragrunt
41+
chmod +x /tmp/terragrunt
42+
sudo mv /tmp/terragrunt /usr/local/bin/terragrunt
43+
terragrunt --version
44+
45+
- name: Setup Terraform and Terragrunt Cache
46+
uses: actions/cache@v4
47+
with:
48+
path: |
49+
/tmp/terragrunt
50+
~/.terraform.d
51+
~/.terragrunt
52+
key: ${{ runner.os }}-tf-tg-${{ steps.get-versions.outputs.terraform_version }}-${{ steps.get-versions.outputs.terragrunt_version }}
53+
54+
- name: Setup Python
55+
uses: actions/setup-python@v5
56+
with:
57+
python-version: ${{ matrix.python-version }}
58+
59+
- name: Setup Python Cache
60+
uses: actions/cache@v4
61+
with:
62+
path: |
63+
~/.cache/pip
64+
~/.cache/uv
65+
~/.cache/hatch
66+
key: ${{ runner.os }}-python-${{ matrix.python-version }}-${{ hashFiles('requirements.lock', 'pyproject.toml') }}
67+
restore-keys: |
68+
${{ runner.os }}-python-${{ matrix.python-version }}-
69+
70+
- name: Setup Hatch and UV
71+
run: |
72+
pip install hatch uv
73+
74+
- name: Create Hatch Environment
75+
run: hatch env create env
76+
77+
- name: Setup Infra Test Dependencies
78+
run: hatch run env:install-infra-deps
79+
80+
- name: Lint Infra Setup
81+
run: hatch run env:lint-infra
82+
83+
- name: Test Infra Setup
84+
run: hatch run env:test-infra
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
name: Lint and Test Setup Scripts
2+
3+
on:
4+
pull_request:
5+
types:
6+
- opened
7+
- synchronize
8+
- reopened
9+
10+
permissions:
11+
contents: read
12+
13+
jobs:
14+
lint-and-test-setup-scripts:
15+
runs-on: ubuntu-latest
16+
defaults:
17+
run:
18+
working-directory: ./setup-scripts
19+
strategy:
20+
matrix:
21+
python-version: ["3.10", "3.11", "3.12", "3.13"]
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
26+
- name: Setup Python
27+
uses: actions/setup-python@v5
28+
with:
29+
python-version: ${{ matrix.python-version }}
30+
31+
- name: Setup Python Cache
32+
uses: actions/cache@v4
33+
with:
34+
path: |
35+
~/.cache/pip
36+
~/.cache/uv
37+
~/.cache/hatch
38+
key: ${{ runner.os }}-setup-scripts-${{ matrix.python-version }}-${{ hashFiles('setup-scripts/requirements.lock', 'setup-scripts/pyproject.toml') }}
39+
restore-keys: |
40+
${{ runner.os }}-setup-scripts-${{ matrix.python-version }}-
41+
42+
- name: Setup Hatch and UV
43+
run: |
44+
pip install hatch uv
45+
46+
- name: Create Hatch Environment
47+
run: hatch env create env
48+
49+
- name: Install Setup Scripts Dependencies
50+
run: hatch run env:install-script-deps
51+
52+
- name: Lint Setup Scripts
53+
run: hatch run env:lint-scripts
54+
55+
- name: Test Setup Scripts
56+
run: hatch run env:test-scripts

.gitignore

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,81 @@
1+
######### TERRAFORM #########
2+
3+
# Local .terraform directories
4+
**/.terraform
5+
**/.terraform/*
6+
**/.terraform.lock.hcl
7+
8+
# .tfstate files
9+
*.tfstate
10+
*.tfstate.*
11+
12+
# Crash log files
13+
crash.log
14+
crash.*.log
15+
16+
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
17+
# password, private keys, and other secrets. These should not be part of version
18+
# control as they are data points which are potentially sensitive and subject
19+
# to change depending on the environment.
20+
*.tfvars
21+
*.tfvars.json
22+
23+
# Ignore override files as they are usually used to override resources locally and so
24+
# are not checked in
25+
override.tf
26+
override.tf.json
27+
*_override.tf
28+
*_override.tf.json
29+
30+
# Ignore transient lock info files created by terraform apply
31+
.terraform.tfstate.lock.info
32+
33+
# Include override files you do wish to add to version control using negated pattern
34+
# !example_override.tf
35+
36+
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
37+
# example: *tfplan*
38+
39+
# Ignore CLI configuration files
40+
.terraformrc
41+
terraform.rc
42+
43+
######### PYTHON #########
44+
45+
# Byte-compiled / optimized / DLL files
46+
__pycache__/
47+
*.py[cod]
48+
*$py.class
49+
50+
# Distribution / packaging
51+
build/
52+
dist/
53+
*.egg-info/
54+
*.egg
55+
56+
# Unit test / coverage reports
57+
.coverage
58+
.coverage.*
59+
coverage.xml
60+
.pytest_cache/
61+
62+
# Hatch
63+
.hatch/
64+
65+
# Type checking
66+
.mypy_cache/
67+
.dmypy.json
68+
dmypy.json
69+
70+
# Linting
71+
.ruff_cache/
72+
73+
# Virtual environments (in case someone uses them)
74+
.env
75+
.venv
76+
env/
77+
venv/
78+
179
# IDE specific files
280
.idea/
381
.vscode/

Makefile

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
.PHONY: clean env format lint test help lock-deps install upgrade-deps
2+
3+
.DEFAULT_GOAL := help
4+
5+
env:
6+
hatch shell env
7+
8+
install:
9+
hatch run env:install-infra-deps
10+
11+
format:
12+
ruff format test_infrastructure.py
13+
14+
lint:
15+
hatch run env:lint-infra
16+
17+
test:
18+
hatch run env:test-infra
19+
20+
lock-deps:
21+
uv pip compile pyproject.toml -o requirements.lock
22+
23+
upgrade-deps:
24+
uv pip compile --upgrade pyproject.toml -o requirements.lock
25+
26+
clean:
27+
find . -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null || true
28+
find . -type f -name "*.pyc" -delete
29+
find . -type d -name ".pytest_cache" -exec rm -rf {} + 2>/dev/null || true
30+
find . -type d -name ".coverage" -delete
31+
find . -type f -name ".coverage" -delete
32+
find . -type f -name "coverage.xml" -delete
33+
find . -type d -name ".ruff_cache" -exec rm -rf {} + 2>/dev/null || true
34+
find . -type d -name ".mypy_cache" -exec rm -rf {} + 2>/dev/null || true
35+
@echo "IMPORTANT: If you're in a Hatch shell, type 'exit' to leave"
36+
37+
help:
38+
@echo "Available commands:"
39+
@echo " env Create and activate Hatch environment"
40+
@echo " install Install dependencies using Hatch script"
41+
@echo " format Format test_infrastructure.py"
42+
@echo " lint Run linting checks on test_infrastructure.py"
43+
@echo " test Run tests for test_infrastructure.py"
44+
@echo " lock-deps Generate requirements.lock from pyproject.toml"
45+
@echo " upgrade-deps Update and regenerate requirements.lock files with latest dependency versions"
46+
@echo " clean Remove Python cache files"

README.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,103 @@
11
# aws-multi-account
22

33
[![CodeQL](https://github.com/mindbuttergold/template-repo/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/mindbuttergold/aws-multi-account/actions/workflows/github-code-scanning/codeql) [![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/mindbuttergold/aws-multi-account/badge)](https://scorecard.dev/viewer/?uri=github.com/mindbuttergold/aws-multi-account) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/10740/badge)](https://www.bestpractices.dev/projects/10740)
4+
5+
This repository demonstrates the setup of an AWS multi-account model with recommended Organization Units, via Infrastructure as Code (IAC) via Terraform and Terragrunt.
6+
7+
The `./accounts` directory and files at the root of the repository show the core infrastructure setup.
8+
9+
The code in the `./setup-scripts` directory is just to facilitate custom, automated setup of the accounts directories and required IAM resources if desired. This `./setup-scripts` directory can be deleted if desired, and the infra setup will stand on its own with its own workflow, tests, etc.
10+
11+
## Organization Structure
12+
13+
```
14+
AWS Organization Root
15+
16+
├── Management OU
17+
│ └── Management Account (mbg-management)
18+
│ └── Organization-wide IAM and account management
19+
20+
├── Security OU
21+
│ └── Security Account (mbg-security)
22+
│ └── Security tools, GuardDuty, audit logs
23+
24+
├── Infrastructure OU
25+
│ ├── Backup Account (mbg-backup)
26+
│ │ └── Centralized backup and disaster recovery
27+
│ ├── Development Account (mbg-infrastructure-development)
28+
│ │ └── Shared development infrastructure
29+
│ ├── Staging Account (mbg-infrastructure-staging)
30+
│ │ └── Pre-production infrastructure validation
31+
│ └── Production Account (mbg-infrastructure-production)
32+
│ └── Production infrastructure and shared services
33+
34+
├── Workloads OU
35+
│ ├── Development Account (mbg-workloads-development)
36+
│ │ └── Development environment workloads
37+
│ ├── Staging Account (mbg-workloads-staging)
38+
│ │ └── Pre-production workload validation
39+
│ └── Production Account (mbg-workloads-production)
40+
│ └── Production workloads and applications
41+
42+
└── Sandbox OU
43+
└── Sandbox Account (mbg-sandbox)
44+
└── Isolated environment for testing and exploration
45+
```
46+
47+
This structure follows AWS best practices by separating accounts by their unique purposes, to isolate potential impact of security events. The infrastructure setup also employs role-based access control (RBAC) for cross-account login and resource management via IAC.
48+
49+
## AWS Documentation:
50+
51+
- [Benefits of Using Multiple AWS Accounts](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-multiple-aws-accounts.html)
52+
- [Benefits of Using Organizational Units](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/benefits-of-using-organizational-units-ous.html)
53+
- [Best Practices for a Multi-Account Environment](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_best-practices.html)
54+
- [Organizing Your AWS Environment Using Multiple Accounts](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/organizing-your-aws-environment.html)
55+
- [Design Principles for Your Multi-Account Strategy](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/design-principles-for-your-multi-account-strategy.html)
56+
- [Recommended OUs and Accounts](https://docs.aws.amazon.com/whitepapers/latest/organizing-your-aws-environment/recommended-ous-and-accounts.html)
57+
- [AWS Well-Architected Framework](https://docs.aws.amazon.com/wellarchitected/latest/framework/welcome.html)
58+
59+
## Getting Started
60+
61+
If you wish, you can use the setup scripts in this repository to create your own, custom AWS multi-account infrastructure. To do so, carefully follow all steps in the [setup-scripts README](./setup-scripts/README.md).
62+
63+
## Testing
64+
65+
There are basic unit tests that validate the structure and configuration of the AWS multi-account infrastructure setup, without requiring actual AWS credentials or resources.
66+
67+
### Test Dependencies:
68+
- Python 3.10 or later
69+
- [Hatch](https://hatch.pypa.io/latest/install/) - For environment management
70+
- All other deps are the `requirements.lock` file.
71+
72+
### Running Tests
73+
74+
A Makefile is available for easier local development, most of which just uses Hatch scripts from the `pyproject.yaml` file.
75+
You can choose to use the makefile commands, or you can use the Hatch script commands directly that are noted in the Makefile.
76+
77+
```zsh
78+
# Create and activate a virtual Hatch environment
79+
80+
make env
81+
82+
# Install the required dependencies
83+
84+
make install
85+
86+
# Run tests
87+
88+
make test
89+
90+
# Run linting
91+
92+
make lint
93+
```
94+
95+
## Cost
96+
97+
This setup should not incur costs to use. AWS does not charge you for creating Organizational Units or accounts. Rather, you incur charges based on resources used within accounts.
98+
99+
The setup scripts will create an S3 bucket and IAM roles, which should fall within the free-tier level.
100+
101+
## License
102+
103+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
locals {
2+
account_name = "mbg-backup"
3+
account_id = "222222222222"
4+
organizational_unit = "Infrastructure"
5+
aws_region = "us-west-2"
6+
terraform_admin_role_name = "TerraformAdminRole"
7+
s3_backend_bucket_name = "mbg-terraform-state"
8+
}

accounts/mbg-backup/main.tf

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Generated by Terragrunt. Sig: nIlQXj57tbuaRZEa
2+
resource "aws_iam_account_alias" "alias" {
3+
account_alias = var.account_name
4+
}

0 commit comments

Comments
 (0)