Files
claude-code-skills-reference/terraform-skill/references/multi-env-isolation.md
daymade 87221d94d5 feat(pdf-creator): add theme system + Chrome backend; add terraform-skill draft
- pdf-creator v1.2.0: theme system (default/warm-terra), dual backend
  (weasyprint/chrome auto-detect), argparse CLI, extracted CSS to themes/
- terraform-skill: operational traps from real deployments (provisioner
  timing, DNS duplication, multi-env isolation, pre-deploy validation)
- asr-transcribe-to-text: add security scan marker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 23:33:03 +08:00

4.1 KiB

Multi-Environment Isolation Checklist

When creating a second Terraform environment (staging, lab, etc.) in the same cloud account alongside production, every item below must be verified. Skip one and you get silent name collisions or cross-contamination.

Terraform state isolation

Two environments MUST use different state paths. Same OSS/S3 bucket is fine — different prefix isolates completely:

# production
backend "oss" {
  bucket = "myproject-terraform-state"
  prefix = "environments/production"
}

# staging
backend "oss" {
  bucket = "myproject-terraform-state"  # same bucket OK
  prefix = "environments/staging"       # different prefix = isolated state
}

Verification: terraform state list in one environment must show ZERO resources from the other.

Resource naming collision matrix

Grep every .tf file for hardcoded names. Every globally-unique resource will collide.

Must rename (apply will fail)

Resource Uniqueness scope Fix pattern
SSH key pair (key_pair_name) Region "${env}-deploy"
SLS log project (project_name) Account "${env}-logs"
CloudMonitor contact (alarm_contact_name) Account "${env}-ops"
CloudMonitor contact group Account "${env}-ops"

Should rename (won't fail but causes confusion)

Resource Issue if same name
Security group name Two SGs with same name in same VPC, can't tell apart in console
ECS instance name/hostname Two instances named myapp-spot in console
Data disk name Same in disk list
Auto snapshot policy name Same in policy list
SLS machine group name Logs from both instances land in same group

Pattern: Use a module name variable

# production main.tf
module "app" {
  source = "../../modules/spot-with-data-disk"
  name   = "production-spot"  # flows to instance_name, disk_name, snapshot_policy_name
}

# staging main.tf
module "app" {
  source = "../../modules/spot-with-data-disk"
  name   = "staging-spot"     # all child resource names auto-isolated
}

DNS record isolation

The duplication trap

Two Terraform environments creating A records for @ (root) in the same Cloudflare zone:

  • Each gets its own Cloudflare record ID (independent)
  • Cloudflare now has TWO A records for the same domain
  • DNS round-robins between the two IPs
  • ~50% of traffic goes to the wrong instance

Correct patterns

Pattern A: Subdomain isolation (recommended for staging/lab):

# Production: root domain records
resource "cloudflare_dns_record" "prod" {
  name = "@"  # gpt-6.pro
}

# Staging: subdomain records only
resource "cloudflare_dns_record" "staging" {
  name = "staging"  # staging.gpt-6.pro
}

Pattern B: Separate zones (for fully independent deployments): Each environment gets its own domain/zone. No shared Cloudflare zone IDs.

Pattern C: One environment owns DNS (production): Only production has DNS resources. Other environments access via IP only.

Destroy safety

When one environment is destroyed:

  • Its DNS records are deleted (by their specific Cloudflare record IDs)
  • Other environments' DNS records are NOT affected
  • Verify before destroy: Compare DNS record IDs between environments:
    terraform state show 'cloudflare_dns_record.app["root"]' | grep "^id"
    
    IDs must be different.

Shared resources (safe to share)

These are referenced but NOT managed by the second environment:

Resource Why safe
VPC / VSwitch Referenced by ID, not created
Cloudflare zone ID Referenced, records are independent
OSS state bucket Different prefix = different state
SSH public key content Same key, different key pair resource
Cloud provider credentials Same account, different resources

Makefile pattern for multi-environment

ENV ?= production
ENV_DIR := environments/$(ENV)

init: ; cd $(ENV_DIR) && terraform init
plan: ; cd $(ENV_DIR) && terraform plan -out=tfplan
apply: ; cd $(ENV_DIR) && terraform apply tfplan
drift: ; cd $(ENV_DIR) && terraform plan -detailed-exitcode

Usage: make plan ENV=staging