프로덕션 환경에서의 인프라 사고는 대부분 잘못 구성된 코드 한 줄에서 시작됩니다. 특히 테라폼(Terraform)의 terraform.tfstate 파일이 암호화되지 않은 채 git 리포지토리에 커밋되거나, S3 버킷이 퍼블릭 액세스로 설정된 채 배포되는 시나리오는 클라우드 보안 침해의 주된 원인입니다. 단순한 기능 구현을 넘어, 인프라의 불변성(Immutability)과 기밀성(Confidentiality)을 보장하는 엔터프라이즈급 IaC 보안 전략을 분석합니다.
State 파일 관리: 암호화 및 잠금 전략
테라폼의 심장인 State 파일은 인프라의 현재 상태뿐만 아니라 데이터베이스 패스워드, 액세스 키 등 민감 정보를 평문(Plaintext)으로 포함할 가능성이 매우 높습니다. 로컬 저장소(`local` backend) 사용은 보안상 허용되지 않으며, 반드시 원격 백엔드(Remote Backend)를 구성하여 암호화(Encryption at Rest)와 전송 중 암호화(Encryption in Transit)를 적용해야 합니다.
terraform.tfstate 파일을 Git과 같은 버전 관리 시스템(VCS)에 포함시키는 행위는 가장 흔하면서도 위험한 실수입니다. 리포지토리가 유출되는 순간 모든 인프라 자격 증명이 노출됩니다. .gitignore에 반드시 포함시켜야 합니다.
AWS S3 + DynamoDB를 활용한 보안 백엔드 구성
State 파일을 위한 S3 버킷은 버전 관리(Versioning)를 활성화하여 실수로 인한 삭제나 덮어쓰기에 대비해야 하며, AWS KMS(Key Management Service)를 통한 서버 측 암호화를 강제해야 합니다. 또한, 동시 실행으로 인한 State 파일 손상을 막기 위해 DynamoDB를 통한 State Locking을 구현합니다.
// Secure Backend Configuration Example
// S3 Bucket with Encryption & DynamoDB Locking
terraform {
backend "s3" {
bucket = "corp-infra-tfstate-prod"
key = "vpc/terraform.tfstate"
region = "ap-northeast-2"
// State Locking을 위한 DynamoDB 테이블
dynamodb_table = "terraform-lock-table"
// 데이터 전송 및 저장 시 암호화
encrypt = true
kms_key_id = "alias/terraform-state-key"
}
}
// S3 버킷 자체에 대한 퍼블릭 액세스 차단 (별도 모듈로 관리 권장)
resource "aws_s3_bucket_public_access_block" "state_security" {
bucket = aws_s3_bucket.terraform_state.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
정적 분석(SAST) 도구 비교 및 통합
인프라가 배포되기 전(Pre-deployment), 코드 레벨에서 보안 취약점을 탐지하는 것은 "Shift-Left" 보안 전략의 핵심입니다. HCL(HashiCorp Configuration Language)을 파싱하여 AST(Abstract Syntax Tree)를 분석하는 주요 도구들을 비교합니다.
| 특성 | tfsec | Checkov | Terraform Validate |
|---|---|---|---|
| 분석 방식 | HCL 파싱 기반 정적 분석 | Python 기반, Graph 분석 지원 | 문법 및 내부 참조 유효성 검사 |
| 속도 | 매우 빠름 (Go 언어 기반) | 보통 (Python 기반, 심층 분석) | 즉시 |
| 커버리지 | AWS, Azure, GCP 주요 리소스 | 테라폼 외 K8s, CloudFormation 지원 | 보안 검사 기능 없음 |
| 사용 시점 | 로컬 개발 및 CI 파이프라인 고속 스캔 | CI/CD 파이프라인 심층 스캔 | 코드 작성 직후 |
CI/CD 파이프라인 내 보안 검증 단계
보안 스캔이 개발자의 자율에 맡겨져서는 안 됩니다. CI 파이프라인(GitHub Actions, GitLab CI 등) 내에서 terraform plan 실행 전 강제적인 차단 게이트(Blocking Gate)로 동작해야 합니다. 아래는 Checkov를 활용하여 보안 위반 사항이 발견될 경우 파이프라인을 실패시키는 워크플로우 예시입니다.
# GitHub Actions Workflow Example: IaC Security Scan
name: Terraform Security Audit
on:
pull_request:
branches: [ "main" ]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run Checkov
uses: bridgecrewio/checkov-action@master
with:
directory: ./terraform
# 심각도가 높은 이슈(High, Critical) 발생 시에만 실패 처리
soft_fail: false
framework: terraform
output_format: cli
quiet: true
# 결과 확인 후 실패 시 PR Merge 차단
코드로 정의된 상태와 실제 클라우드 인프라의 상태가 달라지는 현상을 'Drift'라고 합니다. 누군가 콘솔(Console)에서 수동으로 보안 그룹을 변경했다면, 테라폼은 이를 감지해야 합니다. 주기적인(예: 매일 밤) terraform plan 실행을 스케줄링하여 변경 사항 발생 시 보안 팀에 경보를 보내는 구조를 만들어야 합니다.
Policy as Code: Sentinel 및 OPA 활용
단순한 취약점 스캔을 넘어 비즈니스 로직에 기반한 정책 제어가 필요한 경우(예: "모든 S3 버킷은 특정 태그를 가져야 한다", "운영 환경은 오전 9시~오후 6시에만 배포 가능하다"), OPA(Open Policy Agent)나 HashiCorp Sentinel을 활용합니다.
OPA Rego 정책 예시
아래 코드는 테라폼 실행 계획(Plan) Json 출력을 분석하여, 암호화되지 않은 EBS 볼륨 생성을 원천 차단하는 Rego 정책입니다.
# deny_unencrypted_ebs.rego
package terraform.analysis
import input as tfplan
# 리소스 변경 사항 중 EBS 볼륨 생성/수정 필터링
default allow = false
deny[msg] {
resource := tfplan.resource_changes[_]
resource.type == "aws_ebs_volume"
# 암호화 설정이 false인 경우 탐지
not resource.change.after.encrypted
msg := sprintf(
"EBS Volume must be encrypted: %v",
[resource.address]
)
}
결론: 자동화된 방어 체계 구축
테라폼을 활용한 인프라 관리는 속도와 효율성을 제공하지만, 적절한 보안 통제가 없다면 대규모 보안 사고의 트리거가 될 수 있습니다. State 파일의 원격 암호화 저장, 커밋 전 Hook을 통한 비밀 정보 스캔, CI 파이프라인 내 정적 분석, 그리고 주기적인 Drift 감지는 선택이 아닌 필수적인 엔지니어링 요구사항입니다. 보안을 '나중에' 적용하는 것이 아니라, 코드 작성 시점부터 통합하는 DevSecOps 문화를 정착시켜야 합니다.
Post a Comment