---
title: "Terraform State Management: Kill Local State | CloudGuys Blog"
description: "Why committing .tfstate to Git is a security disaster. A guide to setting up robust S3+DynamoDB remote backends with encryption and locking."
url: "https://cloudguys.io/blog/terraform-state-management"
language: "en"
image: "https://cloudguys.io/_astro/cover.8dB-ACPc.png"
published: "2026-05-03T00:00:00.000Z"
modified: "2026-05-14T00:00:00.000Z"
---

ENGINEERING NOTES / DEVOPS

# Terraform State Management: Kill Local State

Why committing .tfstate to Git is a security disaster. A guide to setting up robust S3+DynamoDB remote backends with encryption and locking.

CloudOpsPro Team · · · May 3, 2026 · · · 2 min

![Terraform State Management: Kill Local State](https://cloudguys.io/_astro/cover.8dB-ACPc_Z276S5y.webp)

**Author:** CloudOpsPro Engineering Team **Category:** DevOps, IaC, Security **Date:** December 12, 2025

We still see it in 2025: A `terraform.tfstate` file committed to a Git repository. This is the DevOps equivalent of storing your credit card number on a sticky note in a public park.

Terraform State is the “brain” of your infrastructure. If it is lost, corrupted, or exposed, it is Game Over.

## 1\. Why Git Storage is Fatal

-   \*\*Secrets in Plain Text: \*\*Terraform state files store the *results* of resources. If you create an RDS database and pass a password, that password is stored **in plain text** in the state file. *Commit to Git -> Secrets are compromised forever.*
-   \*\*No Locking: \*\*Two engineers run `terraform apply` at the same time. Git doesn’t prevent this. They overwrite each other’s changes. *Result: Corrupted infrastructure and undefined state.*
-   \*\*Manual Errors: \*\*“Oops, I forgot to pull before applying.” Now your local state is out of sync with reality.

## 2\. The Solution: Remote Backends with Locking

The extensive standard is **S3 + DynamoDB** (on AWS).

-   **S3 Bucket:** Stores the state file (Versioning enabled).
-   **DynamoDB Table:** Handles the **Locking**.

### Configuration Example

```hcl
# backend.tf

terraform {
  backend "s3" {
    bucket         = "company-terraform-state-prod"
    key            = "vpc/terraform.tfstate"
    region         = "us-east-1"

    # The Lock Table
    dynamodb_table = "terraform-lock-table"

    # Encryption works by default, but explicit is better
    encrypt        = true
  }
}
```

Now, when Engineer A runs `terraform plan`, Terraform writes a Lock ID to DynamoDB. If Engineer B tries to run `apply`, Terraform checks DynamoDB, sees the lock, and errors out: `Error: Error acquiring the state lock`.

**Safety secured.**

## 3\. Best Practices for State Security

Since the state file contains secrets (RDS passwords, IAM keys, TLS private keys):

1.  **Encryption at Rest:** Ensure the S3 bucket has Server-Side Encryption (SSE-S3 or KMS) enabled.
2.  **Access Control:** Only the CI/CD role and top-level admins should have `s3:GetObject` on the state bucket. Developers generally don’t need raw state access; they just need to see the Plan output.
3.  **Versioning:** Enable S3 Versioning. If a `terraform apply` corrupts your state file, you can roll back the S3 object to the previous version to recover.

## 4\. Terraform Cloud / Spacelift

If managing S3 backends feels too manual, managed backends like **Terraform Cloud** or **Spacelift** are excellent alternatives. They handle:

-   State hosting
-   Locking
-   History/Diffs of state
-   Run triggers

**Verdict:**

-   **Small/Mid Teams:** S3 + DynamoDB is fine (and free/cheap).
-   **Large Enterprise:** Use a managed backend for Audit logs and RBAC.

Whatever you do, add `*.tfstate` to your `.gitignore` **right now**.

#Terraform · #Security · #DevOps

A FRESH PERSPECTIVE ON YOUR CLOUD

## Great engineering starts  
with a good conversation.

Let’s talk about what’s working, what’s slowing you down, and what comes next.

[Talk to an engineer ↗](mailto:hello@agrohi.com?subject=CloudGuys%20assessment%20enquiry)

## Structured data

```json
[
  {
    "@context": "https://schema.org",
    "@type": "Organization",
    "@id": "https://cloudguys.io/#organization",
    "name": "CloudGuys",
    "url": "https://cloudguys.io/",
    "logo": {
      "@type": "ImageObject",
      "url": "https://cloudguys.io/assets/logo.png",
      "width": 512,
      "height": 512
    },
    "image": "https://cloudguys.io/assets/og-image.png",
    "description": "Security assessments, cloud architecture reviews, and practical remediation across AWS, Google Cloud, Azure, Kubernetes, and infrastructure as code.",
    "email": "hello@agrohi.com",
    "slogan": "Know your risks. Build a stronger cloud.",
    "areaServed": "Worldwide",
    "knowsAbout": [
      "DevOps",
      "Kubernetes",
      "Terraform",
      "Cloud migration",
      "Cloud cost optimization",
      "GitOps",
      "Site reliability engineering",
      "Kubernetes dashboard",
      "AI SRE",
      "Kubernetes troubleshooting",
      "AWS",
      "Google Cloud",
      "Azure"
    ],
    "contactPoint": {
      "@type": "ContactPoint",
      "contactType": "sales",
      "email": "hello@agrohi.com",
      "availableLanguage": [
        "English"
      ],
      "areaServed": "Worldwide"
    },
    "sameAs": [
      "https://www.linkedin.com/company/agrohitech",
      "https://berth.agrohi.com"
    ],
    "owns": {
      "@type": "SoftwareApplication",
      "@id": "https://berth.agrohi.com/#software",
      "name": "Berth",
      "applicationCategory": "DeveloperApplication",
      "operatingSystem": "Kubernetes",
      "url": "https://berth.agrohi.com",
      "description": "Berth is a self-hosted Kubernetes dashboard with a read-only AI SRE: endpoint health, capacity planning, guided app exposure, and evidence-based troubleshooting, run in your own cluster."
    }
  },
  {
    "@context": "https://schema.org",
    "@type": "WebSite",
    "@id": "https://cloudguys.io/#website",
    "url": "https://cloudguys.io/",
    "name": "CloudGuys",
    "description": "Security and cloud consultancy helping organizations assess risks, improve architecture, and verify remediation.",
    "publisher": {
      "@id": "https://cloudguys.io/#organization"
    },
    "inLanguage": "en"
  },
  {
    "@context": "https://schema.org",
    "@type": "BlogPosting",
    "@id": "https://cloudguys.io/blog/terraform-state-management#article",
    "headline": "Terraform State Management: Kill Local State",
    "description": "Why committing .tfstate to Git is a security disaster. A guide to setting up robust S3+DynamoDB remote backends with encryption and locking.",
    "image": "https://cloudguys.io/_astro/cover.8dB-ACPc.png",
    "datePublished": "2026-05-03T00:00:00.000Z",
    "dateModified": "2026-05-14T00:00:00.000Z",
    "author": {
      "@type": "Organization",
      "name": "CloudOpsPro Team",
      "url": "https://cloudguys.io/"
    },
    "publisher": {
      "@id": "https://cloudguys.io/#organization"
    },
    "mainEntityOfPage": {
      "@type": "WebPage",
      "@id": "https://cloudguys.io/blog/terraform-state-management"
    },
    "articleSection": "DevOps",
    "keywords": "Terraform, Security, DevOps",
    "inLanguage": "en"
  },
  {
    "@context": "https://schema.org",
    "@type": "BreadcrumbList",
    "itemListElement": [
      {
        "@type": "ListItem",
        "position": 1,
        "name": "Home",
        "item": "https://cloudguys.io/"
      },
      {
        "@type": "ListItem",
        "position": 2,
        "name": "Blog",
        "item": "https://cloudguys.io/blog"
      },
      {
        "@type": "ListItem",
        "position": 3,
        "name": "Terraform State Management: Kill Local State",
        "item": "https://cloudguys.io/blog/terraform-state-management"
      }
    ]
  }
]
```
