Infrastructure as Code (IaC) - 이상적 형태와 핵심 개념
TL;DR
- Infrastructure as Code (IaC) - 이상적 형태와 핵심 개념의 핵심 개념과 용어를 한눈에 정리한다.
- Infrastructure as Code (IaC) - 이상적 형태와 핵심 개념이(가) 등장한 배경과 필요성을 요약한다.
- Infrastructure as Code (IaC) - 이상적 형태와 핵심 개념의 특징과 적용 포인트를 빠르게 확인한다.
1. 개념
Infrastructure as Code (IaC) - 이상적 형태와 핵심 개념은(는) 핵심 용어와 정의를 정리한 주제로, 개발/운영 맥락에서 무엇을 의미하는지 설명한다.
2. 배경
기존 방식의 한계나 현업의 요구사항을 해결하기 위해 이 개념이 등장했다는 흐름을 이해하는 데 목적이 있다.
3. 이유
도입 이유는 보통 유지보수성, 성능, 안정성, 보안, 협업 효율 같은 실무 문제를 해결하기 위함이다.
4. 특징
- 핵심 정의와 범위를 명확히 한다.
- 실무 적용 시 선택 기준과 비교 포인트를 제공한다.
- 예시 중심으로 빠른 이해를 돕는다.
5. 상세 내용
작성일: 2026-02-24 카테고리: Infra / DevOps / IaC 포함 내용: IaC, Terraform, OpenTofu, Pulumi, Ansible, Crossplane, GitOps, Declarative, Idempotency, State Management, Drift Detection, Immutable Infrastructure, Policy as Code, Blast Radius, Shift Left, 성숙도 모델
1. IaC란 무엇인가
핵심 정의
┌─────────────────────────────────────────────────────────────┐
│ │
│ Infrastructure as Code (IaC) │
│ │
│ 인프라(서버, 네트워크, DB, 보안규칙 등)를 │
│ 코드로 정의하고 관리하는 방법론 │
│ │
│ "서버를 콘솔에서 클릭하지 말고, 코드로 선언하라" │
│ │
│ 소프트웨어 엔지니어링 관행을 인프라에 적용: │
│ ├── 버전 관리 (Git) │
│ ├── 코드 리뷰 (PR) │
│ ├── 테스트 (Plan, Validate) │
│ └── CI/CD (자동 배포) │
│ │
└─────────────────────────────────────────────────────────────┘
IaC 이전의 세계
┌─────────────────────────────────────────────────────────────┐
│ │
│ IaC 이전: ClickOps의 시대 │
│ │
│ ├── 수동 서버 설정 (콘솔 클릭, SSH 접속 후 수동 작업) │
│ ├── 팀장만 아는 설정, 문서화 안 됨 │
│ │ └── "그건 김 과장이 세팅했는데 퇴사했어요" │
│ ├── 동일한 환경 재현 불가 │
│ │ └── "내 PC에서는 되는데?"의 인프라 버전 │
│ ├── 장애 시 복구에 수일 소요 │
│ │ └── 어떤 설정이 적용되어 있었는지 아무도 모름 │
│ ├── 변경 이력 추적 불가 │
│ │ └── "누가 보안그룹 열었어?" │
│ └── 환경 간 불일치 (dev ≠ staging ≠ prod) │
│ └── "스테이징에서 됐는데 프로덕션에서 안 돼요" │
│ │
└─────────────────────────────────────────────────────────────┘
IaC의 역사
┌─────────────────────────────────────────────────────────────┐
│ IaC 타임라인 │
│ │
│ 연도 이정표 │
│ ───── ────────────────────────────────────────────────── │
│ 1993 CFEngine (Mark Burgess, 오슬로대) │
│ └── 최초의 시스템 자동화 도구 │
│ │
│ 2005 Puppet (Luke Kanies) │
│ └── 선언적 DSL 도입 │
│ │
│ 2009 "Infrastructure as Code" 용어 탄생 │
│ └── Velocity Conference │
│ │
│ 2009 Chef (Adam Jacob) │
│ └── Ruby DSL 기반 구성 관리 │
│ │
│ 2012 Ansible (Michael DeHaan) │
│ └── 에이전트리스, SSH, YAML │
│ │
│ 2012 Martin Fowler │
│ └── Phoenix Server / Snowflake Server 개념 정립 │
│ │
│ 2014 Terraform 0.1 (HashiCorp) │
│ └── 클라우드 중립적 IaC의 시작 │
│ │
│ 2016 Kief Morris "Infrastructure as Code" 출판 │
│ └── O'Reilly, IaC의 바이블 │
│ │
│ 2017 GitOps 용어 탄생 │
│ └── Alexis Richardson, Weaveworks, KubeCon │
│ │
│ 2018 AWS CDK Developer Preview │
│ └── 프로그래밍 언어로 CloudFormation 생성 │
│ │
│ 2023 HashiCorp Terraform 라이선스 변경 (MPL → BUSL) │
│ └── 오픈소스 커뮤니티 분열 │
│ │
│ 2023 OpenTofu 프로젝트 탄생 (Linux Foundation) │
│ └── Terraform의 오픈소스 포크 │
│ │
│ 2025 Crossplane CNCF Graduation │
│ └── Kubernetes-native IaC 공식 인정 │
│ │
└─────────────────────────────────────────────────────────────┘
2. IaC의 이상적 형태 (Gold Standard Stack)
4계층 아키텍처
┌─────────────────────────────────────────────────────────────┐
│ │
│ Layer 4: GitOps + Policy as Code │
│ ArgoCD / Flux + OPA / Sentinel │
│ (Git = Single Source of Truth) │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Layer 3: Container Orchestration │
│ Kubernetes (CNCF 2025: 프로덕션 82% 사용) │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Layer 2: Configuration Management │
│ Ansible (에이전트리스, SSH, YAML) │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ Layer 1: Provisioning │
│ Terraform / OpenTofu / Pulumi │
│ (인프라 자체를 코드로: VPC, VM, RDS 등) │
│ │
└─────────────────────────────────────────────────────────────┘
각 레이어의 역할
| Layer | 도구 | 역할 | 관리 대상 |
|---|---|---|---|
| Provisioning | Terraform/OpenTofu | 클라우드 리소스 생성/관리 | VPC, EC2, RDS, S3, IAM |
| Config Mgmt | Ansible | OS 레벨 설정, SW 설치 | 패키지, 파일, 서비스, 사용자 |
| Orchestration | Kubernetes | 컨테이너 스케줄링 | Pod, Deployment, Service |
| GitOps | ArgoCD/Flux | Git → 클러스터 자동 동기화 | 모든 K8s 리소스 |
| Policy | OPA/Sentinel | 정책 자동 강제 | 보안, 비용, 규정 준수 |
레이어 간 상호작용 흐름
┌─────────────────────────────────────────────────────────────┐
│ │
│ 레이어 간 상호작용 (실제 배포 흐름) │
│ │
│ Step 1: 개발자가 terraform apply 실행 │
│ └── AWS VPC, EKS 클러스터 프로비저닝 │
│ │ │
│ ▼ │
│ Step 2: Ansible이 노드에 필수 SW, 보안 설정 적용 │
│ └── kubelet, 모니터링 에이전트, CIS 벤치마크 │
│ │ │
│ ▼ │
│ Step 3: EKS에 ArgoCD 설치 (Bootstrap) │
│ └── helm install argocd │
│ │ │
│ ▼ │
│ Step 4: ArgoCD가 Git 저장소 감시 시작 │
│ └── Git의 K8s 매니페스트 → 클러스터 자동 동기화 │
│ │ │
│ ▼ │
│ Step 5: OPA가 모든 배포에서 정책 위반 차단 │
│ └── "이미지 태그 latest 금지" │
│ └── "리소스 요청/제한 필수" │
│ └── "특권 컨테이너 금지" │
│ │
└─────────────────────────────────────────────────────────────┘
3. 핵심 용어와 개념
3-1. Declarative vs Imperative (선언적 vs 명령적)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Imperative (명령적) Declarative (선언적) │
│ ───────────────────── ───────────────────── │
│ │
│ "어떻게(How)"를 기술 "무엇(What)"을 선언 │
│ │
│ 각 단계를 순서대로 명시 원하는 최종 상태만 정의 │
│ │
│ "서버 생성 "3대의 nginx 서버가 │
│ → 포트 열기 포트 80에서 │
│ → 패키지 설치 실행 중이어야 한다" │
│ → 서비스 시작" │
│ │
│ 현재 상태를 모르면 도구가 현재 상태와 │
│ 어떤 명령을 내려야 비교해 필요한 액션 │
│ 할지 모름 자동 결정 │
│ │
│ 예: Bash Script 예: Terraform, K8s YAML │
│ │
└─────────────────────────────────────────────────────────────┘
왜 선언적이 표준이 되었는가
┌─────────────────────────────────────────────────────────────┐
│ │
│ 선언적 접근이 표준이 된 이유: │
│ │
│ 1. 멱등성이 자연스럽게 구현됨 │
│ └── "3대 필요" → 이미 3대면 아무것도 안 함 │
│ │
│ 2. 확장성 (규모 무관하게 동일한 코드) │
│ └── 서버 1대든 1000대든 선언 방식은 동일 │
│ │
│ 3. Drift 감지 가능 │
│ └── 현재 상태 vs 선언된 상태 비교 가능 │
│ │
│ 4. 코드만 봐도 인프라 최종 모습 파악 │
│ └── 문서 역할을 겸함 │
│ │
└─────────────────────────────────────────────────────────────┘
비교 예시: Terraform (선언적) vs Bash (명령적)
Terraform (선언적) - “무엇”을 선언:
# "이런 상태여야 한다"고 선언
resource "aws_instance" "web" {
count = 3
ami = "ami-0abcdef1234567890"
instance_type = "t3.medium"
tags = {
Name = "web-${count.index}"
Env = "production"
}
}
# 몇 번을 실행해도 결과는 동일
# 이미 3대 있으면 → 변경 없음
# 2대만 있으면 → 1대 추가
# 4대 있으면 → 1대 삭제
Bash (명령적) - “어떻게”를 나열:
#!/bin/bash
# 문제: 두 번 실행하면 6대가 됨
for i in 1 2 3; do
aws ec2 run-instances \
--image-id ami-0abcdef1234567890 \
--instance-type t3.medium \
--tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=web-$i}]"
done
# 멱등성 확보하려면 직접 구현해야 함:
# - 기존 인스턴스 조회
# - 개수 비교
# - 부족하면 생성, 초과하면 삭제
# - 에러 핸들링...
# → 결국 Terraform을 다시 만드는 셈
3-2. Idempotency (멱등성)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 멱등성 (Idempotency) │
│ │
│ 정의: 동일한 작업을 여러 번 실행해도 │
│ 항상 같은 결과를 보장하는 성질 │
│ │
│ 수학적 표현: f(f(x)) = f(x) │
│ │
│ 예시: │
│ ├── Terraform: "3대 서버 필요" │
│ │ ├── 1회 실행: 3대 생성 │
│ │ ├── 2회 실행: 변경 없음 (이미 3대) │
│ │ └── 3회 실행: 변경 없음 (이미 3대) │
│ │ │
│ ├── Bash Script: "서버 생성" │
│ │ ├── 1회 실행: 3대 생성 │
│ │ ├── 2회 실행: 6대 (중복!) │
│ │ └── 3회 실행: 9대 (더 중복!) │
│ │ │
│ └── 결론: 멱등성 = IaC의 기본 전제 │
│ │
└─────────────────────────────────────────────────────────────┘
왜 멱등성이 등장했는가
┌─────────────────────────────────────────────────────────────┐
│ │
│ 멱등성이 필요한 이유: │
│ │
│ 1. 환경 일관성 │
│ └── dev/staging/prod를 동일하게 재현 가능 │
│ │
│ 2. 중복 리소스 방지 │
│ └── 실수로 두 번 실행해도 안전 │
│ │
│ 3. CI/CD 실패 후 재시도 안전 │
│ └── 파이프라인 중간에 실패해도 처음부터 재실행 가능 │
│ │
│ 4. Self-healing (자가 치유) 가능 │
│ └── 주기적으로 apply 해서 원하는 상태로 수렴 │
│ │
│ 5. "이 스크립트 실행했나?" 확인 오버헤드 제거 │
│ └── 몇 번을 실행해도 결과가 같으므로 걱정 불필요 │
│ │
└─────────────────────────────────────────────────────────────┘
3-3. State Management (상태 관리)
┌─────────────────────────────────────────────────────────────┐
│ │
│ State Management (상태 관리) │
│ │
│ 왜 필요한가: │
│ ├── Terraform은 실제 인프라와 코드 사이의 │
│ │ 매핑을 추적해야 함 │
│ ├── "AWS의 이 EC2가 내 코드의 어느 리소스인가?" │
│ └── 상태 파일 없이는 Plan(실행계획) 계산 불가 │
│ │
│ .tfstate 파일의 역할: │
│ ├── 리소스 ID 매핑 (코드 이름 ↔ 실제 리소스) │
│ ├── 메타데이터 저장 (의존성, 속성 값) │
│ ├── 캐시 역할 (매번 API 호출 최소화) │
│ └── Plan 시 diff 계산의 기준점 │
│ │
└─────────────────────────────────────────────────────────────┘
로컬 State의 문제
┌─────────────────────────────────────────────────────────────┐
│ │
│ 로컬 State 파일의 문제점: │
│ │
│ 1. 팀 협업 불가 │
│ └── 각자 다른 .tfstate → 충돌, 덮어쓰기 │
│ │
│ 2. 상태 파일 손실 = 인프라 제어 불능 │
│ └── 노트북 고장 → 인프라는 있는데 관리 못 함 │
│ │
│ 3. 동시 실행 → Race Condition │
│ └── 두 사람이 동시에 apply → 상태 꼬임 │
│ │
│ 4. 민감 정보 평문 저장 │
│ └── DB 비밀번호가 .tfstate에 그대로 노출 │
│ │
└─────────────────────────────────────────────────────────────┘
Remote State 해결책
┌─────────────────────────────────────────────────────────────┐
│ │
│ Remote State = 팀 협업의 기본 │
│ │
│ 방법 1: S3 + DynamoDB │
│ ├── S3: 상태 파일 저장 (버전 관리, 암호화) │
│ └── DynamoDB: 잠금(Locking) 제공 │
│ │
│ 방법 2: Terraform Cloud / HCP │
│ ├── 자동 잠금, 실행 이력, 접근 제어 │
│ └── 무료 티어: 최대 500 리소스 │
│ │
│ 방법 3: OpenTofu + 암호화 │
│ └── Native State Encryption 지원 (Terraform엔 없음) │
│ │
│ Bootstrap 문제 (닭-달걀): │
│ ├── "S3를 만들려면 Terraform이 필요" │
│ ├── "Terraform 상태를 S3에 저장하려면 S3가 필요" │
│ └── 해결: 최초 S3/DynamoDB는 로컬 state로 생성 후 │
│ terraform state push로 마이그레이션 │
│ │
└─────────────────────────────────────────────────────────────┘
Remote Backend 설정 예시:
# backend.tf
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/network/terraform.tfstate"
region = "ap-northeast-2"
encrypt = true
dynamodb_table = "terraform-lock"
}
}
# DynamoDB 잠금 테이블 (bootstrap 단계에서 생성)
resource "aws_dynamodb_table" "terraform_lock" {
name = "terraform-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
3-4. Configuration Drift (설정 드리프트)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Configuration Drift (설정 드리프트) │
│ │
│ 정의: 실제 인프라 상태가 IaC 코드에서 │
│ 점진적으로 벗어나는 현상 │
│ │
│ 시간 경과에 따른 Drift: │
│ │
│ 코드 상태 ─────────────────────────── (고정) │
│ ↗ │
│ 실제 상태 ───────/──────────────────── (점점 벗어남) │
│ ▲ ▲ ▲ │
│ │ │ │ │
│ 수동변경 핫픽스 자동변경 │
│ │
└─────────────────────────────────────────────────────────────┘
Drift 발생 원인
┌─────────────────────────────────────────────────────────────┐
│ │
│ Drift가 발생하는 주요 원인: │
│ │
│ 1. 콘솔 수동 변경 (긴급 상황) │
│ └── "장애 나서 급하게 보안그룹 열었어요" │
│ │
│ 2. 외부 자동화 도구 간섭 │
│ └── 다른 팀의 Lambda가 리소스 태그 변경 │
│ │
│ 3. 핫픽스 미반영 │
│ └── 수동 변경 후 코드에 반영 안 함 │
│ │
│ 4. 클라우드 프로바이더 자동 변경 │
│ └── Auto Scaling, 자동 패치, 기본값 변경 │
│ │
│ 왜 문제인가: │
│ ├── "코드 = 인프라" 약속 위반 │
│ ├── 보안 규칙이 몰래 변경됨 (VPC 개방 등) │
│ ├── terraform plan 결과와 실제 불일치 │
│ └── 재해 복구 시 코드만으로 복원 불가 │
│ │
│ 감지 방법: │
│ $ terraform plan -refresh-only │
│ # 코드 변경 없이 실제 상태만 확인 │
│ # Drift가 있으면 차이를 보여줌 │
│ │
└─────────────────────────────────────────────────────────────┘
3-5. Immutable Infrastructure (불변 인프라)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Martin Fowler (2012) 개념 정립 │
│ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Snowflake Server (눈송이 서버) │ │
│ │ ├── 수동 변경이 누적 → 재현 불가 │ │
│ │ ├── "이 서버를 관리해온 사람만 이해" │ │
│ │ └── 눈송이처럼 각각 특별하고 취약 │ │
│ └───────────────────────────────────────────────────┘ │
│ │ 개선 │
│ ▼ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Phoenix Server (피닉스 서버) │ │
│ │ ├── "서버는 잿더미에서 다시 태어나야 한다" │ │
│ │ ├── 언제든 부수고 다시 만들 수 있어야 함 │ │
│ │ └── 프로비저닝 자동화 필수 │ │
│ └───────────────────────────────────────────────────┘ │
│ │ 발전 │
│ ▼ │
│ ┌───────────────────────────────────────────────────┐ │
│ │ Immutable Server (불변 서버) │ │
│ │ ├── Phoenix의 논리적 결론 │ │
│ │ ├── 배포 후 절대 수정하지 않음 │ │
│ │ └── 변경 = 새 이미지 빌드 후 교체 │ │
│ └───────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
왜 “수정”보다 “교체”가 나은가
┌─────────────────────────────────────────────────────────────┐
│ │
│ Mutable (수정) Immutable (교체) │
│ ────────────── ─────────────── │
│ │
│ v1 서버에 패치 적용 v2 이미지 새로 빌드 │
│ → Drift 발생 가능 → Drift 원천 차단 │
│ │
│ 인스턴스마다 상태 다를 수 모든 인스턴스 동일 보장 │
│ 있음 (패치 실패 등) (같은 이미지에서 생성) │
│ │
│ 롤백 = 역방향 패치 롤백 = 이전 이미지로 교체 │
│ (실패 위험) (안전하고 빠름) │
│ │
│ 구현 방법: │
│ ├── Docker 이미지 (컨테이너) │
│ ├── Golden AMI (Packer로 빌드) │
│ └── VM Image (Packer + cloud-init) │
│ │
│ CI/CD와 자연스러운 통합: │
│ 코드 변경 → 이미지 빌드 → 테스트 → 교체 배포 │
│ │
└─────────────────────────────────────────────────────────────┘
3-6. GitOps
┌─────────────────────────────────────────────────────────────┐
│ │
│ GitOps │
│ │
│ 역사: 2017년 Alexis Richardson (Weaveworks CEO) │
│ KubeCon에서 최초 사용 │
│ "Operations by Pull Request" │
│ │
│ 핵심 원칙: │
│ ├── 1. Git = Single Source of Truth │
│ │ 모든 인프라/앱 설정이 Git에 존재 │
│ │ │
│ ├── 2. 선언적 설정만 사용 │
│ │ "무엇"이 배포되어야 하는지 YAML로 선언 │
│ │ │
│ └── 3. 자동화 에이전트가 실제 상태를 │
│ 원하는 상태로 지속 수렴 (Reconciliation) │
│ │
│ 2025년 현황: │
│ ├── Weaveworks 2024년 파산 → ArgoCD가 사실상 표준 │
│ └── CNCF 2025: Innovators의 58%가 GitOps 광범위 사용 │
│ │
└─────────────────────────────────────────────────────────────┘
Pull vs Push 모델
┌─────────────────────────────────────────────────────────────┐
│ │
│ Push (전통적 CI/CD) Pull (GitOps 원본) │
│ ───────────────────── ───────────────────── │
│ │
│ CI가 배포 시스템에 클러스터 내 에이전트가 │
│ Push Git을 Pull │
│ │
│ ┌────┐ push ┌─────┐ ┌─────┐ pull ┌────┐ │
│ │ CI │───────→│Cluster│ │Agent│←──────│ Git│ │
│ └────┘ └─────┘ └──┬──┘ └────┘ │
│ │ apply │
│ ▼ │
│ ┌─────┐ │
│ │K8s │ │
│ └─────┘ │
│ │
│ 보안: 외부→클러스터 보안: 클러스터가 외부에 │
│ 자격증명 필요 노출 안 함 (더 안전) │
│ │
│ 도구: Jenkins, GitLab CI 도구: ArgoCD, Flux │
│ │
│ 장점: 설정 간단 장점: 보안, Drift 자동 수정 │
│ 단점: 보안 취약 단점: 초기 구축 복잡 │
│ │
└─────────────────────────────────────────────────────────────┘
3-7. Policy as Code (정책을 코드로)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Policy as Code │
│ │
│ 왜 등장했는가: │
│ ├── 기존: 보안팀이 PDF로 정책 작성 │
│ │ └── 수동 확인 → 배포 후 감사 │
│ ├── 문제: 실수, 일관성 부족, 발견이 너무 늦음 │
│ └── 해결: 정책을 코드화 → CI/CD에서 자동 실행 │
│ │
│ 주요 도구: │
│ ├── OPA (Open Policy Agent) │
│ │ ├── CNCF Graduated 프로젝트 │
│ │ ├── Rego 언어 │
│ │ └── 업계 표준, 범용적 │
│ │ │
│ ├── Sentinel │
│ │ ├── HashiCorp 전용 │
│ │ └── Terraform Cloud/Enterprise 내장 │
│ │ │
│ └── Checkov / Terrascan │
│ ├── IaC 정적 분석 도구 │
│ └── terraform plan 결과를 검사 │
│ │
└─────────────────────────────────────────────────────────────┘
OPA Rego 정책 예시:
# deny_public_s3.rego
# S3 버킷의 퍼블릭 접근 차단 정책
package terraform.s3
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket"
resource.change.after.acl == "public-read"
msg := sprintf(
"S3 버킷 '%s'에 퍼블릭 접근이 허용되어 있습니다. 보안 정책 위반.",
[resource.name]
)
}
deny[msg] {
resource := input.resource_changes[_]
resource.type == "aws_s3_bucket_public_access_block"
resource.change.after.block_public_acls == false
msg := "S3 퍼블릭 접근 차단이 비활성화되어 있습니다."
}
3-8. Secret Management (비밀 관리)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Secret Management (비밀 관리) │
│ │
│ 왜 중요한가: │
│ ├── IaC를 Git에 저장하면 비밀도 안전하게 관리해야 함 │
│ ├── .tfstate에 DB 비밀번호가 평문으로 저장됨 │
│ └── Git 히스토리에 한 번 올라간 시크릿은 영구 노출 │
│ │
│ 주요 도구 비교: │
│ ┌────────────────────┬─────────────────────────────┐ │
│ │ 도구 │ 특징 │ │
│ ├────────────────────┼─────────────────────────────┤ │
│ │ HashiCorp Vault │ Dynamic Secrets │ │
│ │ │ 자동 만료, 감사 로그 │ │
│ │ │ 가장 강력하지만 운영 복잡 │ │
│ ├────────────────────┼─────────────────────────────┤ │
│ │ Sealed Secrets │ Git-safe 비대칭 암호화 │ │
│ │ │ ArgoCD/Flux 통합 │ │
│ │ │ K8s 환경 전용 │ │
│ ├────────────────────┼─────────────────────────────┤ │
│ │ External Secrets │ 브릿지 패턴 │ │
│ │ Operator (ESO) │ AWS/GCP/Azure Secret Mgr │ │
│ │ │ → K8s Secret 자동 동기화 │ │
│ └────────────────────┴─────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
External Secrets Operator 예시:
# external-secret.yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: db-credentials
spec:
refreshInterval: 1h # 1시간마다 동기화
secretStoreRef:
name: aws-secrets-manager
kind: ClusterSecretStore
target:
name: db-credentials # 생성될 K8s Secret 이름
data:
- secretKey: username
remoteRef:
key: prod/database # AWS Secrets Manager 키
property: username
- secretKey: password
remoteRef:
key: prod/database
property: password
3-9. Blast Radius (폭발 반경)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Blast Radius (폭발 반경) │
│ │
│ 정의: 실수/오류 발생 시 영향 받는 인프라의 범위 │
│ │
│ 큰 Blast Radius (위험): │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 하나의 거대한 terraform apply │ │
│ │ ├── VPC │ │
│ │ ├── EC2 x 50 │ │
│ │ ├── RDS │ │
│ │ ├── IAM │ │
│ │ └── 실수 하나 → 전체 인프라 영향 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 작은 Blast Radius (안전): │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ network/ │ │ compute/ │ │ database/│ │
│ │ VPC, SG │ │ EC2, ASG │ │ RDS, DDB │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ 실수 → 해당 모듈만 영향 │
│ │
└─────────────────────────────────────────────────────────────┘
Blast Radius 최소화 전략
┌─────────────────────────────────────────────────────────────┐
│ │
│ 최소화 전략: │
│ │
│ 1. 모듈화 │
│ └── 큰 단일 파일 → 작은 모듈로 분리 │
│ └── network/, compute/, database/, iam/ │
│ │
│ 2. 리소스 보호 │
│ └── lifecycle { prevent_destroy = true } │
│ └── 실수로 DB 삭제 방지 │
│ │
│ 3. 계정 분리 │
│ └── dev/staging/prod를 다른 AWS Account로 │
│ └── AWS Organizations + OU 활용 │
│ │
│ 4. 단계적 배포 │
│ └── 변경을 점진적으로 (Canary, Blue/Green) │
│ └── 한 번에 전체 적용하지 않음 │
│ │
│ 5. 의존성 명확화 │
│ └── 모듈 간 의존성 문서화 │
│ └── 버전 핀닝 (version = "~> 3.0") │
│ │
└─────────────────────────────────────────────────────────────┘
리소스 보호 예시:
resource "aws_db_instance" "production" {
identifier = "prod-main-db"
engine = "postgresql"
instance_class = "db.r6g.xlarge"
# Blast Radius 최소화: 실수로 삭제 방지
lifecycle {
prevent_destroy = true
}
# 삭제 보호 활성화
deletion_protection = true
# 최종 스냅샷 필수
skip_final_snapshot = false
final_snapshot_identifier = "prod-main-db-final"
}
3-10. Shift Left (왼쪽으로 이동)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Shift Left (왼쪽으로 이동) │
│ │
│ 정의: 테스트/보안/품질 검사를 │
│ 개발 라이프사이클 초기(왼쪽)로 이동 │
│ │
│ 왜: 배포 후 발견된 취약점 수정 비용 = 100배 이상 │
│ │
│ IaC 파이프라인에서의 Shift Left: │
│ │
│ ◀── 왼쪽 (빠른 발견, 저렴) 오른쪽 (늦은 발견, 비쌈) ─▶│
│ │
│ ┌────────┐ ┌──────┐ ┌────┐ ┌──────┐ ┌──────┐ ┌───────┐ │
│ │IDE │→│Pre- │→│CI │→│Plan │→│Policy│→│Runtime│ │
│ │Plugin │ │commit│ │ │ │Review│ │Check │ │Monitor│ │
│ └────────┘ └──────┘ └────┘ └──────┘ └──────┘ └───────┘ │
│ tflint tfsec fmt plan OPA CloudTrail │
│ tfsec validate lint cost Sentinel Prometheus │
│ test estimate Checkov │
│ │
│ ◀── 여기서 잡을수록 비용이 적다 │
│ │
└─────────────────────────────────────────────────────────────┘
Pre-commit Hook 설정 예시:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/antonbabenko/pre-commit-tf
rev: v1.88.0
hooks:
- id: terraform_fmt # 코드 포맷팅
- id: terraform_validate # 문법 검증
- id: terraform_tflint # 린트 검사
- id: terraform_tfsec # 보안 스캐닝
- id: terraform_docs # 문서 자동 생성
- id: terraform_checkov # 정책 검사
4. 주요 도구 비교
종합 비교표
| 항목 | Terraform/OpenTofu | Pulumi | CloudFormation/CDK | Ansible | Crossplane |
|---|---|---|---|---|---|
| 유형 | Provisioning | Provisioning | Provisioning | Config Mgmt | K8s-native IaC |
| 언어 | HCL | TypeScript/Python/Go | JSON/YAML (CDK: TS/Py) | YAML | YAML (CRD) |
| 클라우드 | 멀티 | 멀티 | AWS only | 멀티 | 멀티 |
| 상태 관리 | .tfstate | Pulumi Cloud | CloudFormation 내부 | 없음 | K8s API |
| 에이전트 | 없음 | 없음 | 없음 | 없음 (SSH) | Controller |
| GitOps | 별도 구현 | 별도 구현 | 별도 구현 | 별도 구현 | 네이티브 |
| 러닝 커브 | 중간 (HCL 학습) | 낮음 (기존 언어) | 높음 (AWS 종속) | 낮음 (YAML) | 높음 (K8s 필수) |
| 커뮤니티 | 매우 큼 | 성장 중 | AWS 내부 | 매우 큼 | 성장 중 |
Terraform vs OpenTofu
┌─────────────────────────────────────────────────────────────┐
│ │
│ Terraform vs OpenTofu │
│ │
│ 배경: │
│ ├── 2023년 8월: HashiCorp Terraform 라이선스 변경 │
│ │ └── MPL 2.0 (오픈소스) → BUSL 1.1 (상업적 제한) │
│ ├── 2023년 9월: OpenTofu 탄생 (Linux Foundation) │
│ ├── 2024년 1월: OpenTofu v1.0 안정 버전 출시 │
│ └── 2024년: IBM이 HashiCorp를 인수 │
│ │
│ 주요 차이: │
│ ┌─────────────────┬────────────────┬──────────────────┐ │
│ │ 항목 │ Terraform │ OpenTofu │ │
│ ├─────────────────┼────────────────┼──────────────────┤ │
│ │ 라이선스 │ BUSL 1.1 │ MPL 2.0 (OSS) │ │
│ │ State 암호화 │ 없음 │ Native 지원 │ │
│ │ 거버넌스 │ HashiCorp │ Linux Foundation │ │
│ │ 호환성 │ - │ TF 1.x 호환 │ │
│ │ Provider 지원 │ Registry 독점 │ 자체 Registry │ │
│ └─────────────────┴────────────────┴──────────────────┘ │
│ │
│ 채택 현황: │
│ ├── Spacelift 데이터: 배포의 절반이 OpenTofu 사용 │
│ └── Fidelity, Oracle, VMware가 OpenTofu로 공식 이전 │
│ │
└─────────────────────────────────────────────────────────────┘
Crossplane - Kubernetes-native IaC
┌─────────────────────────────────────────────────────────────┐
│ │
│ Crossplane │
│ │
│ 핵심 아이디어: │
│ ├── K8s CRD로 클라우드 리소스를 정의 │
│ ├── kubectl apply -f rds.yaml → 실제 AWS RDS 생성 │
│ ├── K8s reconciliation loop가 Drift 자동 수정 │
│ └── 상태 파일 별도 없음 (K8s API = Source of Truth) │
│ │
│ 장점: │
│ ├── Terraform과 달리 상태 파일 관리 불필요 │
│ ├── GitOps(ArgoCD)와 네이티브 통합 │
│ ├── K8s 운영 경험 그대로 활용 │
│ └── Drift 자동 수정 (reconciliation) │
│ │
│ 단점: │
│ ├── K8s 클러스터가 선행 조건 (닭-달걀 문제) │
│ ├── K8s 지식 필수 (러닝 커브) │
│ └── Terraform 대비 Provider 생태계 작음 │
│ │
│ 현황: │
│ ├── 2025년 CNCF Graduation │
│ └── Nike, Autodesk, NASA, SAP, IBM 사용 │
│ │
└─────────────────────────────────────────────────────────────┘
Crossplane RDS 예시:
# crossplane-rds.yaml
# kubectl apply만으로 실제 AWS RDS 생성
apiVersion: database.aws.crossplane.io/v1beta1
kind: RDSInstance
metadata:
name: prod-postgresql
spec:
forProvider:
region: ap-northeast-2
dbInstanceClass: db.r6g.xlarge
engine: postgres
engineVersion: "15"
masterUsername: admin
allocatedStorage: 100
vpcSecurityGroupIDRefs:
- name: db-security-group
writeConnectionSecretToRef:
name: db-conn
namespace: production
# 적용: kubectl apply -f crossplane-rds.yaml
# 삭제: kubectl delete -f crossplane-rds.yaml
# Drift: K8s가 자동으로 원래 상태로 복구
5. IaC 성숙도 모델
┌─────────────────────────────────────────────────────────────┐
│ │
│ IaC 성숙도 모델 (5단계) │
│ │
│ Level 4 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ Self-Correcting │
│ Level 3 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ Automated │
│ Level 2 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ Validated │
│ Level 1 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ Standardized │
│ Level 0 ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ Ad-Hoc (ClickOps) │
│ │
└─────────────────────────────────────────────────────────────┘
Level 0: Ad-Hoc (ClickOps)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Level 0: Ad-Hoc │
│ │
│ ├── 콘솔 클릭으로 인프라 구성 (ClickOps) │
│ ├── 문서화 없음, 개인 지식 의존 │
│ ├── 환경 재현 불가 │
│ ├── 변경 이력 추적 불가 │
│ └── "왜 이렇게 설정되어 있지?" → 아무도 모름 │
│ │
│ 특징: 서버가 "애완동물(Pet)" 취급 │
│ 이름 붙이고, 아프면 치료하고, 죽으면 슬퍼함 │
│ │
└─────────────────────────────────────────────────────────────┘
Level 1: Standardized (코드화)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Level 1: Standardized │
│ │
│ ├── Terraform으로 기본 인프라 코드화 │
│ ├── Git에 버전 관리 │
│ ├── 아직 자동 보안 검사 없음 │
│ ├── terraform apply를 로컬에서 수동 실행 │
│ └── State는 S3에 저장하기 시작 │
│ │
│ 특징: 서버가 "가축(Cattle)" 취급 시작 │
│ 번호를 매기고, 아프면 교체 │
│ │
│ 달성 기준: │
│ ├── 모든 인프라가 코드로 존재 │
│ ├── Git 저장소에서 관리 │
│ └── 팀원 누구나 환경 재현 가능 │
│ │
└─────────────────────────────────────────────────────────────┘
Level 2: Validated (검증)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Level 2: Validated │
│ │
│ ├── IaC가 CI/CD 파이프라인에 통합 │
│ ├── 정적 분석 자동 실행 (tflint, tfsec) │
│ ├── terraform plan 자동 실행 (PR에 결과 코멘트) │
│ ├── PR 기반 코드 리뷰 프로세스 │
│ └── 비용 추정 자동화 (Infracost) │
│ │
│ 달성 기준: │
│ ├── PR 없이는 인프라 변경 불가 │
│ ├── 자동화된 검증 단계 존재 │
│ └── 변경 전 영향도 파악 가능 │
│ │
└─────────────────────────────────────────────────────────────┘
Level 3: Automated (자동화)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Level 3: Automated │
│ │
│ ├── Policy as Code 자동 강제 (OPA, Sentinel) │
│ ├── Drift 자동 감지/수정 │
│ ├── GitOps 완전 자동화 배포 │
│ │ └── PR 머지 = 자동 apply (사람 개입 최소화) │
│ ├── 모듈 레지스트리 운영 │
│ │ └── 검증된 모듈을 팀 간 재사용 │
│ └── 보안 스캐닝이 배포 차단 가능 │
│ │
│ 달성 기준: │
│ ├── 수동 terraform apply 금지 │
│ ├── 정책 위반 시 자동 차단 │
│ └── Drift 발생 시 자동 알림/수정 │
│ │
└─────────────────────────────────────────────────────────────┘
Level 4: Self-Correcting (자기수정)
┌─────────────────────────────────────────────────────────────┐
│ │
│ Level 4: Self-Correcting │
│ │
│ ├── 자가 치유 인프라 (Self-healing) │
│ │ └── 이상 감지 → 자동 복구 → 알림 │
│ ├── AI 기반 이상 감지 │
│ │ └── 비용 이상, 성능 이상, 보안 이상 │
│ ├── Internal Developer Platform (IDP) │
│ │ └── 개발자가 Terraform 모르고도 인프라 요청 │
│ │ └── Backstage, Port, Humanitec │
│ ├── FinOps 통합 │
│ │ └── 비용 최적화 자동 권고/실행 │
│ └── 완전한 셀프서비스 │
│ └── 개발자: "PostgreSQL 필요" → 자동 프로비저닝 │
│ │
│ 달성 기준: │
│ ├── 인프라팀 개입 없이 개발자 셀프서비스 │
│ ├── 장애 자동 복구율 90% 이상 │
│ └── 비용 이상 자동 감지/조치 │
│ │
└─────────────────────────────────────────────────────────────┘
현실 진단
┌─────────────────────────────────────────────────────────────┐
│ │
│ 현실: 대부분 Level 2~3 사이에서 정체 │
│ │
│ HashiCorp 2024 State of Cloud Strategy 조사: │
│ │
│ 고성숙도 (Level 3~4): 8% ██ │
│ 중성숙도 (Level 2): 59% ████████████████████████ │
│ 저성숙도 (Level 0~1): 33% █████████████ │
│ │
│ 정체 원인: │
│ ├── 조직 문화: "잘 되고 있는데 왜 바꿔?" │
│ ├── 기술 부채: 레거시 ClickOps 인프라 마이그레이션 비용 │
│ ├── 인력: IaC + K8s + GitOps 모두 아는 사람 부족 │
│ └── 닭-달걀: Platform 팀 없이 Platform 구축 불가 │
│ │
│ Level 3 → 4 전환의 핵심: │
│ ├── Platform Engineering 팀 구성 │
│ ├── IDP 도입 (Backstage 등) │
│ └── 개발자 경험(DX) 중심 설계 │
│ │
└─────────────────────────────────────────────────────────────┘
6. 개념들의 연결 관계
┌─────────────────────────────────────────────────────────────┐
│ │
│ IaC 핵심 개념의 연결 관계 │
│ │
│ 선언적 접근 (Declarative) │
│ │ │
│ └──→ 멱등성 (Idempotency) 자연스럽게 달성 │
│ │ │
│ └──→ State Management로 현재 상태 추적 │
│ │ │
│ └──→ Drift Detection으로 차이 감지 │
│ │ │
│ └──→ Immutable Infra로 Drift 차단 │
│ │ │
│ └──→ GitOps로 모든 변경이 │
│ Git 경유 │
│ │ │
│ └──→ Policy as Code로│
│ 정책 자동 강제 │
│ │ │
│ └──→ IDP로 │
│ 셀프서비스│
│ │
│ ───────────────────────────────────────────────────────── │
│ │
│ 이 모든 것을 관통하는 원칙: │
│ │
│ ├── Shift Left: 문제를 최대한 일찍 발견 │
│ ├── Blast Radius: 실수의 영향 범위를 최소화 │
│ └── Secret Management: 비밀은 코드에 절대 하드코딩 금지 │
│ │
└─────────────────────────────────────────────────────────────┘
실무 적용 순서 (권장)
┌─────────────────────────────────────────────────────────────┐
│ │
│ 단계별 도입 권장 순서: │
│ │
│ Phase 1: 기반 구축 (1~3개월) │
│ ├── Terraform/OpenTofu로 주요 리소스 코드화 │
│ ├── Remote State 설정 (S3 + DynamoDB) │
│ ├── Git 저장소 구조 설계 │
│ └── 모듈화 기본 적용 │
│ │
│ Phase 2: 자동화 (3~6개월) │
│ ├── CI/CD 파이프라인에 plan/apply 통합 │
│ ├── Pre-commit hooks 설정 │
│ ├── PR 기반 리뷰 프로세스 수립 │
│ └── 비용 추정 도구 도입 (Infracost) │
│ │
│ Phase 3: 거버넌스 (6~12개월) │
│ ├── Policy as Code 도입 (OPA/Sentinel) │
│ ├── Drift Detection 자동화 │
│ ├── Secret Management 체계화 (Vault/ESO) │
│ └── 모듈 레지스트리 구축 │
│ │
│ Phase 4: 플랫폼 (12개월+) │
│ ├── GitOps 도입 (ArgoCD) │
│ ├── IDP 구축 (Backstage) │
│ ├── 개발자 셀프서비스 포털 │
│ └── FinOps 통합 │
│ │
└─────────────────────────────────────────────────────────────┘
관련 키워드
IaC, Infrastructure as Code, Terraform, OpenTofu, Pulumi, Ansible, Crossplane, GitOps, ArgoCD, Flux, Declarative, Idempotency, State Management, Configuration Drift, Immutable Infrastructure, Phoenix Server, Snowflake Server, Policy as Code, OPA, Sentinel, Blast Radius, Shift Left, Secret Management, Vault, HCL, 성숙도 모델, ClickOps