Terraform Remote Backend & State Locking

2026. 5. 8. 14:24·Computer Science

 Terraform은 인프라를 코드로 관리할 수 있게 해주는 IaC이지만, 실무에서는 코드 작성만큼이나 상태파일 관리가 중요합니다. Terraform은 terraform.tfstate 파일을 기준으로 실제 클라우드 리소스와 코드의 차이를 판단하기 때문에, 이 파일이 꼬이거나 서로 다른 작업자가 다른 상태를 기준으로 작업하면 동기화가 되지 않아 문제가 발생할 수 있습니다. 그래서 실무에서는 상태파일을 S3 같은 원격 저장소에 보관하고, 동시에 여러 사용자가 terraform apply를 실행하지 못하도록 Lock 구조를 함께 구성합니다. 이번 포스팅에서는 Terraform 상태파일을 AWS 환경에서 S3와 DynamoDB Lock을 이용해 안전하게 관리하는 방법을 알아보겠습니다.

 


 

목차

1. 상태파일 중앙관리 by S3
2. DynamoDB로 State Locking 구성
3. Terraform 실습
4. 결론

 


 

#1 상태파일 중앙관리 by S3

<그림 1>. Terraform Remote Backend

 

 terraform apply를 최초로 실행하면 현재 작업 디렉토리에 terraform.tfstate 파일이 생성됩니다. 이 파일은 Terraform이 관리하는 인프라의 현재 상태를 기록하는 파일로, 이후 실행되는 plan, apply, destroy 과정에서 이 상태파일을 기준으로 실제 AWS 리소스와 코드의 차이를 비교합니다. 비교 후에는 내용과 비교하여 리소스를 생성, 삭제, 수정 등을 실행하는데, 여러 명이 같은 인프라를 함께 관리하는 환경에서는 로컬 상태파일 방식에 한계가 생깁니다. 예를 들어 A 엔지니어가 자신의 로컬 상태파일을 기준으로 한 리소스를 수정하고, B 엔지니어가 또 다른 로컬 상태파일을 기준으로 다른 리소스를 수정한다면 두 사람은 서로 다른 인프라 상태를 기준으로 작업하게 됩니다. 이 경우 실제 AWS 리소스 상태가 자신의 로컬 상태파일에 있는 상태와 달라질 수 있고, apply시에는 중복 오류나 변경 사항이 누락되는 문제가 발생할 수 있습니다.

 

 그렇다면 상태파일을 공동으로 사용을 해야 하는데, 어떻게 해야 할까요? 먼저, 공동 작업이 가능한 Git을 떠올릴 수 있지만, 상태파일에는 일부 민감한 정보가 포함될 수 있기 때문에 Git 저장소에 그대로 올리는 것은 위험할 수 있습니다. 상태파일을 코드처럼 공유하기 위해 Git에 커밋하는 방식은 협업 관점에서도, 보안 관점에서도 적절하지 않습니다. 따라서 실무에서는 상태파일을 로컬에 두는 대신, 팀원들이 동일한 상태파일을 참조할 수 있도록 원격 저장소에 중앙 관리하는 또 다른 방식이 필요합니다.

 

 AWS 환경에서는 일반적으로 S3를 Terraform Remote Backend로 사용합니다. S3 Backend를 설정하면 terraform.tfstate 파일이 로컬이 아니라 S3 버킷에 저장되고, 팀원들은 동일한 S3 경로에 있는 상태파일을 기준으로 plan과 apply를 실행하게 됩니다. 이를 통해 인프라 상태를 중앙에서 일관되게 관리할 수 있습니다.

 

 예를 들어 다음과 같이 S3 Backend를 설정할 수 있습니다.

 

terraform {
  backend "s3" {
    bucket  = "my-company-terraform-state"
    key     = "prod/terraform.tfstate"
    region  = "ap-northeast-2"
    encrypt = true
    dynamodb_table = "terraform-state-lock"
  }
}

 

 여기서 bucket은 상태파일을 저장할 S3 버킷 이름을 의미하고, key는 버킷 내부에서 상태파일이 저장될 경로를 의미합니다. region은 S3 버킷이 위치한 AWS 리전을 지정하며, encrypt는 상태파일을 암호화하여 저장하기 위한 설정입니다.

 

상태파일 관리 주의할 점

  • S3 Versioning을 활성화하여 상태파일이 잘못 변경되거나 삭제되었을 때 이전 버전으로 복구가 가능해야 합니다.
  • S3 버킷의 Public Access는 반드시 차단해야 하며, IAM 정책을 통해 필요한 사용자나 CI/CD 파이프라인만 상태파일에 접근할 수 있도록 제한해야 합니다.
  • dev, stage, prod처럼 환경별로 state 경로를 나누어, 운영 환경에 영향 없이 개발 환경의 리소스를 독립적으로 관리해야 합니다.

 


 

#2 DynamoDB로 State Locking 구성

 

 S3 원격 백엔드를 사용하면 상태파일을 중앙에서 관리할 수 있지만, 아직 남아있는 문제가 있습니다. 상태파일을 S3에 저장하면 여러 사용자가 같은 terraform.tfstate 파일을 참조할 수는 있지만, 동시에 여러 명이 terraform apply를 실행하는 상황이 발생할 수도 있습니다. 예를 들어 A 관리자가 임의의 한 리소스를 수정하기 위해 apply를 실행하고 있는 중에, B 관리자도 같은 상태를 기준으로 다른 리소스를 수정하는 apply를 실행할 수 있습니다. 이 경우 두 관리자가 같은 상태파일을 동시에 읽고 서로 다른 변경사항을 실행하게 되며, 작업 순서에 따라 state가 꼬이거나 특정 변경 사항이 누락될 수 있습니다.

 

 이런 문제를 막기 위해 필요한 것이 State Locking입니다. State Locking은 한 관리자가 상태파일을 수정하는 동안 다른 관리자가 동시에 같은 state를 변경하지 못하도록 Lock을 거는 기능입니다. 즉, 누군가 apply를 실행 중이라면 다른 관리자는 해당 작업이 끝날 때까지 같은 state에 대해 변경 작업을 수행할 수 없도록 막는 구조입니다.

 

 AWS 환경에서는 DynamoDB를 이용해 Terraform State Locking을 구성하는 방식이 많이 사용되며, DynamoDB 테이블은 실제 인프라 리소스를 저장하는 용도가 아니라, 현재 어떤 작업자가 state를 사용 중인지 기록합니다. Terraform은 apply, destroy처럼 상태파일을 변경하는 작업을 실행할 때 DynamoDB 테이블에 Lock 정보를 기록합니다. 이미 Lock이 존재하는 상태라면 다른 사용자는 같은 state에 대해 작업을 진행할 수 없고, 기존 작업이 끝나 Lock이 해제된 이후에 다시 실행해야 합니다.

 

 DynamoDB Lock Table은 보통 다음과 같이 구성합니다.

 

resource "aws_dynamodb_table" "terraform_lock" {
  name         = "terraform-state-lock"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

 

 name은 생성할 DynamoDB 테이블 이름이며, 이후 S3 Backend를 선언할 때 dynamodb_table 값과 동일하게 맞춰야 합니다. billing_mode = "PAY_PER_REQUEST"는 요청한 만큼만 비용을 지불하는 온디맨드 과금 방식입니다. Locking 용도의 테이블은 요청량이 많지 않기 때문에, 별도로 읽기·쓰기 용량을 고정해서 관리하는 것보다 이 방식이 간단하게 사용하기 좋습니다. hash_key = "LockID"는 DynamoDB 테이블의 기본 키를 LockID로 지정한다는 의미입니다. state에 Lock을 걸 때 이 LockID 값을 기준으로 잠금 정보를 저장하고 확인합니다.

 

 아래의 attribute 블록은 S3 Backend에서 DynamoDB Locking을 사용할 때는 LockID라는 문자열 속성이 필요하므로, LockID라는 속성을 문자열 타입으로 정의하는 부분입니다.

 


 

#3 Terraform 실습

 

 이번엔 Terraform 언어로 실제로 S3 원격 백엔드와 DynamoDB Locking을 진행해 보겠습니다. 먼저, S3 버킷과 DynamoDB 테이블은 Terraform 상태파일을 저장하고 잠금을 관리하기 위한 기반 리소스이므로 부트스트랩 단계에서 생성해야 합니다. 이후 실제 dev, prod 인프라 코드에서는 terraform 블록의 backend "s3" 설정을 통해 이미 생성된 S3 버킷과 DynamoDB 테이블을 참조해야 합니다.

 

resource "aws_s3_bucket" "state_bucket" {
  bucket = var.terraform_state_bucket_name
}

 

 S3 버킷을 생성하는 코드이며, bucket에는 버킷의 이름을 지정하여 전달합니다. 예시에서는 var.terraform_state_bucket_name 변수를 통해 버킷 이름을 전달받도록 구성했습니다. 이 버킷은 이후 테라폼 상태파일을 저장하는 원격 저장소로 사용됩니다.

 

resource "aws_s3_bucket_versioning" "state_versioning" {
  bucket = aws_s3_bucket.state_bucket.id

  versioning_configuration {
    status = "Enabled"
  }
} 

 

 S3 버킷의 Versioning을 활성화하는 코드입니다. bucket에는 Versioning을 적용할 S3 버킷을 지정하며, 여기서는 앞에서 생성한 aws_s3_bucket.state_bucket.id를 참조합니다. status = "Enabled"로 설정하면 상태파일이 수정되거나 덮어써질 때 이전 버전이 함께 보관됩니다. 실수로 잘못 변경되거나 롤백을 원할 때, 이전 버전으로 복구할 수 있도록 Versioning을 활성화해야 합니다.

 

resource "aws_s3_bucket_server_side_encryption_configuration" "state_encryption" {
  bucket = aws_s3_bucket.state_bucket.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

 

 위 코드는 S3 버킷에 서버 측 암호화를 적용하는 코드입니다. bucket에는 암호화를 적용할 S3 버킷을 지정합니다. sse_algorithm = "AES256"은 AWS가 제공하는 S3 관리형 암호화 방식인 SSE-S3를 사용하겠다는 의미입니다. 상태파일에는 민감한 정보가 포함될 수 있으므로, 암호화되도록 설정이 필수입니다.

 

resource "aws_s3_bucket_public_access_block" "state_access_block" {
  bucket = aws_s3_bucket.state_bucket.id

  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

 

 이번엔 상태파일을 저장하는 S3 버킷에 Public Access Block을 설정하는 코드입니다. 상태정보 유출을 방지하도록 버킷이 실수로 퍼블릭하게 열리지 않게 모든 공개 접근을 차단해야 합니다.

  • block_public_acls = true : 퍼블릭 ACL 설정을 차단
  • ignore_public_acls = true : 기존에 퍼블릭 ACL이 있더라도 무시
  • block_public_policy = true : 퍼블릭 접근을 허용하는 버킷 정책을 차단
  • restrict_public_buckets = true : 퍼블릭 정책이 적용된 버킷에 대한 접근을 제한

 위 옵션은 S3 버킷이 외부에 노출되는 것을 방지하기 위한 보안 설정입니다.

 

resource "aws_dynamodb_table" "terraform_lock_table" {
  name         = var.terraform_lock_table_name
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}

 

 앞서 설명했던 State Locking에 사용할 DynamoDB 테이블을 생성하는 코드입니다. name에는 생성할 DynamoDB 테이블 이름을 지정하며, 예시에서는 var.terraform_lock_table_name 변수를 통해 테이블 이름을 전달받도록 구성했습니다.

 

terraform {
  backend "s3" {
    bucket         = "project-terraform-state-bucket"
    key            = "dev/terraform.tfstate"
    region         = "ap-northeast-2"
    dynamodb_table = "project-terraform-locks"
    encrypt        = true
  }
}

 

 위 코드도 앞서 설명했던 S3 원격 백엔드를 연결하는 코드이며, 부트스트랩 이후에 인프라를 개발하고 운영할 때 사용됩니다. 버킷 이름, State 경로, 테이블 이름 등의 노출을 막고자 한다면 backend "s3" {} 처럼 backend 타입만 선언하고, 실제 변수들은 .hcl 파일로 별도로 분리한 뒤, init 단계에서 -backend-config= 옵션으로 백엔드 정보를 전달하는 방식이 권장됩니다.

 

 위에서 S3 버킷에 기본 서버 측 암호화를 설정했다면 backend에 encrypt 옵션을 추가할 필요는 없지만, 상태 파일은 암호화되어야 한다는 의도를 보여줌과 동시에 혹시 모를 상황을 대비해 추가하는 것이 좋습니다.

 

 

<그림 2>. S3 버킷 생성

 

 AWS의 S3 콘솔 창에서 버킷 탭에 들어가 확인을 해보면 성공적으로 S3 버킷이 생성된 것을 확인할 수 있습니다.

 

 

<그림 3>. 상태파일 저장

 

 위에서 만들어진 S3 버킷에 들어가 보면, bootstrap 경로에 상태파일이 잘 저장된 것을 확인할 수 있습니다.

 

 

<그림 4>. DynamoDB 테이블 생성

 

 DynamoDB 콘솔에서 테이블을 선택하면 Overview 화면에서 파티션 키를 확인할 수 있습니다. Terraform Locking 용도로 생성한 테이블이라면 파티션 키가 문자열 타입의 LockID로 설정되어 있어야 합니다.

 

 

<그림 5>. State Locking

 

 테라폼 작업이 실행되면 DynamoDB Lock 테이블에 LockID 항목이 생성됩니다. 이 항목은 현재 테라폼이 상태파일을 사용 중이라는 의미이며, 작업이 완료되면 자동으로 삭제됩니다. 따라서 작업 중에 DynamoDB 테이블에서 LockID가 보인다면 State Locking이 정상적으로 동작하고 있는 것입니다.

 

 


 

#4 결론

 

 Terraform 상태파일을 실무에서 안전하게 관리하려면 S3 Remote Backend와 DynamoDB Locking을 함께 구성해야 합니다.
S3에 상태파일을 중앙 저장하고, DynamoDB로 동시에 수정되는 상황을 막아야 여러 개발자가 같은 기준으로 안정적으로 인프라를 관리할 수 있습니다. 따라서 두 구성을 함께 적용해야 안정적인 Terraform 협업 환경 구축이 가능합니다.

'Computer Science' 카테고리의 다른 글

Amazon Bedrock 기반 RAG와 Agent 아키텍처 설계  (0) 2026.05.22
ALB와 TLS/SSL 인증서로 HTTPS 암호화 통신 구현하기  (0) 2026.05.15
ISMS-P 인증 받는 클라우드 아키텍처 핵심 7가지  (0) 2026.05.01
ECS on EC2와 ECS on Fargate를 비용과 운영 관점에서 비교하기  (0) 2026.04.15
Terraform을 활용하여 안전한 SG 및 NACL 인바운드/아웃바운드 아키텍처 설계하기  (0) 2026.04.09
'Computer Science' 카테고리의 다른 글
  • Amazon Bedrock 기반 RAG와 Agent 아키텍처 설계
  • ALB와 TLS/SSL 인증서로 HTTPS 암호화 통신 구현하기
  • ISMS-P 인증 받는 클라우드 아키텍처 핵심 7가지
  • ECS on EC2와 ECS on Fargate를 비용과 운영 관점에서 비교하기
Cloud9Ops
Cloud9Ops
CloudOps 지망생입니다. 스스로의 공부를 위한, 더 많은 사람들이 양질의 지식을 습득하는 공간입니다.
  • Cloud9Ops
    CloudOps Engineer
    Cloud9Ops
  • 전체
    오늘
    어제
    • 전체 (20)
      • Computer Science (15)
      • Programming (2)
      • Projects (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    정규화
    성능 최적화
    캐시
    BruteForce
    해시 체이닝
    비동기적 처리
    데이터베이스 인덱싱
    SQL 인젝션
    단방향 알고리즘
    B+트리
    컨시스턴트 해싱
    샤딩
    해싱
    해시 테이블
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
Cloud9Ops
Terraform Remote Backend & State Locking
상단으로

티스토리툴바