Multi-Account Strategy
DocuStack uses AWS Organizations to implement a multi-account strategy that provides environment isolation, security boundaries, and compliance controls.
Why Multi-Account?
| Benefit | Description |
|---|---|
| Security Isolation | Compromise in dev doesn't affect prod |
| Compliance Boundaries | Separate audit trails per environment |
| Cost Allocation | Clear cost attribution per account |
| Blast Radius Reduction | Limit impact of misconfigurations |
| Team Autonomy | Different teams can own different accounts |
Organizational Structure
┌─────────────────────────────────────────────────────────────────────────────┐
│ AWS Organization │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Management Account │ │
│ │ - AWS Organizations │ │
│ │ - Service Control Policies (SCPs) │ │
│ │ - CloudTrail (Organization Trail) │ │
│ │ - AWS Config (Aggregator) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────┼─────────────────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐ │
│ │ Security OU │ │ Sandbox OU │ │ Workloads OU │ │
│ │ │ │ │ │ │ │
│ │ • Log Archive │ │ • Developer │ │ • Dev │ │
│ │ • Audit │ │ Sandboxes │ │ • Staging │ │
│ │ │ │ • No PHI allowed │ │ • Production │ │
│ └─────────────────────┘ └─────────────────────┘ └─────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Account Purposes
| Account | OU | Purpose | Key Resources |
|---|---|---|---|
| Management | Root | Organization governance | SCPs, CloudTrail, Config Aggregator |
| Log Archive | Security | Immutable audit logs | S3 (CloudTrail, VPC Flow Logs) |
| Audit | Security | Security monitoring | Security Hub, GuardDuty, Config |
| Dev | Workloads | Development environment | Full stack, Terrateam, test data |
| Staging | Workloads | Pre-production testing | Full stack, integration tests |
| Production | Workloads | Live workloads | Full stack, production data, Multi-AZ |
Service Control Policies (SCPs)
SCPs provide preventive guardrails that cannot be bypassed, even by account administrators.
| SCP | Target | Effect |
|---|---|---|
| Region Deny | All accounts | Only us-east-1 allowed |
| Require S3 Encryption | Workloads OU | Block unencrypted S3 uploads |
| Protect CloudTrail | All accounts | Prevent trail deletion/modification |
| Protect Log Archive | Log Archive | Deny object deletion |
| Deny Public S3 | Workloads OU | Block public bucket policies |
SCP Hierarchy
Root (Organization)
└── SCP: Region Deny (only us-east-1)
└── SCP: Protect CloudTrail
Security OU
└── SCP: Protect Log Archive
└── Deny: s3:DeleteObject, s3:DeleteBucket
└── Deny: cloudtrail:StopLogging, cloudtrail:DeleteTrail
Workloads OU
└── SCP: Require S3 Encryption
└── Deny: s3:PutObject without encryption header
└── SCP: Deny Public S3
└── Deny: s3:PutBucketPublicAccessBlock (if enabling public)
Example: S3 Encryption Required SCP
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedS3Uploads",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption": "true"
}
}
}
]
}
Bootstrap Strategy
Each account needs its own bootstrap (S3 bucket + DynamoDB table) for Terraform state.
Why Per-Account Bootstrap?
- State lives in the same account as resources (security isolation)
- Each account is independent (can delete staging without affecting prod)
- Separate audit trails per account
- No cross-account IAM complexity
Bootstrap Pattern
Dev Account (216482851263)
├── Bootstrap → S3: docustack-terraform-state-216482851263
└── Resources → VPC, ECS, RDS (state stored in dev bucket)
Staging Account (staging-id)
├── Bootstrap → S3: docustack-terraform-state-staging-id
└── Resources → VPC, ECS, RDS (state stored in staging bucket)
Production Account (prod-id)
├── Bootstrap → S3: docustack-terraform-state-prod-id
└── Resources → VPC, ECS, RDS (state stored in prod bucket)
Management Account (348665872333)
├── Bootstrap → S3: docustack-terraform-state-348665872333
└── Resources → SCPs, Org CloudTrail (state stored in mgmt bucket)
Bootstrap Cost
| Resource | Cost |
|---|---|
| S3 Bucket | ~$0.25/month |
| DynamoDB Table | ~$0.25/month |
| Per Account | ~$0.50/month |
| 4 Accounts Total | ~$2.00/month |
Process for New Accounts
Step-by-Step
1. Create AWS Account
# Via AWS Organizations or Control Tower Account Factory
# Get the new account ID
2. Configure AWS Access
export AWS_PROFILE=docustack-staging-admin
aws sts get-caller-identity # Verify account ID
3. Create Account Config
# infrastructure-live/staging/account.hcl
locals {
account_name = "staging"
account_id = "555666777888"
}
4. Run Bootstrap
cd infrastructure-live/bootstrap
terragrunt init
terragrunt apply
# Creates S3 bucket and DynamoDB table
5. Deploy Environment Resources
cd ../staging/us-east-1/vpc
terragrunt init
terragrunt apply
Security Benefits
Attack Scenario Comparison
Centralized State (Bad):
1. Developer laptop compromised
2. Has AWS creds for management account (for state access)
3. Attacker reads ALL state files (dev, staging, prod)
4. Attacker learns RDS endpoints, passwords, VPC structure for PROD
5. Pivots to production environment
Distributed State (Good):
1. Developer laptop compromised
2. Has AWS creds for DEV account only
3. Attacker reads DEV state files only
4. Attacker learns dev RDS endpoint, dev passwords
5. CANNOT pivot to production (no credentials)