본문 바로가기
IT/Cloud

[Cloud] Terraform State 관리 보안: 1.9+ Remote Backend & 암호화 설정 가이드

by 수누다 2026. 4. 9.
반응형

Terraform State 관리 보안, 왜 지금 당장 점검해야 할까요?

인프라를 코드로 관리하다 보면 어느 순간 이런 상황을 마주하게 되더라고요. 팀원이 실수로 terraform.tfstate 파일을 Git에 커밋해버린 거죠. 그 안에 RDS 비밀번호, IAM 액세스 키, 각종 민감한 리소스 정보가 그대로 담긴 채로요. 저도 몇 년 전에 비슷한 아찔한 경험을 했는데, 그때부터 Terraform State 관리 보안을 진지하게 고민하기 시작했습니다.

Terraform은 1.7 버전에서 State 암호화 기능이 실험적으로 도입된 이후, 1.9 버전부터 해당 기능이 GA(General Availability) 상태로 전환되어 프로덕션 환경에서 공식 권장되고 있습니다. 공식 문서만 봐서는 어디서부터 시작해야 할지 막막한 분들이 많으실 것 같아서, 제가 직접 실무에서 적용해본 경험을 바탕으로 정리해봤습니다.

이 글에서는 Terraform Remote Backend 설정부터 S3 State 암호화, 접근 제어까지 실제로 동작하는 코드와 함께 단계별로 알아볼게요. 2026년 7월 기준 최신 내용을 반영하였습니다.

Terraform State란 뭐고, 왜 위험할까요?

Terraform State는 Terraform이 관리하는 인프라의 현재 상태를 기록한 파일입니다. terraform.tfstate라는 JSON 파일로 저장되며, 여기에는 각 리소스의 ID, 설정값, 그리고 민감한 정보(비밀번호, API 키 등)가 평문으로 저장될 수 있습니다.

State 파일이 노출되면 다음과 같은 위험이 생깁니다:

  • 데이터베이스 비밀번호 및 연결 문자열 노출
  • IAM 자격증명(액세스 키, 시크릿 키) 유출
  • 인프라 전체 구조 파악 가능 → 타겟 공격 위험 증가
  • State 파일 직접 조작을 통한 인프라 파괴 시도 가능

Local vs Remote Backend 비교

Terraform Backend는 State 파일을 어디에 저장할지 결정합니다. 팀 환경에서는 Remote Backend가 필수입니다.

구분 Local Backend Remote Backend (S3 등)
저장 위치 로컬 파일시스템 클라우드 스토리지
팀 협업 어려움 (파일 직접 공유 필요) 용이 (중앙 집중식 관리)
잠금(State Locking) 미지원 지원 (DynamoDB 등)
보안 취약 (Git 실수 노출 위험) 강화 가능 (KMS 암호화, IAM 접근 제어)

사전 준비: IAM 권한과 AWS CLI 설정

Remote Backend를 S3로 설정하기 위해서는 적절한 IAM 권한이 필요합니다. AWS CLI가 정상적으로 설정되어 있어야 하며, 최소 권한 원칙(Least Privilege)에 따라 꼭 필요한 권한만 부여하는 것이 중요합니다.

필요한 IAM 권한 목록

Terraform Remote Backend 운영에 필요한 최소 IAM 권한은 다음과 같습니다:

  • s3:GetObject, s3:PutObject, s3:DeleteObject — State 파일 읽기/쓰기/삭제
  • s3:ListBucket — 버킷 내 객체 목록 조회
  • s3:GetBucketVersioning — 버전 관리 상태 확인
  • dynamodb:GetItem, dynamodb:PutItem, dynamodb:DeleteItem — State Locking용
  • kms:Encrypt, kms:Decrypt, kms:GenerateDataKey, kms:DescribeKey — KMS 암호화 사용 시

IAM Policy 예시 (최소 권한):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::my-terraform-state",
        "arn:aws:s3:::my-terraform-state/*"
      ]
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:GetItem",
        "dynamodb:PutItem",
        "dynamodb:DeleteItem"
      ],
      "Resource": "arn:aws:dynamodb:ap-northeast-2:*:table/terraform-state-lock"
    },
    {
      "Effect": "Allow",
      "Action": [
        "kms:Encrypt",
        "kms:Decrypt",
        "kms:GenerateDataKey",
        "kms:DescribeKey"
      ],
      "Resource": "arn:aws:kms:ap-northeast-2:*:key/*"
    }
  ]
}

Terraform 1.9+: encryption 블록 GA 전환과 달라진 점

이 글을 처음 작성했을 때는 Terraform 1.7에서 실험적으로 도입된 encryption 블록을 소개했었는데요. 2025년 하반기에 출시된 Terraform 1.9부터 State 암호화 기능이 정식(GA) 상태로 전환되었습니다. 이에 따라 기존 설정에서 몇 가지 변경이 필요합니다.

주요 변경 사항 요약:

  • experiments 플래그 제거 필요: 1.7~1.8에서 사용하던 experiments = ["state_encryption"] 선언이 1.9부터 불필요(오히려 경고 발생)
  • enforced 옵션 추가: state 블록 내 enforced = true 설정으로 암호화되지 않은 State 읽기를 강제 차단 가능
  • 다중 키 공급자 네이티브 지원: AWS KMS 외에 GCP KMS, HashiCorp Vault Transit, PBKDF2 방식을 공식 지원
  • fallback 블록 지원: 키 교체 시 기존 암호화 State를 점진적으로 마이그레이션하는 fallback 옵션 추가

Terraform 1.9+ 기준 업데이트된 Backend 설정 전체 예시:

terraform {
  required_version = ">= 1.9"

  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-2"
    encrypt        = true
    kms_key_id     = "arn:aws:kms:ap-northeast-2:123456789012:key/your-key-id"
    dynamodb_table = "terraform-state-lock"
  }

  # 1.9+: experiments 플래그 없이 바로 사용 가능 (GA)
  encryption {
    key_provider "aws_kms" "primary" {
      kms_key_id = "arn:aws:kms:ap-northeast-2:123456789012:key/your-key-id"
      key_spec   = "AES_256"
    }

    method "aes_gcm" "default_method" {
      keys = key_provider.aws_kms.primary
    }

    state {
      method   = method.aes_gcm.default_method
      enforced = true  # 1.9+ 신규: 미암호화 State 읽기 차단
    }

    plan {
      method   = method.aes_gcm.default_method
      enforced = true
    }
  }
}

기존 1.7/1.8 설정에서 마이그레이션 시 주의사항: 이미 암호화된 State가 있다면 enforced = true를 바로 적용하면 안 됩니다. fallback 블록을 활용하여 기존 State를 새 키로 점진적으로 마이그레이션한 후 enforced를 활성화하세요.

OpenTofu와의 비교: BSL 라이선스 이슈와 오픈소스 대안

이 글을 처음 쓸 당시에도 OpenTofu 이야기가 나오기 시작했는데, 이제는 꽤 진지하게 검토해야 할 대안이 됐습니다. OpenTofu는 HashiCorp가 Terraform의 라이선스를 MPL 2.0에서 BSL 1.1로 변경한 것에 반발해 탄생한 오픈소스 포크로, Linux Foundation 산하에서 운영되고 있습니다.

기능 Terraform 1.9+ OpenTofu 1.8+
State 암호화 지원 (GA) 지원 (GA, 먼저 도입)
라이선스 BSL 1.1 (상업적 경쟁 제품 제한) MPL 2.0 (완전 오픈소스)
Provider 호환성 완전 지원 Registry 호환 (대부분 동작)
Terraform Cloud 연동 공식 지원 미지원 (대안: Spacelift, env0 등)
기업 지원 HashiCorp/IBM 공식 Linux Foundation + 커뮤니티

언제 OpenTofu로 전환을 고려해야 할까요?

  • SaaS 형태로 Terraform 유사 서비스를 제공하려는 경우 (BSL 1.1 제한에 해당)
  • 완전한 오픈소스 스택만 사용하는 정책이 있는 경우
  • Terraform Cloud를 사용하지 않고 자체 CI/CD 파이프라인으로 운영 중인 경우

반대로 Terraform을 유지해야 하는 경우: Terraform Cloud/Enterprise와 강하게 통합되어 있거나, HashiCorp의 공식 엔터프라이즈 지원이 필요한 경우입니다. 두 도구는 문법과 State 형식이 거의 동일하므로 마이그레이션 자체는 어렵지 않지만, 주변 생태계(CI/CD, 정책 도구 등) 교체 비용을 반드시 고려해야 합니다.

🔄 마지막 업데이트: 2026년 07월

반응형