드리프트는 왜 생기고 왜 위험한가
드리프트(drift)는 코드로 선언한 인프라 상태와 클라우드의 실제 상태가 어긋나는 현상이다. 장애 대응 중 콘솔에서 수동으로 보안 그룹을 열거나, 다른 팀이 오토스케일링 정책을 바꾸거나, 클라우드 공급자가 기본값을 변경하면 발생한다.
문제는 다음 apply 시점에 드러난다. Terraform은 상태 파일을 기준으로 실제와 코드의 차이를 되돌리려 하므로, 급하게 넣은 방화벽 예외가 조용히 삭제되거나, 반대로 수동 변경을 코드가 인지하지 못해 재현 불가능한 인프라가 된다. 드리프트를 방치하면 IaC의 핵심 가치인 "코드가 곧 진실(single source of truth)"이 무너진다.
상태 파일이 드리프트 관리의 중심인 이유
Terraform의 상태 파일(terraform.tfstate)은 코드와 실제 리소스를 잇는 매핑 테이블이다. 리소스 ID, 속성값, 의존성을 담고 있어 diff 계산의 기준이 된다. 이 파일이 오래되면 드리프트 감지 자체가 부정확해진다.
상태 파일은 절대 로컬에 두거나 Git에 커밋하지 않는다. 평문에 비밀번호·토큰이 남고, 동시 실행 시 충돌한다. 원격 백엔드 + 잠금(lock)이 기본이다.
# backend.tf — S3 + DynamoDB 잠금
terraform {
backend "s3" {
bucket = "mycorp-tfstate"
key = "prod/network/terraform.tfstate"
region = "ap-northeast-2"
dynamodb_table = "tf-locks"
encrypt = true
}
}
드리프트 감지: plan과 refresh
가장 단순한 감지는 terraform plan이다. 실제 상태를 읽어 코드와 비교하고, 변경이 없으면 종료 코드 0, 차이가 있으면 2를 반환한다. 이 종료 코드를 CI에서 활용해 정기 감지를 자동화한다.
#!/usr/bin/env bash
set -euo pipefail
terraform init -input=false -backend=true
# -detailed-exitcode: 0=변경없음, 1=오류, 2=드리프트 존재
if terraform plan -refresh-only -detailed-exitcode -out=drift.plan; then
echo "드리프트 없음"
else
code=$?
if [ "$code" -eq 2 ]; then
echo "드리프트 감지됨 — 알림 발송"
terraform show -no-color drift.plan | tee drift-report.txt
exit 2
fi
exit "$code"
fi
-refresh-only는 코드를 적용하지 않고 상태와 실제의 차이만 보여준다. 순수 드리프트 감지에 적합하며, 정규 배포 파이프라인과 분리해 매시간 또는 매일 크론으로 돌린다.
감지 도구 비교
| 도구 | 방식 | 적합한 상황 |
|---|---|---|
| terraform plan -refresh-only | 상태 vs 실제 비교 | 기본 감지, 무료 |
| driftctl | 상태에 없는 리소스까지 탐지 | 미관리 리소스 발견 |
| Terraform Cloud/Atlantis | 정기 감지 + PR 워크플로 | 팀 협업, 승인 절차 |
plan은 코드가 관리하는 리소스만 본다. 아무도 코드로 안 만든 "고아 리소스"까지 잡으려면 driftctl 같은 도구로 계정 전체를 스캔하는 편이 낫다.
드리프트를 코드로 되돌리는 두 방향
드리프트를 발견하면 선택은 둘이다. 실제를 코드에 맞추거나(apply), 코드를 실제에 맞춘다(import 또는 코드 수정). 수동 변경이 정당한 것이었다면 코드에 반영해야 한다.
# 상태에 없는 실제 리소스를 코드로 흡수 (Terraform 1.5+)
import {
to = aws_security_group.web
id = "sg-0a1b2c3d4e5f"
}
# 이후 terraform plan 으로 코드-실제 차이를 확인하고 HCL 보완
과거의 terraform import CLI 대신 import 블록을 쓰면 가져오기 계획을 plan으로 미리 검토할 수 있어 안전하다.
실무에서의 주의점
- 상태 잠금 필수: DynamoDB나 백엔드 네이티브 잠금 없이 동시
apply를 돌리면 상태가 깨진다. 복구는 백업에서 되돌리는 수밖에 없다. - 버전 관리와 백업: 상태 버킷은 버저닝을 켜고, 손상 시 이전 버전으로 롤백할 수 있게 둔다.
- 수동 변경 정책: 콘솔 접근을 읽기 전용으로 제한하거나, 긴급 변경 후 반드시 코드 반영을 의무화한다. 정책 없이 도구만 쓰면 드리프트는 반복된다.
- 대상 최소화:
-target남용은 상태 일부만 갱신해 드리프트를 유발한다. 예외 상황에만 쓴다. - 비밀 정보: 상태에 남는 민감값은 백엔드 암호화와 접근 IAM 정책으로 보호한다.
정리
드리프트 관리의 핵심은 도구가 아니라 규율이다. 원격 백엔드와 잠금으로 상태를 안전하게 두고, -refresh-only 감지를 정기 자동화하며, 발견한 차이를 코드로 흡수하거나 되돌리는 절차를 팀 규칙으로 만든다. 이 순환이 돌아갈 때 비로소 코드가 인프라의 진실로 유지된다.