- 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>
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:
IDs must be different.
terraform state show 'cloudflare_dns_record.app["root"]' | grep "^id"
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