Remote State Boundaries
Overview
Terraform state should be isolated to reduce blast radius and enable independent deployments. This skill covers state organization patterns for multi-environment, multi-account setups.
mermaid
graph TB
subgraph "State Organization"
subgraph "By Environment"
DevState[dev/terraform.tfstate]
StagingState[staging/terraform.tfstate]
ProdState[prod/terraform.tfstate]
end
subgraph "By Layer"
Foundation[foundation/terraform.tfstate]
Platform[platform/terraform.tfstate]
Workloads[workloads/terraform.tfstate]
end
end
State Isolation Strategies
| Strategy | Use Case | Blast Radius |
|---|---|---|
| Monolithic | Small projects | High |
| Per-Environment | Single team | Medium |
| Per-Layer | Platform team | Low |
| Per-Layer-Per-Env | Enterprise | Very Low |
Best Practices
- •Never share state across accounts - Security boundary
- •Separate by blast radius - What can break together?
- •Use locking - DynamoDB for S3 backend
- •Limit access - Least privilege to state
- •Encrypt state - Contains sensitive values
- •Version state bucket - Recovery from corruption
Example 1: Terraform - S3 Backend with Isolation
State per environment and layer with proper locking.
📁 Location: terraform/examples/remote-state/
Backend Configuration
hcl
# backend.tf
terraform {
backend "s3" {
bucket = "mycompany-terraform-state"
key = "layers/foundation/prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks"
# Workspace-based key pattern
workspace_key_prefix = "env"
}
}
State Bucket Setup
hcl
# state-bucket/main.tf
resource "aws_s3_bucket" "state" {
bucket = "${var.org_name}-terraform-state-${data.aws_caller_identity.current.account_id}"
}
resource "aws_s3_bucket_versioning" "state" {
bucket = aws_s3_bucket.state.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
bucket = aws_s3_bucket.state.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.state.arn
}
}
}
resource "aws_dynamodb_table" "locks" {
name = "terraform-locks"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Example 2: CDK - Isolated Pipelines
CDK stacks with isolated state per stage.
📁 Location: cdk/examples/remote-state/
Pipeline Stages
typescript
// Each environment has isolated synth/deploy
const pipeline = new pipelines.CodePipeline(this, 'Pipeline', {
synth: new pipelines.ShellStep('Synth', {
commands: ['npm ci', 'npm run build', 'npx cdk synth'],
}),
});
// Dev stage - independent state
pipeline.addStage(new MyApplicationStage(this, 'Dev', {
env: { account: DEV_ACCOUNT, region: 'us-east-1' },
}));
// Prod stage - requires manual approval
pipeline.addStage(new MyApplicationStage(this, 'Prod', {
env: { account: PROD_ACCOUNT, region: 'us-east-1' },
}), {
pre: [new pipelines.ManualApprovalStep('PromoteToProd')],
});
Naming Convention
code
s3://{org}-terraform-state-{account}/
├── foundation/{env}/terraform.tfstate
├── platform/{env}/terraform.tfstate
└── workloads/{app}/{env}/terraform.tfstate
Validation Checklist
- • State bucket versioning enabled
- • State encrypted with KMS
- • DynamoDB locking configured
- • State access restricted (IAM policies)
- • Separate state per environment
- • Cross-account access via assume role
Related Skills
- •Layered Stacks - State per layer
- •GitOps Workflow - State in CI/CD
- •Disaster Recovery - State backup