AWS CDK 100 Drill Exercises #002: IAM 기본 — 사용자, 역할 및 보안 비밀번호 관리
Source: Dev.to
소개
이 글은 AWS CDK 100 Drill Exercises 시리즈의 두 번째 연습문제입니다.
시리즈에 대한 자세한 내용은 이 소개 글을 참고하세요.
첫 번째 연습문제에서 S3 기본 개념을 배운 뒤(첫 번째 연습문제), 이제 AWS Identity and Access Management (IAM) 로 들어갑니다. IAM은 AWS 보안의 기반으로, 누가 리소스에 접근할 수 있는지와 어떤 작업을 할 수 있는지를 제어합니다.
왜 S3 다음에 IAM인가?
- 보안 기반 – IAM은 모든 AWS 리소스를 보호하는 데 필수적입니다.
- 실제 필요성 – 모든 AWS 배포에서는 적절한 접근 관리가 필요합니다.
- CDK 통합 – CDK가 IAM 정책과 역할을 어떻게 생성하는지 이해합니다.
- 모범 사례 – 초기부터 보안 패턴을 배우면 향후 취약점을 예방할 수 있습니다.
배울 내용
- CDK가 IAM 사용자, 그룹, 역할을 생성하는 방법.
- AWS Secrets Manager 로 안전한 비밀번호 관리.
- 관리형 정책과 인라인 정책의 차이점.
- MFA 요구 조건이 포함된 스위치‑롤 구현.
- CloudFormation의 동적 비밀 해석.
- IAM 보안 모범 사례.
📁 코드 저장소: 모든 예제는 GitHub 에서 확인할 수 있습니다.
아키텍처 개요
네 개의 construct에 걸쳐 여섯 가지 패턴을 구현합니다.
Construct 1: 기본 사용자 (CDKDefaultUser)
- 패턴 1 – 최소 IAM 사용자 설정.
Construct 2: 비밀번호 관리 사용자 (IAMUserWithPassword)
- 패턴 2A – 하드코딩된 비밀번호 (⚠️ 권장되지 않음).
- 패턴 2B – Secrets Manager 로 안전하게 비밀번호 관리 (✅ 권장).
- 패턴 3A – AWS 관리형 정책 연결.
- 패턴 3B – 인라인 정책 연결.
Construct 3: 그룹 관리 사용자 (IamUserGroup)
- 패턴 4 – 그룹 기반 권한 관리.
Construct 4: 스위치 역할 사용자 (SwitchRoleUser)
- 패턴 5 – MFA가 요구되는 역할 가정.
사전 요구 사항
- AWS CLI v2 설치 및 구성.
- Node.js 20+.
- AWS CDK CLI (
npm install -g aws-cdk). - 기본 TypeScript 지식.
- AWS 계정 (Free Tier 로도 가능).
- IAM 개념에 대한 이해 (사용자, 역할, 정책).
프로젝트 디렉터리 구조
iam-basics/
├── bin/
│ └── iam-basics.ts # 애플리케이션 진입점
├── lib/
│ ├── stacks/
│ │ └── iam-basics-stack.ts # 메인 스택 정의
│ └── constructs/
│ ├── iam-user-with-password.ts # 패턴 2‑3
│ ├── iam-user-with-group.ts # 패턴 4
│ └── iam-user-with-switch-role.ts # 패턴 5
├── test/
│ ├── compliance/
│ │ └── cdk-nag.test.ts # 테스트 (아래 설명)
│ ├── snapshot/
│ │ └── snapshot.test.ts # 테스트 (아래 설명)
│ └── unit/
│ └── iam-basics.test.ts # 테스트 (아래 설명)
├── cdk.json
├── package.json
└── tsconfig.json
패턴 1: CDK 기본 사용자 이해
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
export class IamBasicsStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 최소 IAM 사용자 설정
const cdkDefaultUser = new iam.User(this, 'CDKDefaultUser', {});
}
}
생성된 CloudFormation
{
"Resources": {
"CDKDefaultUserF7AAA71A": {
"Type": "AWS::IAM::User",
"Metadata": {
"aws:cdk:path": "Dev/DrillexercisesIamBasics/CDKDefaultUser/Resource"
}
}
}
}
기본 구성 세부 정보
- 사용자 이름 – AWS에서 자동 생성.
- 비밀번호 – 없음; 콘솔 접근이 기본적으로 비활성화됨.
- 정책 – 권한 없음 (최소 권한 원칙).
- 액세스 키 – 없음; 프로그래밍 접근이 비활성화됨.
명시적으로 권한을 부여하기 전까지 이 사용자는 어떤 리소스에도 접근할 수 없습니다.
패턴 2A: 하드코딩된 비밀번호를 가진 사용자 (⚠️ 권장되지 않음)
⚠️ 이 패턴은 프로덕션에서 비밀번호를 하드코딩하는 것이 얼마나 위험한지 보여주기 위한 예시입니다.
const userWithPassword = new iam.User(this, 'PasswordUser', {
password: cdk.SecretValue.unsafePlainText('InitialPassword123!'),
passwordResetRequired: true,
});
생성된 CloudFormation
{
"UserWithPasswordPasswordUserA5E8EDB8": {
"Type": "AWS::IAM::User",
"Properties": {
"LoginProfile": {
"Password": "InitialPassword123!",
"PasswordResetRequired": true
}
}
}
}
왜 위험한가
- 소스 코드에 비밀번호 – 버전 관리 시스템에 그대로 노출됩니다.
- CloudFormation 템플릿 – 콘솔 및 로그에 비밀번호가 드러납니다.
- 암호화 없음 – 평문으로 저장됩니다.
- 감사 추적 어려움 – 비밀번호 변경 이력을 파악하기 힘듭니다.
프로덕션에서는 절대 이 패턴을 사용하지 마세요.
패턴 2B: Secrets Manager 를 이용한 사용자 (✅ 권장)
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as cdk from 'aws-cdk-lib';
const userName = 'SecretsPasswordUser';
// 자동 생성된 비밀번호로 비밀을 생성
const userSecret = new secretsmanager.Secret(this, 'UserSecret', {
generateSecretString: {
secretStringTemplate: JSON.stringify({ username: userName }),
generateStringKey: 'password',
excludePunctuation: true,
passwordLength: 16,
requireEachIncludedType: true,
},
});
// Secrets Manager 에서 비밀번호를 가져와 IAM 사용자 생성
const user = new iam.User(this, 'SecretsPasswordUser', {
userName: userName,
password: userSecret.secretValueFromJson('password'),
passwordResetRequired: true,
});
// 사용자가 자신의 비밀번호를 변경할 수 있도록 AWS 관리형 정책 연결
user.addManagedPolicy(
iam.ManagedPolicy.fromAwsManagedPolicyName('IAMUserChangePassword')
);
이 방법은 비밀번호를 Secrets Manager에 안전하게 저장하고, 비밀을 하드코딩하지 않으며, 필요 시 비밀번호 회전도 가능하게 합니다.