CertNote/ 출퇴근 학습 노트
로드맵
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
  • Week 1
    • 1.개발자 시점에서 본 AWS: 리전, 인프라, 그리고 책임의 경계
    • 2.IAM의 4대 엔터티: User, Group, Role, Policy
    • 3.STS와 정책 조건: 임시 자격증명의 깊은 세계
    • 4.AWS CLI와 SDK: 자격증명 체이닝부터 SigV4까지
    • 5.Week 1 종합: 인프라와 IAM이 만드는 신뢰의 사슬
  • Week 2
  • Week 3
  • Week 4
  • Week 5
  • Week 6
  • Week 7
  • Week 8
  • Week 9
  • Week 10
  • Week 11
  • Week 12
    • 1.ECS와 Fargate: 컨테이너를 "서버 없이" 돌린다는 말의 진짜 의미
    • 2.CloudFormation: 인프라를 "선언"한다는 발상
    • 3.SAM: 서버리스를 위해 CloudFormation을 압축하다
    • 4.CDK와 서버리스 아키텍처: "인프라를 코드로 쓴다"의 끝, 그리고 좋은 설계의 문법
    • 5.Week 12 종합 복습: 컨테이너와 IaC를 하나의 그림으로 꿰기
  • Week 13
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
SCS-C03 · SpecialtySecurity - Specialty
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
합격 후기

© CertNote · 주간랩스

  • 소개
  • 수정 기록
  • 문의
  • 이용약관
  • 개인정보처리방침
← DVA-C02/Week 12/Day 2

기준: DVA-C02 시험 가이드·오류 제보

DVA-C02· AssociateWeek 12 · Day 2읽기 약 18분

Day 2 - CloudFormation: 인프라를 "선언"한다는 발상

서버 한 대를 콘솔에서 클릭으로 만드는 건 쉽다. 그런데 VPC, 서브넷, 보안 그룹, EC2, RDS, ALB, Lambda 수십 개를 클릭으로 만들고, 그걸 스테이징·프로덕션에 똑같이 복제하고, 6개월 뒤에 "이 보안 그룹이 왜 이렇게 열려 있지?"를 추적하려 하면 지옥이 시작된다. 손으로 만든 인프라는 재현할 수 없고, 변경 이력이 없으며, 사람의 기억에만 의존한다. 인프라를 코드로(Infrastructure as Code, IaC) 정의한다는 발상은 이 문제를 정면으로 겨냥한다. 인프라를 텍스트 파일에 선언하면 버전 관리(git)와 코드 리뷰가 가능해지고, 똑같은 환경을 명령 한 번으로 재생산할 수 있다. AWS CloudFormation은 이 IaC를 AWS 위에서 구현한 서비스다.

DVA-C02에서 CloudFormation은 배포 도메인의 중심축이고, SAM·CDK의 기반이라 반드시 알아야 한다. 단순 암기(!Ref vs !GetAtt, DeletionPolicy)도 다루지만, 동작 원리를 묻는 시나리오도 있다. 예를 들면 "스택 업데이트가 왜 위험한가", "롤백은 어떻게 동작하나", "교차 스택 참조의 함정"이다.

이번 글은 네 가지를 다룬다.

  • 선언적 IaC가 명령적 스크립트와 무엇이 다른지
  • CloudFormation이 어떻게 의존 그래프를 풀어 생성 순서를 정하는지
  • 스택 업데이트와 롤백의 내부 동작
  • 여러 보호 메커니즘이 갈라지는 이유

선언적 대 명령적: "무엇을"과 "어떻게"의 차이

CloudFormation 템플릿을 처음 보면 "그냥 설정 파일 아닌가" 싶지만, 그 밑에는 선언적(declarative) 모델이라는 중요한 철학이 있다. 선언적 IaC는 "무엇을 원하는지(원하는 최종 상태)"만 적고, "그것을 어떻게 만들지(생성 순서, API 호출, 에러 처리, 롤백)"는 CloudFormation 엔진에 맡긴다. 반대로 bash 스크립트로 aws ec2 create-vpc → aws ec2 create-subnet → ...을 순서대로 적는 것은 명령적(imperative) 모델이다.

이 차이가 실무에서 결정적이다. 명령적 스크립트는 "절반 실행되다 실패하면" 어중간한 상태로 남는다 — VPC는 만들어졌는데 서브넷에서 실패하면, 그 VPC를 정리할 책임이 사람에게 있다. 선언적 모델은 "원하는 상태"와 "현재 상태"의 차이를 엔진이 계산하므로, 두 번 실행해도 같은 결과가 나오는 멱등성(idempotency) 을 가지고, 실패하면 엔진이 알아서 자동 롤백한다. "내가 시키는 대로 하라"가 아니라 "이 상태가 되게 하라"는 것이다.

AWSTemplateFormatVersion: '2010-09-09'
Description: My Application Stack
 
Parameters:
  EnvironmentName:
    Type: String
    Default: production
    AllowedValues: [production, staging, development]
 
Conditions:
  IsProduction: !Equals [!Ref EnvironmentName, production]
 
Mappings:
  RegionAMI:
    ap-northeast-2: { AMI: ami-0c9c942bd7bf113a2 }
    us-east-1:      { AMI: ami-0abcdef1234567890 }
 
Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      Tags: [{ Key: Name, Value: !Sub "${EnvironmentName}-vpc" }]
 
  MyEC2:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !If [IsProduction, m5.large, t3.micro]
      ImageId: !FindInMap [RegionAMI, !Ref AWS::Region, AMI]
 
Outputs:
  VPCId:
    Value: !Ref MyVPC
    Export:
      Name: !Sub "${EnvironmentName}-vpc-id"

선언적 모델의 핵심 가치는 수렴(convergence) 이다 — 시스템이 어떤 상태에서 출발하든 선언된 목표 상태로 수렴한다. 이는 구성 관리 도구의 오랜 계보(Puppet 2005, Chef 2009, Ansible 2012)가 공유하는 철학이고, 더 근본적으로는 함수형 프로그래밍의 "무엇을 계산할지 기술하되 어떻게 계산할지는 런타임에 맡긴다"와 닮았다. CloudFormation, Terraform, 쿠버네티스 매니페스트가 모두 선언적인 이유는, 분산 인프라에서 "사람이 모든 순서와 에러를 손으로 챙기는 것"이 본질적으로 불가능에 가깝기 때문이다. 엔진에게 그 복잡성을 떠넘기는 것이 선언형의 본질이다.

CloudFormation은 생성 순서를 어떻게 정하는가: 의존 그래프

템플릿에 EC2와 그것이 속할 VPC, 보안 그룹을 적었을 때, CloudFormation은 무엇을 먼저 만들어야 하는지 어떻게 알까? 답은 의존 그래프(dependency graph) 다. CloudFormation은 템플릿을 파싱하면서 리소스 간 참조를 추출한다 — EC2가 !Ref MyVPC로 VPC를 참조하면 "EC2는 VPC에 의존한다"는 간선이 생긴다. 이렇게 만들어진 방향 그래프를 위상 정렬(topological sort) 해서, 의존되는 것부터(VPC → 서브넷 → EC2) 순서대로 만들고, 서로 의존하지 않는 리소스들은 병렬로 생성한다.

그래서 대부분의 경우 DependsOn을 명시할 필요가 없다 — !Ref나 !GetAtt로 다른 리소스를 참조하면 의존성이 자동으로 추론된다. DependsOn은 그 자동 추론이 닿지 않는 "암묵적 의존"을 강제할 때만 쓴다(예: IAM 역할이 실제로 전파되기 전에 그걸 쓰는 리소스가 만들어지면 안 될 때).

!Ref와 !GetAtt의 차이는 단순 암기를 넘어 의존 그래프의 작동과 연결된다. !Ref MyVPC는 보통 그 리소스의 "기본 식별자"(VPC면 VPC ID)를 돌려주고, !GetAtt MyRDS.Endpoint.Address는 특정 속성을 콕 집어 가져온다. 둘 다 "이 값을 알려면 그 리소스가 먼저 만들어져야 한다"는 의존성을 만든다. 그런데 !GetAtt가 가져오는 속성 중에는 리소스가 완전히 프로비저닝된 뒤에야 정해지는 것이 있다(RDS 엔드포인트 주소는 DB가 다 떠야 알 수 있다). 그래서 RDS 엔드포인트를 !GetAtt로 참조하는 리소스는 RDS의 생성 완료까지 기다리게 되고, 이게 스택 생성이 길어지는 원인이 된다.

⚠️ 함정: 두 리소스가 서로를 참조하면 순환 의존(circular dependency) 이 생겨 스택 생성이 실패한다. 예를 들어 보안 그룹 A가 B를 인바운드로 참조하고 B가 A를 참조하면 위상 정렬이 불가능하다. 해법은 인라인 규칙 대신 별도의 SecurityGroupIngress 리소스로 규칙을 떼어내 순환을 끊는 것이다. 시험에서 "circular dependency" 에러가 보이면 이 패턴을 의심한다.

스택 업데이트의 세 가지 운명: 수정, 교체, 중단 없는 변경

CloudFormation에서 가장 위험한 순간은 생성이 아니라 업데이트다. 이미 떠 있는 프로덕션 스택의 템플릿을 바꿔 적용할 때, CloudFormation은 변경된 각 리소스를 세 갈래 중 하나로 처리한다.

  • 중단 없는 수정(No interruption): 리소스를 유지한 채 속성만 바꾼다. 예: EC2 태그 변경, Lambda 환경 변수 변경. 가장 안전하다.
  • 일부 중단(Some interruption): 리소스는 유지되지만 잠깐 멈춘다. 예: EC2 인스턴스 타입 변경(재시작 필요).
  • 교체(Replacement): 리소스를 새로 만들고 기존 것을 삭제한다. 이게 가장 위험하다 — 어떤 속성은 변경 불가(immutable)라, 바꾸려면 통째로 새 리소스를 만들어야 한다. 예: EC2의 AZ나 일부 RDS 설정, 이름이 식별자인 리소스의 이름 변경.

교체가 무서운 이유는 명확하다. RDS 데이터베이스가 교체되면 새 빈 DB가 만들어지고 기존 데이터가 사라질 수 있다. 그래서 "어떤 속성이 교체를 유발하는지"를 모르고 템플릿을 고치면 데이터 손실 사고가 난다. 바로 이 위험을 미리 보기 위해 Change Set이 존재한다.

aws cloudformation create-change-set \
    --stack-name my-stack --template-body file://template.yaml \
    --change-set-name my-changes
aws cloudformation describe-change-set \
    --stack-name my-stack --change-set-name my-changes   # Replacement: True 확인
aws cloudformation execute-change-set \
    --stack-name my-stack --change-set-name my-changes

Change Set은 "이번 업데이트로 무엇이 추가/수정/삭제되고, 어떤 게 교체(Replacement: True)되는지"를 실행 전에 보여준다. 프로덕션 배포의 안전 장치로, "DB가 교체된다"는 경고를 미리 보고 멈출 수 있다.

CloudFormation으로 RDS를 관리하다 DBInstanceIdentifier나 특정 엔진 속성을 바꿔 의도치 않은 교체가 일어나 데이터를 날리는 사고는 IaC 운영의 고전적 함정이다. AWS가 권장하는 방어는 두 겹이다. 첫째, DeletionPolicy: Snapshot 또는 Retain 을 RDS/EBS에 걸어 삭제·교체 시 데이터를 보존한다. 둘째, Change Set으로 Replacement 여부를 항상 확인한다. 실무에서 "직접 update를 절대 하지 말고 반드시 Change Set을 거쳐라"가 철칙이 된 배경이다.

자동 롤백: 실패하면 시간을 되돌린다

선언적 모델의 가장 강력한 안전망이 자동 롤백(automatic rollback) 이다. 스택 생성이나 업데이트 중 한 리소스라도 실패하면, CloudFormation은 그때까지 만든 것을 그대로 두지 않고 직전의 안정 상태로 되돌린다. 생성 중 실패면 만든 것을 모두 삭제(ROLLBACK_COMPLETE)하고, 업데이트 중 실패면 이전 템플릿 상태로 복구(UPDATE_ROLLBACK_COMPLETE)한다. 이게 명령적 스크립트와의 결정적 차이다 — 스크립트는 절반 실행된 채 방치되지만, CloudFormation은 "전부 성공" 또는 "전부 되돌림"이라는 트랜잭션 비슷한 보장을 준다.

이 "전부 성공 아니면 전부 취소"는 데이터베이스 트랜잭션의 원자성(atomicity) 과 같은 개념이다. CloudFormation을 일종의 "인프라 트랜잭션 매니저"로 보면 이해가 쉽다 — 여러 리소스 생성을 하나의 단위로 묶고, 중간에 실패하면 보상 동작(생성한 것 삭제)으로 롤백한다. 다만 완벽한 트랜잭션은 아니다. 어떤 리소스는 롤백 중 삭제가 안 돼(예: 비어 있지 않은 S3 버킷) 스택이 UPDATE_ROLLBACK_FAILED에 빠지기도 한다. 이때는 문제 리소스를 수동 정리하고 ContinueUpdateRollback으로 롤백을 재개해야 한다. 시험에서 "스택이 ROLLBACK_FAILED에 멈췄다"의 해법으로 이게 나온다.

업데이트 중 새로 만들어진 리소스가 롤백되면 삭제되는데, 만약 그 리소스에 DeletionPolicy: Retain이 걸려 있으면 롤백해도 남는다. 또 EC2 부트스트랩이 끝났는지를 CloudFormation이 알려면 CreationPolicy와 cfn-signal이 필요하다 — 이게 없으면 CloudFormation은 "EC2 API가 성공했다"만 보고 인스턴스 안 애플리케이션이 실제로 떴는지 모른 채 성공 처리한다. UserData 스크립트가 깨져도 스택은 성공으로 끝나는 함정이 여기서 나온다.

교차 스택 참조 대 중첩 스택: 인프라를 어떻게 쪼개나

스택 하나가 너무 커지면 관리가 어렵다. 인프라를 여러 스택으로 쪼개는 두 가지 방식이 있고, 둘은 목적이 다르다.

방식메커니즘결합도적합
교차 스택 참조(Cross-stack)Export + !ImportValue느슨네트워크 스택의 VPC ID를 여러 앱 스택이 공유
중첩 스택(Nested stack)부모가 자식 템플릿을 AWS::CloudFormation::Stack으로 포함강함재사용 컴포넌트(표준 ALB 구성)를 여러 곳에서

교차 스택 참조는 한 스택이 Outputs에서 값을 Export하고, 다른 스택이 !ImportValue로 가져온다. 느슨하게 결합되지만 제약이 있다 — Export된 값을 누가 Import하고 있으면 그 Export를 바꾸거나 스택을 지울 수 없다. 의존이 생겨 단단히 묶인다. 또 !ImportValue는 같은 리전·같은 계정 안에서만 작동한다(cross-region/account 불가).

중첩 스택은 부모 스택이 자식 스택을 리소스처럼 품는다. 표준화된 빌딩 블록을 재사용할 때 좋고, 부모를 지우면 자식도 함께 정리된다.

Export/ImportValue가 만드는 단단한 의존이 운영에서 발목을 잡는다. 네트워크 스택이 VPC ID를 Export하고 앱 스택 다섯 개가 그걸 Import하고 있으면, 네트워크 스택의 그 Export 이름을 바꾸려면 다섯 앱 스택을 먼저 떼어내야 한다. 그래서 큰 조직은 점점 교차 스택 Export 대신 SSM Parameter Store에 값을 넣고 읽는 패턴으로 옮겨간다 — Parameter Store는 이런 강결합을 만들지 않아 스택을 독립적으로 바꿀 수 있다. CDK가 등장한 이유 중 하나도 이런 스택 간 참조를 코드로 더 유연하게 다루기 위해서다.

보호 메커니즘 4종: 무엇으로부터 무엇을 지키는가

CloudFormation에는 비슷해 보이지만 보호 대상이 다른 메커니즘이 여럿 있어 헷갈리기 쉽다. "무엇으로부터 무엇을 지키는가"로 가르면 명확하다.

메커니즘무엇을 막나범위
DeletionPolicy스택/리소스 삭제 시 그 리소스가 사라지는 것 (Retain/Snapshot/Delete)개별 리소스, 삭제 시점
UpdateReplacePolicy업데이트로 리소스가 교체될 때 기존 것이 사라지는 것개별 리소스, 교체 시점
Stack Policy업데이트 중 특정 리소스의 수정/교체 자체스택 업데이트 작업
Termination Protection스택 전체의 삭제 명령스택 단위
IAM Policy누가 스택을 조작할 수 있는지사용자/역할 권한

헷갈리기 쉬운 두 쌍은 다음과 같이 나뉜다. DeletionPolicy vs Termination Protection: 전자는 "스택을 지울 때 이 DB만은 남겨라"(리소스 단위), 후자는 "이 스택 자체를 아예 못 지우게 하라"(스택 단위)다. Stack Policy vs IAM: 전자는 "업데이트 중 ProductionDB를 건드리지 마라"(작업 보호), 후자는 "철수는 스택을 업데이트할 수 없다"(사람 보호)다.

{
  "Statement": [
    { "Effect": "Allow", "Action": "Update:*", "Principal": "*", "Resource": "*" },
    {
      "Effect": "Deny",
      "Action": ["Update:Replace", "Update:Delete"],
      "Principal": "*",
      "Resource": "LogicalResourceId/ProductionDB"
    }
  ]
}

⚠️ 함정: "프로덕션 DB가 실수로 삭제되는 걸 막으려면?"에서 정답은 시나리오에 따라 다르다. "스택 삭제 시 DB 보존" → DeletionPolicy: Retain. "스택 업데이트 중 DB 교체 방지" → Stack Policy의 Deny Update:Replace. "스택 자체 삭제 방지" → Termination Protection. 하나만 외워두면 함정에 빠진다 — 보호 시점(삭제/업데이트)과 범위(리소스/스택)를 함께 봐야 한다.

드리프트: 코드와 현실이 어긋날 때

IaC의 전제는 "템플릿이 곧 인프라의 진실"이다. 그런데 누군가 콘솔에서 보안 그룹을 손으로 열어버리면, 템플릿(코드)과 실제 인프라(현실)가 어긋난다. 이게 드리프트(drift) 다. CloudFormation의 드리프트 감지(Drift Detection) 는 템플릿이 기대하는 상태와 실제 리소스 상태를 비교해 차이를 보여준다.

중요한 점은 드리프트 감지는 자동이 아니다 — 명시적으로 실행해야 한다. CloudFormation은 콘솔 변경을 실시간으로 막지 않는다(그건 IAM·SCP의 일이다). 드리프트 감지는 "이미 벌어진 어긋남을 사후에 발견"하는 도구다. 자동·지속 감지가 필요하면 AWS Config의 규칙과 결합한다.

가상의 사례로, 한 팀이 "긴급하니 일단 콘솔에서 고치고 나중에 코드에 반영한다"는 임시 변경을 반복하다 템플릿과 현실이 크게 벌어졌다. 이 상태에서 다음 스택 업데이트를 돌리면 콘솔 변경이 통째로 덮어써진다. CloudFormation 업데이트는 "템플릿이 진실"이라 보고 동작하므로, 드리프트를 무시하고 업데이트하면 손으로 한 긴급 패치가 사라진다. 그래서 콘솔 직접 변경을 IAM으로 막고(읽기 전용 권한), 모든 변경을 템플릿→파이프라인으로만 흐르게 하는 불변 인프라(immutable infrastructure) 규율을 세운다.

정리

CloudFormation을 관통하는 한 문장은 "인프라의 원하는 상태를 선언하면, 엔진이 의존 그래프로 순서를 풀고, 트랜잭션처럼 전부 만들거나 전부 되돌린다"이다.

  • 선언적 모델은 멱등성과 자동 롤백을 주고, 의존 그래프와 위상 정렬은 생성 순서와 병렬화를 자동으로 결정한다.
  • 업데이트의 위험은 교체(Replacement)에 있고, Change Set이 그걸 미리 보여준다.
  • DeletionPolicy·Stack Policy·Termination Protection은 각기 다른 시점과 범위에서 리소스를 지킨다.
  • 교차 스택 참조의 강결합은 SSM Parameter Store로 완화되고, 드리프트는 "코드가 진실"이라는 전제가 깨졌음을 알린다.
  • 시험 함정은 "삭제냐 교체냐, 리소스냐 스택이냐, 자동이냐 수동이냐"를 가르는 형태가 많다.

다음 글에서는 이 CloudFormation을 서버리스에 맞게 압축한 SAM으로 넘어간다.

📝 연습 문제

선택지를 클릭하면 정답·해설이 펼쳐집니다.

문제 1

프로덕션 스택의 템플릿을 수정해 적용하려 한다. RDS가 의도치 않게 교체되어 데이터가 사라지는 것을 사전에 발견하려면?

문제 2

CloudFormation 스택 생성 시 두 보안 그룹이 서로를 참조해 "circular dependency" 오류가 났다. 올바른 해결은?

문제 3

스택을 삭제하더라도 그 안의 프로덕션 RDS 데이터베이스는 보존하고 싶다. 적절한 설정은?

문제 4

네트워크 스택이 Export한 VPC ID를 애플리케이션 스택에서 참조하려 한다. 올바른 함수와 제약은?

문제 5

CloudFormation으로 EC2를 만들고 UserData로 애플리케이션을 부트스트랩하는데, 스크립트가 실패해도 스택이 "성공"으로 끝난다. 부트스트랩 완료를 CloudFormation이 기다리게 하려면?

문제 6

운영자가 콘솔에서 보안 그룹을 손으로 수정했다. CloudFormation 템플릿과 실제 리소스의 차이를 확인하려면?

문제 7

CloudFormation의 자동 롤백 동작에 대한 설명으로 가장 정확한 것은?

이전ECS와 Fargate: 컨테이너를 "서버 없이" 돌린다는 말의 진짜 의미Week 12 · Day 1다음 SAM: 서버리스를 위해 CloudFormation을 압축하다Week 12 · Day 3

참고 공식 자료

  • DVA-C02 공식 시험 안내(새 탭에서 열림)
  • AWS CloudFormation 공식 문서(새 탭에서 열림)
  • Amazon EC2 공식 문서(새 탭에서 열림)
  • Amazon RDS · Aurora 공식 문서(새 탭에서 열림)
  • Amazon VPC 공식 문서(새 탭에서 열림)
  • AWS IAM 공식 문서(새 탭에서 열림)

이 페이지

  • 선언적 대 명령적: "무엇을"과 "어떻게"의 차이
  • CloudFormation은 생성 순서를 어떻게 정하는가: 의존 그래프
  • 스택 업데이트의 세 가지 운명: 수정, 교체, 중단 없는 변경
  • 자동 롤백: 실패하면 시간을 되돌린다
  • 교차 스택 참조 대 중첩 스택: 인프라를 어떻게 쪼개나
  • 보호 메커니즘 4종: 무엇으로부터 무엇을 지키는가
  • 드리프트: 코드와 현실이 어긋날 때
  • 정리
  • 연습 문제