Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions .github/workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,70 @@ Follow the trigger and deployment rules from docs/pipeline-rules.md:
- Prod requires change_request input
```

## Caching Strategy

Use `actions/cache@v4` to dramatically reduce pipeline time:

### Terraform Cache

```yaml
- name: Cache Terraform providers
uses: actions/cache@v4
with:
path: ~/.terraform.d/plugin-cache
key: terraform-${{ runner.os }}-${{ hashFiles('**/.terraform.lock.hcl') }}
restore-keys: terraform-${{ runner.os }}-

- name: Terraform Init
run: terraform init
env:
TF_PLUGIN_CACHE_DIR: ~/.terraform.d/plugin-cache
```

### Ansible Cache

```yaml
- name: Cache Ansible collections
uses: actions/cache@v4
with:
path: ~/.ansible/collections
key: ansible-${{ hashFiles('**/requirements.yml') }}
restore-keys: ansible-

- name: Install collections
run: ansible-galaxy collection install -r requirements.yml
env:
ANSIBLE_COLLECTIONS_PATH: ~/.ansible/collections
```

### S3 Backend Cache (Cross-Runner)

For persistent caching across all runners:

```yaml
env:
ARTIFACT_BUCKET: ${{ vars.ARTIFACT_BUCKET }}

steps:
- name: Download cache from S3
run: |
CACHE_KEY="terraform-$(sha256sum .terraform.lock.hcl | cut -d' ' -f1)"
aws s3 cp "s3://${ARTIFACT_BUCKET}/${CACHE_KEY}.tar.gz" /tmp/cache.tar.gz || true
if [[ -f /tmp/cache.tar.gz ]]; then
mkdir -p ~/.terraform.d/plugin-cache
tar -xzf /tmp/cache.tar.gz -C ~/.terraform.d/
fi

- name: Upload cache to S3
if: always()
run: |
CACHE_KEY="terraform-$(sha256sum .terraform.lock.hcl | cut -d' ' -f1)"
tar -czf /tmp/cache.tar.gz -C ~/.terraform.d/ plugin-cache/ 2>/dev/null || true
aws s3 cp /tmp/cache.tar.gz "s3://${ARTIFACT_BUCKET}/${CACHE_KEY}.tar.gz" || true
```

See [docs/caching.md](../docs/caching.md) for complete details.

## Files to Generate

| File | Purpose |
Expand Down
88 changes: 64 additions & 24 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,59 @@

Architecture patterns for IaC (Terraform, Ansible, CloudFormation) pipelines on AWS.

## AWS Account Model
## OU Hierarchy

```
┌─────────────────────────────────┐ ┌─────────────────────────────────┐
│ NON-PROD ACCOUNT │ │ PROD ACCOUNT │
│ │ │ │
│ 10-dev 20-qat │ │ 40-stg 70-prod 90-dr │
│ │ │ │
│ ca-central-1 │ │ ca-central-1 / ca-west-1 (DR) │
└─────────────────────────────────┘ └─────────────────────────────────┘
Root
├── PLT OU (Platform)
│ └── PLT-Runner Account
└── WKL OU (Workloads)
├── WKL-NPD OU (NonProd)
│ ├── SBX Account
│ ├── DEV Account
│ └── QAT Account
└── WKL-PRD OU (Prod)
├── STG Account
├── PRD Account
└── DR Account
```

**OU Code Reference:**

| Code | Full Name | Purpose |
| ----------- | ----------------- | -------------------------------- |
| **PLT** | Platform | CI/CD runners and shared tooling |
| **WKL** | Workloads | Application environments |
| **WKL-NPD** | Workloads-NonProd | Development and testing |
| **WKL-PRD** | Workloads-Prod | Production and DR |

## Core Patterns

### 1. Role Chaining
### 1. Cross-Account Role Chaining

```mermaid
flowchart LR
A[CI/CD Runner] --> B[cicd-oidc-role<br/>minimal perms]
B --> C[cicd-admin-role<br/>full perms]
C --> D[Deploy]
A[CI/CD Platform] --> B[OIDC Provider]
B --> C[cicd-runner-role<br/>PLT OU]
C --> D[cicd-deploy-role<br/>WKL Accounts]
D --> E[Deploy]
```

**Why:** OIDC handles auth, admin role handles permissions. See
**Why:** Runner in PLT assumes deploy roles in WKL accounts. See
[docs/authentication.md](docs/authentication.md)

### 2. Pipeline Triggers
### 2. Two-StackSet Deployment

| StackSet | Target OU | Creates |
| ------------------- | --------- | ------------------------------ |
| PLT Runner StackSet | PLT OU | `cicd-runner-role` + OIDC |
| WKL Deploy StackSet | WKL OU | `cicd-deploy-role` per account |

New accounts added to WKL automatically receive deploy roles.

### 3. Pipeline Triggers

| Event | Runs? | Why |
| ------------------- | ------ | ----------------- |
Expand All @@ -39,20 +65,33 @@ flowchart LR

See [docs/pipeline-rules.md](docs/pipeline-rules.md)

### 3. Environment Progression
### 4. Environment Progression

```
NON-PROD ACCOUNT PROD ACCOUNT
──────────────── ────────────
10-dev → 20-qat 40-stg → 70-prod → 90-dr
requires CR
WKL-NPD OU WKL-PRD OU
────────── ──────────
05-sbx → 10-dev → 20-qat 40-stg → 70-prod → 90-dr
requires CR
```

See [docs/conventions.md](docs/conventions.md)

---

## StackSet Templates

```
cloudformation/stacksets/
├── plt/ # Deploy to PLT OU
│ ├── 00-oidc-provider-github.yaml
│ └── 10-iam-runner-role.yaml
└── wkl/ # Deploy to WKL OU
├── 15-iam-deploy-role.yaml
└── 20-terraform-state-backend.yaml
```

## Generate Pipelines

Use AI with your org context + these docs:
Expand All @@ -61,8 +100,8 @@ Use AI with your org context + these docs:
Generate a [GitHub/GitLab/Jenkins] pipeline for Terraform:
- Follow docs/pipeline-rules.md for triggers
- Follow docs/authentication.md for role chaining
- 2 AWS accounts: non-prod, prod
- 5 environments: dev, qat (non-prod) | stg, prod, dr (prod account)
- PLT account for runners, WKL accounts for deployments
- 6 environments: sbx, dev, qat (WKL-NPD) | stg, prod, dr (WKL-PRD)
- Regions: ca-central-1, ca-west-1 (DR)
```

Expand All @@ -77,5 +116,6 @@ Generate a [GitHub/GitLab/Jenkins] pipeline for Terraform:
## Docs

- [Pipeline Rules](docs/pipeline-rules.md) - triggers, deployment patterns
- [Authentication](docs/authentication.md) - role chaining
- [Conventions](docs/conventions.md) - naming standards
- [Authentication](docs/authentication.md) - cross-account role chaining
- [Conventions](docs/conventions.md) - OU and naming standards
- [Caching](docs/caching.md) - artifact caching for faster pipelines
161 changes: 126 additions & 35 deletions cloudformation/README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,149 @@
# CloudFormation
# CloudFormation StackSets

Placeholder directory for CloudFormation templates.
Foundation resources deployed via StackSets from management account.

## Generate Your CloudFormation
## OU-Targeted Deployment

Use AI to generate CloudFormation specific to your organization. Provide:

1. **Your org context** - naming conventions, AWS accounts, regions
2. **The patterns from** `docs/conventions.md`
3. **Your specific requirements** - StackSets, nested stacks
```
cloudformation/stacksets/
├── plt/ # Deploy to PLT OU
│ ├── 00-oidc-provider-github.yaml # GitHub OIDC provider
│ ├── 10-iam-runner-role.yaml # Runner role (assumes WKL deploy roles)
│ └── 25-cicd-artifacts.yaml # Artifact & cache bucket
└── wkl/ # Deploy to WKL OU
├── 15-iam-deploy-role.yaml # Deploy role (trusts PLT runner)
└── 20-terraform-state-backend.yaml # State bucket + DynamoDB lock
```

## StackSets for Foundation
## Deployment Order

CloudFormation StackSets deploy foundation resources across accounts:
```mermaid
flowchart LR
A[1. OIDC Provider<br/>→ PLT] --> B[2. Runner Role<br/>→ PLT]
B --> C[3. Artifact Bucket<br/>→ PLT]
C --> D[4. Deploy Role<br/>→ WKL]
D --> E[5. State Backend<br/>→ WKL]
```

## StackSet Configuration

### PLT OU StackSets

```bash
# 1. Deploy OIDC Provider to PLT OU
aws cloudformation create-stack-set \
--stack-set-name plt-oidc-provider \
--template-body file://stacksets/plt/00-oidc-provider-github.yaml \
--parameters ParameterKey=GitHubOrganization,ParameterValue=YOUR_ORG \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false

aws cloudformation create-stack-instances \
--stack-set-name plt-oidc-provider \
--deployment-targets OrganizationalUnitIds=ou-xxxx-plt \
--regions ca-central-1

# 2. Deploy Runner Role to PLT OU
aws cloudformation create-stack-set \
--stack-set-name plt-runner-role \
--template-body file://stacksets/plt/10-iam-runner-role.yaml \
--parameters ParameterKey=GitHubOrganization,ParameterValue=YOUR_ORG \
--capabilities CAPABILITY_NAMED_IAM \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false

aws cloudformation create-stack-instances \
--stack-set-name plt-runner-role \
--deployment-targets OrganizationalUnitIds=ou-xxxx-plt \
--regions ca-central-1

# 3. Deploy Artifact Bucket to PLT OU (cache storage)
aws cloudformation create-stack-set \
--stack-set-name plt-cicd-artifacts \
--template-body file://stacksets/plt/25-cicd-artifacts.yaml \
--parameters ParameterKey=OrganizationPrefix,ParameterValue=YOUR_ORG \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false

aws cloudformation create-stack-instances \
--stack-set-name plt-cicd-artifacts \
--deployment-targets OrganizationalUnitIds=ou-xxxx-plt \
--regions ca-central-1
```
stacksets/
├── 00-oidc-provider-github.yaml # OIDC for GitHub Actions
├── 10-iam-cicd-roles.yaml # cicd-oidc-role, cicd-admin-role
└── 20-terraform-state-backend.yaml # S3 + DynamoDB for TF state

### WKL OU StackSets

```bash
# 4. Deploy Deploy Role to WKL OU (auto-deploys to WKL-NPD and WKL-PRD)
aws cloudformation create-stack-set \
--stack-set-name wkl-deploy-role \
--template-body file://stacksets/wkl/15-iam-deploy-role.yaml \
--parameters ParameterKey=RunnerAccountId,ParameterValue=PLT_ACCOUNT_ID \
--capabilities CAPABILITY_NAMED_IAM \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false

aws cloudformation create-stack-instances \
--stack-set-name wkl-deploy-role \
--deployment-targets OrganizationalUnitIds=ou-xxxx-wkl \
--regions ca-central-1

# 5. Deploy State Backend to WKL OU
aws cloudformation create-stack-set \
--stack-set-name wkl-terraform-state \
--template-body file://stacksets/wkl/20-terraform-state-backend.yaml \
--parameters \
ParameterKey=OrganizationPrefix,ParameterValue=YOUR_ORG \
ParameterKey=RunnerAccountId,ParameterValue=PLT_ACCOUNT_ID \
--capabilities CAPABILITY_NAMED_IAM \
--permission-model SERVICE_MANAGED \
--auto-deployment Enabled=true,RetainStacksOnAccountRemoval=false

aws cloudformation create-stack-instances \
--stack-set-name wkl-terraform-state \
--deployment-targets OrganizationalUnitIds=ou-xxxx-wkl \
--regions ca-central-1 ca-west-1
```

## Example Prompt for AI
## Automatic Onboarding

With `--auto-deployment Enabled=true`, when new accounts are added to WKL OU:

1. StackSet automatically deploys `cicd-deploy-role` to the new account
2. StackSet automatically deploys state backend to the new account
3. Trust policy already references PLT runner role ARN
4. New account immediately ready for CI/CD deployments

## Role Trust Relationship

```
PLT Account WKL Accounts
─────────── ────────────
cicd-runner-role ──────────────> cicd-deploy-role
│ │
├─ OIDC trust (GitHub) ├─ Trusts PLT runner role ARN
└─ Can assume WKL deploy roles └─ Full infra permissions
```
Generate CloudFormation StackSets for CI/CD foundation with:
- Org: <your-org>
- AWS accounts: non-prod (111111111111), prod (222222222222)
- Regions: ca-central-1 (primary), ca-west-1 (DR)
- GitHub org: <github-org>

Include:
1. OIDC provider for GitHub Actions
2. Role chaining: cicd-oidc-role -> cicd-admin-role
3. Terraform state backend (S3 + DynamoDB)
## OU IDs

Follow numbered file naming from docs/conventions.md
Deploy via StackSets from management account
Get your OU IDs:

```bash
aws organizations list-organizational-units-for-parent \
--parent-id r-xxxx # root ID
```

Replace `ou-xxxx-plt` and `ou-xxxx-wkl` with your actual OU IDs.

## File Naming Convention

| Range | Layer |
| ----- | ------------------ |
| 00-09 | Identity providers |
| 10-19 | IAM roles/policies |
| 20-29 | State management |
| 15-19 | Deploy roles |
| 20-29 | State & artifacts |
| 30-39 | Network foundation |
| 40-49 | Security baseline |

## Deployment Order

StackSets should be deployed in numbered order:

1. `00-*` - OIDC providers (prerequisite for role assumption)
2. `10-*` - IAM roles (depends on OIDC)
3. `20-*` - State backends (can use roles)
Loading