---
title: "Enterprise Terraform: State Locking, Directory Segregation, and CI/CD"
description: "Production patterns for managing Terraform at scale: remote state locking with DynamoDB, environment boundary segregation, and automated CI/CD PR planning."
canonical: "https://zainahmed.net/blog/terraform-best-practices"
published: "2023-12-10"
---

# Enterprise Terraform: State Locking, Directory Segregation, and CI/CD

> Author: Zain Ahmed
> Published: 2023-12-10
> Read Time: 2 min read
> Category: Infrastructure as Code
> Tags: Terraform, IaC, DevOps, AWS
> Canonical URL: https://zainahmed.net/blog/terraform-best-practices

## Excerpt
Production patterns for managing Terraform at scale: remote state locking with DynamoDB, environment boundary segregation, and automated CI/CD PR planning.

---

Adopting Infrastructure as Code (IaC) across enterprise engineering teams requires strict operational discipline. Without state locking, directory segregation, and automated plan approval gates, concurrent applies corrupt state files, drift goes undetected, and production infrastructure becomes fragile. Here are verified architecture patterns for managing production Terraform environments.

## 1. Remote State Management & Distributed Locking

Local state storage (`terraform.tfstate`) invites disastrous race conditions and leaks sensitive variables to developer laptops.

- **Encrypted S3 Backend:** Store state files in an Amazon S3 bucket with server-side encryption (`AES256` or AWS KMS) and versioning permanently enabled. Versioning provides an immutable audit trail and allows instant restoration if state corruption occurs.
- **DynamoDB State Locking:** Configure a dedicated Amazon DynamoDB table with a `LockID` primary key. Every `terraform plan` and `terraform apply` acquires an exclusive distributed lock, halting concurrent operations from team members or automated CI runners.
- **Access Control:** Restrict backend S3 bucket and DynamoDB table IAM permissions strictly to deployment role ARNs. Developers should not have direct read or write access to production state buckets.

## 2. Environment Segregation & Blast Radius Containment

Monolithic Terraform configurations (where the entire corporate infrastructure resides in a single `main.tf`) create dangerous blast radii where a small typo in a staging subnet can destroy a production database.

```txt
terraform/
├── modules/
│   ├── vpc/
│   └── eks-cluster/
└── environments/
    ├── dev/
    │   ├── main.tf
    │   └── backend.tf (isolated dev.tfstate)
    └── prod/
        ├── main.tf
        └── backend.tf (isolated prod.tfstate)
```

- **Separate State per Environment:** Isolate environments (`dev`, `staging`, `prod`) into separate directories with independent backend configurations and state files. An accidental destroy command in `dev` cannot touch `prod`.
- **Reusable Versioned Modules:** Package infrastructure patterns into reusable Git-tagged modules. Pin module sources to exact release versions (`?ref=v2.4.1`) to prevent upstream changes from unexpectedly modifying running environments.

## 3. Automated CI/CD Execution & Plan Review Gates

Running `terraform apply` from local developer workstations introduces configuration drift, uncommitted changes, and privilege escalation vulnerabilities:

- **Automated PR Planning:** Configure GitHub Actions to automatically run `terraform plan` on every pull request. The formatted output is posted directly as a PR comment, enabling peer review of exact resource additions, modifications, and destructions.
- **Strict Plan Execution:** Pass the generated plan binary (`-out=tfplan`) from the PR build directly to the apply job upon merge to `main`. This guarantees that the exact reviewed changes - and only those changes - are applied to production.
- **Automated Policy-as-Code:** Run static security checks using Trivy, tfsec, or Open Policy Agent (OPA) before planning. Reject pull requests that attempt to open SSH (`0.0.0.0/0`) or provision unencrypted storage volumes.

---

## Related Endpoints & Navigation
- **All Articles**: [https://zainahmed.net/blog](https://zainahmed.net/blog)
- **Author Profile**: [https://zainahmed.net/about](https://zainahmed.net/about)
- **Machine-Readable LLM Manifest**: [https://zainahmed.net/llms.txt](https://zainahmed.net/llms.txt)
- **RSS Feed**: [https://zainahmed.net/feed.xml](https://zainahmed.net/feed.xml)
