Skip to content
Back to skills

State Management

ASecurity

Manage Terraform remote state — backend setup, state isolation, locking, import, mv, and state surgery.

  • 19 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added October 19, 2026
ai-agentsbashawsgcpterraformdebuggingdatabasebackendsecurity

Works with

  • cli

Security analysis

A100/100

Scanned October 19, 2026

npx -y skills add sawrus/agent-guides --skill state-management --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of State Management?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for State Management
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/sawrus-state-management/badge)](https://www.skillsdirectory.com/skills/sawrus-state-management)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: state-management
type: skill
description: Manage Terraform remote state — backend setup, state isolation, locking, import, mv, and state surgery.
related-rules:
  - state-management.md
  - iac-standards.md
allowed-tools: Read, Write, Edit, Bash
---

# Skill: Terraform State Management

> **Expertise:** Remote backends, state isolation, import, mv, rm, state surgery, cross-stack references.

## When to load

When setting up a new Terraform backend, debugging state lock, importing manually-created resources, or safely moving resources between state files.

## Backend Setup Patterns

```hcl
# AWS S3 + DynamoDB lock
terraform {
  backend "s3" {
    bucket         = "mycompany-terraform-state"
    key            = "${var.environment}/${var.component}/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    kms_key_id     = "alias/terraform-state"
    dynamodb_table = "terraform-state-lock"
  }
}

# GCS (GCP) — built-in locking, no separate lock table needed
terraform {
  backend "gcs" {
    bucket = "mycompany-terraform-state"
    prefix = "${var.environment}/${var.component}"
  }
}

# Terraform Cloud / HCP Terraform
terraform {
  cloud {
    organization = "mycompany"
    workspaces { name = "production-network" }
  }
}
```

## State Isolation (per environment × component)

```
state/
├── staging/
│   ├── network/terraform.tfstate
│   ├── k8s-cluster/terraform.tfstate
│   └── databases/terraform.tfstate
└── production/
    ├── network/terraform.tfstate
    ├── k8s-cluster/terraform.tfstate
    └── databases/terraform.tfstate
```

**Rule**: Staging and production **must** use separate state files (separate key/prefix, ideally separate bucket).

## Cross-Stack Values (avoid `terraform_remote_state`)

```hcl
# ✅ Publish outputs to SSM Parameter Store
resource "aws_ssm_parameter" "vpc_id" {
  name  = "/${var.environment}/network/vpc_id"
  type  = "String"
  value = aws_vpc.this.id
}

# ✅ Consume in another stack via data source
data "aws_ssm_parameter" "vpc_id" {
  name = "/${var.environment}/network/vpc_id"
}

resource "aws_subnet" "app" {
  vpc_id = data.aws_ssm_parameter.vpc_id.value
}
```

## State Import (bring unmanaged resource under TF control)

```bash
# 1. Write the resource block in .tf first
resource "aws_s3_bucket" "legacy" {
  bucket = "my-legacy-bucket"
}

# 2. Import the existing resource
terraform import aws_s3_bucket.legacy my-legacy-bucket

# 3. Run plan — should show no changes if .tf matches reality
terraform plan   # should be: "No changes."
```

## State Move (rename / reorganize)

```hcl
# Safe rename using moved{} block (Terraform 1.1+) — no CLI required
moved {
  from = aws_instance.web
  to   = aws_instance.this["web-01"]
}

# After apply, remove the moved{} block
```

```bash
# Manual state mv (use when moved{} block is not applicable)
# ALWAYS take a backup first
terraform state pull > backup-$(date +%Y%m%d-%H%M%S).tfstate

terraform state mv \
  'aws_security_group.old_name' \
  'aws_security_group.new_name'
```

## State Surgery (break-glass commands)

```bash
# List all resources in state
terraform state list

# Show a specific resource's state
terraform state show 'aws_instance.this["web-01"]'

# Remove a resource from state WITHOUT destroying it (use when managed outside TF)
terraform state rm 'aws_s3_bucket.legacy'

# Force-unlock a stuck state lock (use only when lock is genuinely stale)
terraform force-unlock <LOCK_ID>
# Lock ID from error message: "Error acquiring the state lock"

# Pull state for manual inspection
terraform state pull | jq '.resources[] | {type: .type, name: .name}'

# Replace a resource (force-recreate without destroy first)
terraform apply -replace='aws_instance.this["web-01"]'
```

## Debugging Lock Issues

```bash
# Error: "Error acquiring the state lock" + lock ID
# Check DynamoDB for stale lock:
aws dynamodb get-item \
  --table-name terraform-state-lock \
  --key '{"LockID": {"S": "mycompany-terraform-state/production/network/terraform.tfstate"}}'

# Verify no apply is actually running before force-unlock
# Only force-unlock if you are certain no other process holds the lock
terraform force-unlock <LOCK_ID_FROM_ERROR>
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.