브라우저에서 12개의 정책 퍼즐로 AWS IAM 배우기
출처: Dev.to
AWS IAM은 어렵다 – 실습형 학습 도구
Learn AWS IAM – 무료이며 오픈‑소스, 브라우저 전용 놀이터( AWS 계정 필요 없음, 회원가입도 안 함).
Learn Git Branching에 영감을 받음.
12개의 인터랙티브 레벨 각각은 현실적인 시나리오를 제시합니다(예: “사용자는 버킷 A는 읽을 수 있지만 버킷 B는 읽을 수 없음”, “EC2 역할이 다른 계정의 역할을 가정해야 함”, “SCP가 원하지 않는 것을 차단하고 있음”).
기존 정책을 읽고 문제점을 찾아낸 뒤, JSON을 편집해 요청이 올바르게 평가될 때까지 수정합니다.
다루는 주제
- 아이덴티티‑기반 및 리소스‑기반 정책
- 교차 계정 접근
- 태그를 활용한 ABAC
- 서비스 제어 정책(SCP)
- 권한 경계
이 글의 나머지 부분에서는 구현 방식을 설명합니다.
레벨당 하나의 상태 머신
각 레벨은 자체 XState 머신을 가집니다. 머신은 다음에 대한 단일 진실 원천입니다.
- 캔버스상의 노드와 엣지
- 현재 목표
- UI 제한(팝업, 비활성화된 컨트롤 등)
- 현재 튜토리얼 단계
사용자와의 모든 상호작용은 현재 레벨 머신에 전달되는 이벤트입니다(정책 제출, 노드 연결, “다음” 클릭 등).
왜 상태 머신인가?
- 선형 흐름에 가끔씩 분기가 존재 → 각 튜토리얼 단계가 하나의 상태가 됨.
- 전이는 사용자 행동에 의해 구동되고, 가드가 건너뛰기나 잘못된 단계를 방지함.
대안인 useEffect들의 얽힘은 순서를 암묵적으로 만들고 이해하기 어렵게 합니다. 머신을 사용하면 전이 테이블이 명시적으로 드러납니다.
직렬화
진행 상황은 체크포인트로 저장되므로 머신은 직렬화 가능해야 합니다. 런타임에 의존하는 로직(검증기, 가드 조건)은 머신 컨텍스트에 직접 들어갈 수 없습니다. 대신:
- 레지스트리(레벨 번호 + 문자열 이름을 키로 함)에 실제 함수를 보관합니다.
- 머신은 함수 이름만 저장합니다.
- 액션이 실행될 때 레지스트리에서 구현을 찾아 실행합니다.
스냅샷에 이름만 들어 있기 때문에 체크포인트 복원은 투명하게 이루어집니다.
캔버스는 별도 레이어
캔버스는 IAM 엔티티를 드래그 가능한 노드와 엣지(관계)로 시각화합니다. ReactFlow 위에 구현되었습니다.
- XState 머신은 무엇이 존재하는가에 대한 진실 원천입니다.
- 가벼운
@xstate/store인스턴스가 UI‑레벨 상태(위치, 호버, 선택)를 보관합니다.
이벤트 흐름
| 머신 이벤트 | 캔버스 반응 |
|---|---|
NODES_ADDED | 스토어에 노드 추가 |
NODES_DELETED | 노드를 “삭제 중”으로 표시 → 종료 애니메이션 트리거 |
EDGES_ADDED | 엣지 추가 |
NODE_UPDATED | 노드 데이터(예: 라벨) 업데이트 |
이러한 간접 단계는 애니메이션을 위해 필요합니다. 머신에서 바로 노드를 제거하면 DOM에서 즉시 사라져 Framer Motion이 종료 애니메이션을 실행할 기회를 잃게 됩니다. 먼저 이벤트를 발생시켜 캔버스가 애니메이션을 수행하고, 애니메이션이 끝난 뒤에 스토어에서 노드를 최종 삭제합니다.
정책 편집 – CodeMirror + AJV
대부분의 목표는 JSON 형태의 IAM 정책을 작성하는 것입니다. 편집기는 CodeMirror 6으로 구현됐으며, AJV를 이용해 매 키 입력마다 검증합니다.
검증 레이어
- AWS IAM 기본 스키마 – 구문 구조,
Action,Principal,Resource, 조건 연산자 등을 검증합니다. - 목표‑특화 규칙 – 예를 들어 레벨 5의 EC2 역할 목표는 신뢰 정책에
ec2.amazonaws.com서비스 프린시플이 포함돼야 합니다.
모든 검증기는 레벨이 로드될 때 한 번 컴파일되고, 해당 레벨이 살아있는 동안 재사용됩니다.
UI 개선
맞춤형 CodeMirror 확장은 헬프 배지를 인라인으로 렌더링해, 관련 라인 옆에 상황에 맞는 힌트를 제공합니다.
프로젝트 구조
코드베이스는 여러 레이어로 구성되며, 의존성은 아래 방향으로만 흐릅니다:
lib / types / hooks / config / stores ← 기반
domain ← IAM 엔티티, ARN, 기본 스키마
levels ← 레벨별 머신, 목표, 튜토리얼 텍스트
runtime ← 레벨 로더, 영속성, 프로바이더
features ← 캔버스, 편집기, 다이얼로그(렌더링 전용)
app_shell / app ← 최상위
상위 레이어는 하위 레이어를 import하고, 하위 레이어는 위쪽을 import하지 않습니다.
예외는 타입드 pub/sub 버스로, levels/가 발생시킨 부수 효과를 runtime/이 처리하도록(예: 체크포인트 저장) 하면서 import 순환을 방지합니다.
features/와 levels/는 동등한 위치에 있으며 서로를 import할 수 없습니다. 레벨 로직과 UI 렌더링은 완전히 격리돼 runtime/을 통해서만 통신합니다. 캔버스 컴포넌트는 어떤 레벨을 렌더링하고 있는지 알지 못하고, 단지 runtime/이 제공하는 머신 액터에 구독할 뿐입니다.
기술 스택
- React와 TypeScript, 번들링은 Vite
- 레벨 오케스트레이션은 XState, UI 상태는
@xstate/store - 인터랙티브 캔버스는 ReactFlow
- 정책 편집기는 CodeMirror 6 + AJV
- 전체 UI는 Chakra UI
소스 코드를 살펴보거나, 기여하거나, 직접 레벨을 만들어 보세요!
컴포넌트
- Framer Motion – 애니메이션
- Vitest – 단위·통합 테스트
- Playwright – 12개 레벨 전체에 대한 E2E 테스트
각 레벨의 상태 머신은 동적 import로 로드되므로 사용자가 해당 레벨로 이동할 때만 현재 레벨 코드를 다운로드합니다. 코드 편집기도 지연 로드됩니다.
링크
- 사이트:
- 코드: (MIT