Skip to main content

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?

BenefitDescription
Security IsolationCompromise in dev doesn't affect prod
Compliance BoundariesSeparate audit trails per environment
Cost AllocationClear cost attribution per account
Blast Radius ReductionLimit impact of misconfigurations
Team AutonomyDifferent 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

AccountOUPurposeKey Resources
ManagementRootOrganization governanceSCPs, CloudTrail, Config Aggregator
Log ArchiveSecurityImmutable audit logsS3 (CloudTrail, VPC Flow Logs)
AuditSecuritySecurity monitoringSecurity Hub, GuardDuty, Config
DevWorkloadsDevelopment environmentFull stack, Terrateam, test data
StagingWorkloadsPre-production testingFull stack, integration tests
ProductionWorkloadsLive workloadsFull stack, production data, Multi-AZ

Service Control Policies (SCPs)

SCPs provide preventive guardrails that cannot be bypassed, even by account administrators.

SCPTargetEffect
Region DenyAll accountsOnly us-east-1 allowed
Require S3 EncryptionWorkloads OUBlock unencrypted S3 uploads
Protect CloudTrailAll accountsPrevent trail deletion/modification
Protect Log ArchiveLog ArchiveDeny object deletion
Deny Public S3Workloads OUBlock 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

ResourceCost
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)