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

131 lines
4.1 KiB
Markdown

# 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:
```hcl
# 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
```hcl
# 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):
```hcl
# 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:
```bash
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
```makefile
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`