Terraform Plan 리뷰 에이전트 구축하기: 머지 전 CI에서 위험한 변경 사항 포착하기
요약
CI 파이프라인에서 Terraform 플랜의 위험 요소를 자동으로 감지하는 LLM 에이전트 구축 가이드를 제공합니다. 결정론적 규칙과 LLM의 추론을 결합하여 인프라 변경 사항을 안전하게 리뷰하는 방법을 다룹니다.
핵심 포인트
- Terraform 플랜을 텍스트가 아닌 JSON 형식으로 파싱하여 데이터 정확도 확보
- 데이터베이스 삭제 등 명확한 위험은 결정론적 규칙으로 우선 처리
- LLM은 복잡한 추론이 필요한 영역에만 활용하여 신뢰성 향상
- 읽기 전용(Read-only) 경계를 설정하여 에이전트의 인프라 직접 조작 방지
💡 원문은 devtocash.com에 게시되었습니다 — 이 가이드의 최신 정보가 유지되는 곳입니다. 저는 그곳에서 매주 실무 중심의 DevOps/SRE 심층 분석 글을 작성합니다.
아무도 충분히 주의 깊게 읽지 않는 리뷰
CI에서의 terraform apply는 파이프라인이 수행할 수 있는 가장 폭발 반경(blast-radius)이 큰 작업 중 하나이며, 그 앞의 인간 안전장치는 보통 금요일 오후에 400줄짜리 플랜(plan)을 대충 훑어보는 리뷰어입니다. 위험한 코드들 — 상태 저장 리소스(stateful resource)에 대한 destroy, 보안 그룹(security group)을 0.0.0.0/0으로 개방하는 것, IAM 정책이 조용히 "*"로 확장되는 것 — 은 태그 변경이나 태그 순서 변경의 소음 속에 숨어 있습니다. 이것이 바로 LLM 에이전트가 범위를 올바르게 설정하기만 한다면 매우 잘 수행할 수 있는, 좁고 신호가 명확한(high-signal) 판단의 영역입니다.
이 가이드는 CI에서 실행되는 **Terraform 플랜 리뷰 에이전트(Terraform plan review agent)**를 구축합니다. 이 에이전트는 기계가 읽을 수 있는 플랜을 파싱하고, 절대 놓쳐서는 안 될 변경 사항에 대해 결정론적 규칙(deterministic rules)을 적용하며, 나머지 부분에 대해서는 LLM에게 추론을 요청합니다. 그런 다음 Pull Request(PR)에 구조화된 리뷰 댓글을 게시하고, 고위험 변경 사항에 대해 머지를 차단하는 0이 아닌 종료 코드(non-zero exit code)를 설정합니다. 이 에이전트는 인프라를 절대 건드리지 않습니다. 플랜을 읽고 결과(findings)를 반환할 뿐입니다. 이러한 읽기 전용(read-only) 경계가 핵심이며, 이는 안전한 Kubernetes MCP 서버 뒤에 있는 것과 동일한 설계 원칙입니다. 에이전트에게 셸(shell)이 아닌, 제한되고 구조화된 접점(surface)을 제공하십시오.
플랜은 텍스트가 아닌 JSON으로 읽으세요
팀들이 저지르는 첫 번째 실수는 terraform plan의 사람이 읽기 좋게 포맷팅된 출력을 프롬프트(prompt)로 전달하는 것입니다. 해당 출력은 정보 손실이 있고, 색상이 입혀져 있으며, 모호합니다. 대신 파싱할 수 있는 안정적이고 구조화된 플랜을 Terraform에서 생성할 수 있습니다:
terraform plan -out=tfplan.binary
terraform show -json tfplan.binary > plan.json
plan.json 내의 resource_changes 배열은 신뢰할 수 있는 근거(ground truth)입니다. 각 항목은 change.actions 필드 — ["create"], ["update"], ["delete"], 또는 교체(replacement)를 의미하는 ["delete", "create"] — 와 더불어 before 및 after 객체를 가집니다. 모델이 개입하기 전에, 이로부터 의도를 결정론적(deterministically)으로 추출합니다.
import json
def load_changes(path="plan.json"):
...
결정론적 규칙 우선, LLM은 그다음
코드로 잡아낼 수 있는 것들을 모델에게 잡아달라고 요청하지 마세요. 데이터베이스에 대한 delete는 판단의 영역이 아니라 엄격한 규칙입니다. 타협할 수 없는 사항들은 결정론적 검사(deterministic checks)로 인코딩하여, 컨디션이 좋지 않은 모델이 이를 놓치는 일이 절대 없도록 하세요. 이는 Kyverno를 이용한 정책 코드화 (policy-as-code with Kyverno)와 동일한 계층 구조입니다. 결정론적 게이트는 울타리 역할을 하고, LLM은 그 뒤에서 감시하는 추가적인 눈 역할을 합니다.
STATEFUL = {"aws_db_instance", "aws_rds_cluster", "aws_s3_bucket",
"aws_dynamodb_table", "aws_ebs_volume", "aws_efs_file_system"}
...
이러한 규칙들은 의도적으로 지루하게 설계되었습니다. 이 규칙들은 사후 분석(postmortems)에 기록되는 사고들을 잡아내며, 토큰 비용 없이 밀리초 단위로 실행됩니다. LLM의 역할은 그 외의 모든 것, 즉 정규 표현식(regex)에 맞지 않는 미묘한 부분들을 다루는 것입니다.
에이전트: 도구 사용(tool use)을 통한 구조화된 결과 도출
이제 LLM 차례입니다. 이를 CI 환경에서 안전하게 만드는 비결은 자유 형식의 산문(free-form prose)을 절대 허용하지 않는 것입니다. 모델이 **도구 스키마 (tool schema)**를 통해 결과(findings)를 반환하도록 강제하여, 출력값이 즉시 조치 가능한 검증된 JSON이 되도록 하세요. 이는 인프라로서의 에이전트 하네스 (the agent harness as infrastructure)에서 심도 있게 다룬 내용으로, 모든 운영(ops) 에이전트를 신뢰할 수 있게 만드는 제약 조건과 동일합니다. PR(Pull Request)당 리뷰어로서 적절한 가격/지연 시간 계층을 가진 Claude Sonnet과 Anthropic Python SDK를 사용합니다.
import anthropic
REVIEW_TOOL = {
...
두 가지 세부 사항이 핵심적인 역할을 수행합니다. tool_choice는 도구 호출 (tool call)을 _강제_하므로, 모델이 수다스러운 문단을 작성하며 경로를 벗어날 수 없게 합니다. 그리고 입력 슬라이싱 (input slice)은 컨텍스트 (context)를 제한합니다. 300개의 리소스를 건드리는 플랜 (plan)이 토큰 예산이나 지연 시간 (latency)을 초과해서는 안 됩니다. 만약 플랜이 정기적으로 그 정도로 크다면, resource_changes를 청크 (chunk)로 나누어 각 배치를 검토한 다음 결과를 병합하십시오.
머지 (Merge) 게이트 설정
두 소스를 결합하고, 중복을 제거한 뒤, 그 결과를 종료 코드 (exit code)로 변환합니다. 심각도가 높은 (High-severity) 결과는 체크를 실패시키며, 중간 (medium) 및 낮은 (low) 심각도의 결과는 댓글로 게시하되 최종 결정은 사람이 내리도록 합니다.
def main():
changes = load_changes()
findings = rule_findings(changes) + llm_findings(changes)
...
GitHub Actions에 연결하기
워크플로 (workflow)는 플랜을 생성하고, 리뷰어를 실행하며, — 결정적으로 — 리뷰어에게 무엇인가를 _변경_할 수 있는 권한을 절대 부여하지 않습니다. 리뷰어는 플랜을 생성하기 위해 상태 (state)를 읽고 PR 댓글을 작성할 뿐이며, 이것이 전체 범위입니다. 이와 같은 파이프라인 단계 (pipeline stages)를 구성하는 것이 처음이라면, GitHub Actions 프로덕션 설정 가이드에서 메커니즘을 다룹니다.
name: terraform-plan-review
on:
pull_request:
...
permissions 블록이 클라우드 자격 증명 (credentials)을 부여하지 않고 스크립트가 plan.json만 읽기 때문에, 에이전트가 해킹당하거나 환각 (hallucination)을 일으키더라도 최악의 상황은 잘못된 댓글을 다는 것이지, 잘못된 apply를 실행하는 것이 아닙니다. 이러한 격리는 의도된 설계입니다. 폭발 반경 (blast radius)은 프롬프트 (prompt)가 무엇을 하라고 _말하는지_가 아니라, 작업 (job)이 할 수 있는 범위에 의해 제한됩니다.
신뢰하기 전에 리뷰어를 테스트하세요
머지 (merge)를 통제하는 에이전트 자체가 하나의 프로덕션 인프라 (production infrastructure)이므로, 에이전트 스스로도 자체적인 테스트가 필요합니다. 저장된 plan.json 파일들로 피스처 (fixture) 세트를 구축하십시오. — 알려진 데이터베이스 삭제 (database destroy), 와일드카드 IAM 정책 (wildcard IAM policy), 무해한 태그 변경 (benign tag change) 등 — 그리고 리뷰어가 정확히 포착해야 할 항목들을 제대로 플래그 (flag) 하는지 확인(assert)하십시오. 이는 evals for DevOps AI agents에서 강조하는 평가 (eval) 규율입니다. 에이전트가 파이프라인 (pipeline)에 대한 거부권 (veto power)을 갖기 전에, 실제 플랜 (plan)에 대해 정밀도 (precision)와 재현율 (recall)을 측정하십시오. 모든 태그 수정마다 양치기 소년처럼 경고를 울리는 리뷰어는 일주일 안에 무시당하게 되며, 삭제 (destroy) 작업을 놓치는 리뷰어는 리뷰어가 아예 없는 것보다 더 나쁩니다.
정직한 한계
이 에이전트는 인간의 리뷰를 대체하지 않으며, 그렇게 홍보하는 것은 실패로 가는 지름길입니다. 이 에이전트는 모든 패턴 매칭 (pattern-matcher) 도구와 마찬가지로 새로운 유형의 위험을 놓칠 수 있고, 볼 수 없는 컨텍스트 (context)를 잘못 판단할 수 있으며 (예: 특정 "삭제"가 의도된 마이그레이션일 수 있음), LLM 부분은 비결정론적 (non-deterministic)입니다. 즉, 두 번 실행했을 때 중간/낮음 수준의 탐지 결과가 달라질 수 있습니다. 이를 결정론적 규칙 (deterministic rules)이 항상 작동하도록 보장하고, 인간이 확인할 수 있도록 미묘한 사항들을 표면화하는 재현율 우선의 1차 검토 (high-recall first pass) 단계로 취급하십시오. 이를 원격 상태 (remote state), 작은 폭발 반경 (small blast-radius) 모듈, 그리고 Terraform best practices 및 cost-saving Terraform patterns에 명시된 패턴들과 같은 건전한 Terraform 위생 (hygiene) 관리와 결합한다면, 금요일에도 지치지 않는 리뷰어로서 제 역할을 다할 것입니다. 처음 몇 주 동안은 코멘트 전용 모드 (exit-code gate 없음)로 시작하여 에이전트가 무엇을 플래그 하는지 관찰하고, 정밀도 (precision)를 신뢰할 수 있을 때에만 머지를 차단하는 권한을 부여하십시오.
📌 이 가이드의 최신 버전과 DevOps, SRE, Kubernetes, 관측성 (observability) 및 클라우드 비용 관리 가이드 전체 라이브러리는 devtocash.com에서 확인하실 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기