본문으로 건너뛰기
김신건의 로그

[IaC] Terraform State: backend, locking, drift, import

· 수정 · 📖 약 2분 · 784자/단어 #terraform #state #iac #devops #cloud
terraform.tfstate, S3 backend, state locking, DynamoDB lock, drift detection, terraform import, state rm

정의

Terraform State = 코드 (의도) vs 실제 인프라 매핑. JSON 파일. 모든 Terraform 작업의 핵심. plan, apply, destroy 모두 state 를 기반으로 diff 계산.

사용 상황

상황Terraform State 주요 고려사항
팀 협업Remote backend 필수 (S3/TFC), local file 금지
여러 환경 분리Workspace 또는 별도 backend key
기존 인프라 도입terraform import 로 state 등록
인프라 드리프트 감지terraform plan -refresh-only 정기 실행
대규모 모노리식 state레이어별 state 분할 전략
Secret 관리output sensitive + aws-secrets-manager 또는 Vault

State 가 하는 일

flowchart LR
    Code["main.tf<br/>(의도)"] --> Plan
    State["terraform.tfstate<br/>(알려진 실제)"] --> Plan
    Real["AWS 실제"] --> Refresh
    Refresh --> State
    Plan --> Diff[Diff]
    Diff --> Apply[apply]
    Apply --> Real
    Apply --> State
역할의미
Mappingresource 이름 ↔ AWS ARN/ID
Metadata의존성 그래프, 버전 정보
Performancerefresh 캐시 (매번 AWS API 호출 안 해도 됨)
Sensitiveoutput value 보관 (평문)

State 파일 내부 구조

{
  "version": 4,
  "terraform_version": "1.8.0",
  "serial": 42,
  "lineage": "550e8400-...",
  "outputs": {
    "vpc_id": {
      "value": "vpc-0abc123",
      "type": "string",
      "sensitive": false
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_s3_bucket",
      "name": "data",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "id": "my-data-bucket",
            "bucket": "my-data-bucket",
            "region": "us-east-1"
          }
        }
      ]
    }
  ]
}
  • serial: apply 마다 증가. 충돌 감지.
  • lineage: state 파일 고유 ID. 다른 state 교체 방지.
  • sensitive 출력값도 JSON 에 평문 저장. Backend 암호화 필수.

Backend 종류

flowchart TB
    B[Backend]
    B --> Local[local file<br/>팀 사용 금지]
    B --> S3["S3 + DynamoDB lock<br/>(AWS 표준)"]
    B --> TFC["Terraform Cloud / HCP Terraform"]
    B --> GCS[GCS]
    B --> Azure[Azure Blob]
    B --> Consul[Consul]

S3 + DynamoDB (AWS 표준)

terraform {
  backend "s3" {
    bucket         = "my-tf-state"
    key            = "prod/web/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    kms_key_id     = "arn:aws:kms:us-east-1:123:key/..."
    dynamodb_table = "tf-lock"
  }
}
컴포넌트역할
S3 bucketstate 저장 + versioning 활성화
KMSserver-side 암호화
DynamoDBdistributed lock (conditional write)

State Locking

sequenceDiagram
    Dev1->>Lock: acquire (DynamoDB CAS)
    Lock-->>Dev1: OK
    Dev1->>State: write
    Dev2->>Lock: acquire
    Lock-->>Dev2: 이미 잠겨있음
    Dev1->>Lock: release
    Dev2->>Lock: acquire
    Lock-->>Dev2: OK

동시 apply 충돌 방지. DynamoDB 의 conditional write (CAS: Compare-And-Swap).

Lock 강제 해제 (비정상 종료 후):

terraform force-unlock LOCK_ID

Drift Detection

# 코드 변경 없이 실제 vs state 차이만 확인
terraform plan -refresh-only
상황원인대응
state < 실제콘솔 직접 수정terraform refresh + 코드 반영
state > 실제수동 삭제terraform state rm 후 재적용
정기 감지드리프트 자동화CI 에서 plan -refresh-only 스케줄링

Prod 수동 변경 감지. 정기 drift check 는 CI 파이프라인에 포함.

State 분할 전략

flowchart TD
    Mono["모노리식 State<br/>(모든 리소스 한 파일)"]
    Split["레이어별 State 분할"]
    Mono --> Split
    Split --> Net["network/<br/>VPC, Subnet, Route"]
    Split --> Compute["compute/<br/>EKS, EC2, ASG"]
    Split --> App["app/<br/>Lambda, RDS, ElastiCache"]
    Split --> Shared["shared/<br/>IAM, KMS, ECR"]
레이어예시 리소스변경 빈도
networkVPC, Subnet, Route Table매우 낮음
sharedIAM Role, KMS Key, ECR낮음
computeEKS, EC2, Auto Scaling중간
appLambda, RDS, ElastiCache높음

분할 이점: plan 시간 단축, 블라스트 반경 감소, 팀별 소유권 분리. 분할 방법: terraform_remote_state 로 다른 state 의 output 참조.

data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "my-tf-state"
    key    = "prod/network/terraform.tfstate"
    region = "us-east-1"
  }
}

resource "aws_eks_cluster" "main" {
  vpc_config {
    subnet_ids = data.terraform_remote_state.network.outputs.private_subnet_ids
  }
}

State 조작 명령

terraform state list                           # 모든 리소스 목록
terraform state show aws_s3_bucket.data        # 단일 리소스 상세
terraform state mv old.name new.name           # rename (리팩토링 시)
terraform state rm aws_s3_bucket.old           # state 에서만 제거 (AWS 실제 리소스 남음)
terraform state pull > backup.tfstate          # state 다운로드 (백업)
terraform state push backup.tfstate            # state 업로드 (위험, 수동)

terraform import aws_instance.web i-1234abcd  # 기존 리소스를 state 에 등록

CAUTION

state pushserial 번호 역전 방지 없이 덮어씀. 잘못된 state 로 인프라 삭제 위험.

Import (기존 리소스 등록)

CLI import (Terraform 1.5+)

import {
  to = aws_s3_bucket.legacy
  id = "my-legacy-bucket"
}

resource "aws_s3_bucket" "legacy" {
  bucket = "my-legacy-bucket"
}
# 코드 자동 생성
terraform plan -generate-config-out=generated.tf
terraform apply

구버전 CLI import

terraform import aws_s3_bucket.legacy my-legacy-bucket

코드는 직접 작성. import 후 terraform plan 으로 drift 없는지 확인.

Workspace (환경 분리)

terraform workspace new prod
terraform workspace new staging
terraform workspace select prod
terraform workspace list
locals {
  env = terraform.workspace   # "prod" / "staging"
}

resource "aws_instance" "web" {
  instance_type = local.env == "prod" ? "c5.xlarge" : "t3.small"
}

한 backend 에 여러 state 관리. 단, separate backend (별도 S3 key) 가 더 안전. Workspace 는 동일 AWS 계정에서 사용 → 실수로 Prod 에 staging 적용 위험.

Terragrunt 연계

Terraform 의 DRY wrapper. 여러 환경/레이어의 중복 backend 설정 제거.

# terragrunt.hcl
remote_state {
  backend = "s3"
  config = {
    bucket  = "my-tf-state-${get_aws_account_id()}"
    key     = "${path_relative_to_include()}/terraform.tfstate"
    region  = "us-east-1"
    encrypt = true
    dynamodb_table = "tf-lock"
  }
}
environments/
  prod/
    network/   ← terragrunt.hcl 상속
    compute/
    app/
  staging/
    network/
    compute/

CI/CD 연계

단계명령설명
PRterraform plandiff 리뷰, 변경 범위 확인
Mergeterraform apply -auto-approve자동 적용
정기terraform plan -refresh-onlydrift 감지
공유plan 결과를 PR comment 로Atlantis / Spacelift / TFC

AtlantisTerraform Cloud 는 PR 이벤트에 plan 자동 실행 + 승인 후 apply.

State 의 위험

WARNING

  1. State 의 secret 평문 = terraform output 의 password 등 그대로. 접근 제한 + KMS + IAM.
  2. 수동 state 편집 = 형식 깨짐 위험. 반드시 terraform state 명령 사용.
  3. State 손실 = 추적 불가 (코드와 실제 매핑 소실). S3 versioning + 정기 백업.
  4. 여러 사람 동시 apply = lock 없으면 state 깨짐. DynamoDB lock 필수.
  5. Local backend 를 팀이 공유 = git 에 state 올리면 secret 노출 + 충돌. Remote backend 전환.

관련 위키

이 글의 용어 (6개)
[AWS] CloudTrail (API Activity Logging)cloud
정의 AWS CloudTrail 은 AWS 계정의 API 호출 및 사용자 활동을 기록 하는 감사 로깅 서비스입니다. "누가, 언제, 어디서, 어떤 API 를, 어떤 리소스에 대해…
[AWS] IAM: User, Role, Policy, STScloud
정의 IAM (Identity and Access Management) = AWS 의 권한 관리 전부. User, Group, Role, Policy 로 구성. "누가 어떤 리소…
[AWS] KMS: 암호화 키 관리, envelope encryptioncloud
정의 KMS (Key Management Service) = 암호화 키 중앙 관리. envelope encryption + IAM 통합 + 감사 로그. 키 종류 | 종류 | 의미…
[AWS] S3: object storage, storage classes, lifecyclecloud
정의 S3 = AWS 의 object storage. bucket + key + object. 11 9's durability (99.999999999%), 무한 확장. 2026…
[AWS] Secrets Manager + Parameter Storecloud
정의 AWS Secrets Manager = 회전이 필요한 비밀 (DB 패스워드, API key) 을 안전하게 저장/관리하는 서비스. Lambda 기반 자동 회전과 암호화 내장.…
[IaC] Terraform: HCL, provider, statecloud
정의 Terraform = 선언적 인프라 코드. HCL (HashiCorp Configuration Language) 로 리소스 정의 → AWS/GCP/Azure 등 provid…

이 개념을 다룬 위키 페이지 (1)

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기