IAM
분류: Layer 3 - AWS 인프라 & 보안
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”AWS IAM은 “누가(사용자/서비스) AWS의 어떤 리소스에 어떤 작업을 할 수 있는지”를 관리하는 서비스이다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”AWS에서 하는 모든 작업은 IAM 권한을 거친다. EC2를 띄우든, S3에 파일을 올리든, 권한이 없으면 불가능하다. 권한 문제는 가장 흔한 AWS 에러 원인 중 하나이고, 보안 사고의 대부분도 IAM 설정 실수에서 시작한다.
3. 핵심 개념
섹션 제목: “3. 핵심 개념”User (사용자)
AWS에 로그인하는 사람. 각 개발자마다 IAM User가 있다. 콘솔 로그인용 비밀번호 + CLI용 Access Key를 가진다.
⚠️ 2025년 AWS 공식 권고: AWS는 이제 사람(Human User)에 대해서는 IAM User 대신 **IAM Identity Center(SSO)**를 사용하도록 권고한다. IAM Identity Center는 임시 자격증명을 자동 발급하므로 장기 Access Key 노출 위험이 없다. 팀 규모가 커지면 반드시 검토할 것.
Group (그룹)
User를 묶은 단위. “개발팀” 그룹에 권한을 부여하면, 그룹 내 모든 User가 그 권한을 갖는다.
Role (역할)
사람이 아닌 “서비스”에 부여하는 권한. ECS 태스크가 S3에 접근해야 한다면, 그 태스크에 IAM Role을 부여한다.
Policy (정책)
실제 권한 규칙을 정의한 JSON 문서.
{ "Effect": "Allow", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::my-bucket/*"}IAM 정책 JSON 실습 — Resource ARN 패턴과 Condition 키
Resource 필드에는 와일드카드(*)를 활용해 ARN 범위를 정밀하게 지정할 수 있다.
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowSpecificBucketReadWrite", "Effect": "Allow", "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], "Resource": [ "arn:aws:s3:::my-app-uploads/*", "arn:aws:s3:::my-app-uploads-dev/*" ] }, { "Sid": "AllowListBucket", "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::my-app-uploads", "Condition": { "StringLike": { "s3:prefix": ["uploads/*", "temp/*"] } } }, { "Sid": "DenyPublicAccess", "Effect": "Deny", "Action": "s3:PutObjectAcl", "Resource": "arn:aws:s3:::my-app-uploads/*", "Condition": { "StringEquals": { "s3:x-amz-acl": ["public-read", "public-read-write"] } } } ]}ARN 패턴 규칙:
arn:aws:s3:::my-bucket/*— 버킷 내 모든 객체 (버킷 자체 제외)arn:aws:s3:::my-bucket— 버킷 자체만 (ListBucket 등 버킷 레벨 액션에 필요)arn:aws:ecs:ap-northeast-2:123456789:service/my-cluster/*— 특정 클러스터의 모든 서비스"Resource": "*"— 모든 리소스 (서비스에 따라 ARN 미지원 액션에만 사용)
Condition 키를 사용하면 특정 조건을 만족할 때만 권한을 적용할 수 있다. 주요 Condition 연산자와 글로벌 키:
{ "Condition": { "StringEquals": { "aws:RequestedRegion": "ap-northeast-2" }, // 특정 리전만 허용 "Bool": { "aws:MultiFactorAuthPresent": "true" }, // MFA 인증된 경우만 "IpAddress": { "aws:SourceIp": ["203.0.113.0/24"] }, // 특정 IP 대역만 "DateLessThan": { "aws:CurrentTime": "2026-12-31T23:59:59Z" } // 기간 제한 }}IAM 정책 평가 로직 — 왜 이렇게 동작하는가
비유: IAM은 “보안 검문소”이다. 검문소의 기본 규칙은 **모두 통과 금지(Implicit Deny)**이다. 통과하려면 명시적인 허가(Allow)가 필요하다. 단, 누군가 “이 사람은 통과 금지”라고 명시(Explicit Deny)했으면, 아무리 허가증이 있어도 막힌다.
AWS가 요청을 평가하는 순서:
- Explicit Deny 확인: 어느 정책에라도 Deny가 있으면 즉시 거부 (다른 Allow가 있어도 무시)
- Allow 확인: Deny가 없고 Allow가 있으면 허용
- Implicit Deny: Deny도 Allow도 없으면 거부 (기본값)
요청 → [Explicit Deny?] YES → 거부 ↓ NO [Allow 있음?] YES → 허용 ↓ NO Implicit Deny → 거부이 규칙이 중요한 이유: 여러 정책이 동시에 적용될 때(그룹 Policy + 인라인 Policy + SCP 등), 어느 하나에서라도 Deny가 나오면 무조건 거부된다. Allow가 10개 있어도 Deny 1개에 진다.
📖 더 보기: AWS IAM Policy Evaluation Logic 공식 문서 — Explicit Deny, Allow, Implicit Deny의 평가 순서와 교차 계정 시나리오 설명
최소 권한 원칙 (Least Privilege)
필요한 권한만 딱 그만큼만 부여한다. “일단 다 열어놓고 나중에 줄이자”는 보안 사고의 지름길.
실무 적용: AWS 콘솔에서 IAM Access Analyzer를 사용하면, 실제로 사용된 권한만 남기고 불필요한 권한을 자동으로 식별할 수 있다.
경로: IAM → Access Analyzer → Unused access→ 90일간 사용되지 않은 권한 목록을 자동으로 제안Access Key vs Role — 서비스에서는 Role을 써야 한다
EC2, ECS, Lambda 같은 서비스에는 Access Key를 직접 넣지 말고 IAM Role을 부여한다.
Access Key는 코드나 설정 파일에 노출될 위험이 있고, 유출 시 즉시 교체가 어렵다.
Role은 AWS가 임시 자격증명을 자동 발급/갱신하므로 더 안전하다.
❌ 나쁜 예: ECS Task 환경변수에 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 직접 설정✅ 좋은 예: Task Definition에 taskRoleArn 설정 → AWS SDK가 자동으로 임시 자격증명 획득Trust Policy — Role을 누가 assume할 수 있는지 정의한다
Role에는 권한 규칙(Permission Policy)과, 누가 이 Role을 맡아도 되는지(Trust Policy)가 함께 필요하다.
ECS Task에 Role을 부여할 때의 Trust Policy 예시:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "ecs-tasks.amazonaws.com" }, "Action": "sts:AssumeRole" } ]}ECS 태스크에 Role을 달았는데 여전히 Access Denied라면 Trust Policy를 먼저 확인하자.
ECS Task Role vs Execution Role 구분
ECS에는 두 가지 Role이 있어 자주 혼동된다:
| Role | 목적 | 예시 |
|---|---|---|
Task Role (taskRoleArn) | 컨테이너 안의 애플리케이션이 AWS 서비스에 접근할 때 | NestJS 코드에서 S3 파일 업로드, SQS 메시지 전송 |
Execution Role (executionRoleArn) | ECS가 태스크를 시작하기 위한 권한 | ECR에서 이미지 Pull, CloudWatch에 로그 전송 |
📖 더 보기: Amazon ECS Task IAM Role 공식 문서 — Task Role과 Execution Role의 차이 및 설정 방법
IAM Policy Simulator로 권한 테스트
AWS 콘솔에서 “특정 IAM 엔티티가 이 작업을 할 수 있는가”를 실제 요청 없이 시뮬레이션할 수 있다.
경로: IAM → Policy Simulator (https://policysim.aws.amazon.com/)사용법: IAM User/Role 선택 → 서비스 선택 → 작업 선택 → Run SimulationMFA(다중 인증) — 계정 보안의 기본
IAM User는 Password 하나만으로 콘솔에 로그인할 수 있어 보안 취약점이 된다. MFA를 활성화하면 비밀번호 + OTP 앱(Google Authenticator 등)의 2단계 인증이 필요해진다.
설정 경로: IAM → Users → <내 이름> → Security credentials → Assign MFA device권고: Root 계정과 모든 콘솔 접근 IAM User에 MFA 필수 적용IAM 보안 하드닝 — 2025년 주요 권고사항
-
Access Key 주기적 교체 및 미사용 Key 삭제
장기 Access Key는 유출될수록 위험도가 올라간다. 90일 이상 된 Key는 교체하거나 삭제한다.
Terminal window # 현재 모든 Access Key와 마지막 사용일 확인aws iam list-users --query 'Users[].UserName' --output text | \xargs -I{} aws iam list-access-keys --user-name {} \--query 'AccessKeyMetadata[].{User:`{}`,KeyId:AccessKeyId,Status:Status,Created:CreateDate}'# IAM Access Analyzer로 미사용 키 자동 탐지# 경로: IAM → Access Analyzer → Findings → Unused access -
AWS Organizations SCP로 조직 전체 가드레일 설정
비유: SCP(Service Control Policy)는 “건물 전체에 적용되는 마스터 키 제한”이다. 아무리 개별 IAM Policy에서 허용해도, SCP에서 금지된 작업은 불가능하다.
// 예: 특정 리전 외 리소스 생성 금지 SCP{"Effect": "Deny","Action": "*","Resource": "*","Condition": {"StringNotEquals": {"aws:RequestedRegion": ["ap-northeast-2", "us-east-1"]}}} -
IAM Access Analyzer로 외부 공유 리소스 탐지
누군가 실수로 IAM Role을 외부 계정에 공유하거나, S3 버킷을 퍼블릭으로 열었을 때 자동으로 탐지한다.
경로: IAM → Access Analyzer → Findings→ "External access" 타입의 Findings가 있으면 즉시 검토
4. 실무에서 어디에 쓰이나
섹션 제목: “4. 실무에서 어디에 쓰이나”- AWS 콘솔/CLI 접근 권한 관리
- 서비스(ECS, Lambda 등)가 다른 AWS 리소스에 접근할 때
- CI/CD 파이프라인이 AWS에 배포할 때 사용하는 권한
- 팀원 온보딩/오프보딩 시 권한 부여/회수
5. 현재 내 업무와 연결점
섹션 제목: “5. 현재 내 업무와 연결점”- “Access Denied” 에러 대응 시 IAM 정책 확인이 필요
- 새로운 서비스 배포 시 적절한 Role 생성/부여
- 팀원의 AWS 접근 권한 관리
- 보안 감사 시 IAM 설정 점검
6. 자주 헷갈리는 개념 비교
섹션 제목: “6. 자주 헷갈리는 개념 비교”| 개념 A | 개념 B | 차이점 |
|---|---|---|
| User | Role | User는 사람에게 부여, Role은 서비스에 부여(사람도 임시 사용 가능) |
| Policy | Role | Policy는 “권한 규칙”, Role은 “Policy를 가진 역할” |
| 인라인 Policy | 관리형 Policy | 인라인은 하나의 User/Role에 직접 붙임, 관리형은 재사용 가능한 독립 Policy |
| Root Account | IAM User | Root는 모든 권한을 가진 최상위 계정, IAM User는 제한된 권한의 개별 계정 |
| IAM User | IAM Identity Center | User는 장기 자격증명(Access Key), Identity Center는 임시 자격증명(SSO) |
6.5 트러블슈팅
섹션 제목: “6.5 트러블슈팅”🔧 “AccessDeniedException” — ECS/Lambda에서 S3, SQS 등 접근 거부
섹션 제목: “🔧 “AccessDeniedException” — ECS/Lambda에서 S3, SQS 등 접근 거부”증상: 애플리케이션 로그에 AccessDeniedException: User: arn:aws:sts::123456789:assumed-role/... 에러가 찍힘
원인: ECS Task Role에 해당 작업의 Allow 정책이 없거나, Task Role 자체가 설정되지 않음
해결:
- 에러 메시지에서
assumed-role/<Role이름>부분 확인 - IAM → Roles → 해당 Role → Permissions 탭에서 필요한 액션이 Allow되어 있는지 확인
- 없으면 정책 추가 (예:
s3:PutObject가 빠진 경우) - Task Definition에
taskRoleArn이 설정되어 있는지 확인 (미설정 시 애플리케이션에서 AWS SDK가 권한 없음)
🔧 “Role을 달았는데 여전히 Access Denied” — Trust Policy 누락
섹션 제목: “🔧 “Role을 달았는데 여전히 Access Denied” — Trust Policy 누락”증상: Task Role에 모든 Permission Policy를 붙였는데도 ECS Task가 시작 시 또는 실행 중에 AccessDenied 발생
원인: IAM Role의 Trust Policy에 ecs-tasks.amazonaws.com이 Principal로 없어서 ECS가 해당 Role을 assume(맡기) 불가
해결:
- IAM → Roles → 해당 Role → Trust Relationships 탭 클릭
- Principal이
"Service": "ecs-tasks.amazonaws.com"인지 확인 - 없으면 Edit trust policy에서 아래 내용 추가:
{"Effect": "Allow","Principal": { "Service": "ecs-tasks.amazonaws.com" },"Action": "sts:AssumeRole"}
🔧 CLI에서 “Unable to locate credentials” 또는 만료된 임시 자격증명
섹션 제목: “🔧 CLI에서 “Unable to locate credentials” 또는 만료된 임시 자격증명”증상: aws s3 ls 등 CLI 명령 실행 시 Unable to locate credentials 또는 ExpiredTokenException 에러
원인 1: ~/.aws/credentials 또는 환경변수에 Access Key가 설정되지 않음
원인 2: STS AssumeRole로 발급한 임시 자격증명이 만료됨 (기본 1시간)
해결:
# 현재 자격증명 확인aws sts get-caller-identity
# 출력 예시 (정상):# {# "UserId": "AIDAXXXXXXXXXXXXXXXXX",# "Account": "123456789012",# "Arn": "arn:aws:iam::123456789012:user/my-user"# }
# 에러 시: 프로필 재설정aws configure --profile my-profile🔧 CI/CD 파이프라인에서 AWS 권한 에러
섹션 제목: “🔧 CI/CD 파이프라인에서 AWS 권한 에러”증상: GitHub Actions 또는 Jenkins에서 aws 명령어 실행 시 Unable to locate credentials 또는 권한 에러 발생
원인: CI/CD 파이프라인에 AWS 자격증명이 설정되지 않았거나, IAM 권한이 부족함
해결: Access Key를 GitHub Secrets에 저장하는 방식보다 OIDC(OpenID Connect)를 통한 Role Assume이 보안상 더 좋다.
# GitHub Actions에서 OIDC로 AWS Role Assume (Access Key 없이)- name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456789012:role/github-actions-role aws-region: ap-northeast-2# → 임시 자격증명을 자동으로 발급받아 후속 aws 명령어에 사용🔧 “This policy would have no effect” — 의도한 대로 권한이 안 먹히는 경우
섹션 제목: “🔧 “This policy would have no effect” — 의도한 대로 권한이 안 먹히는 경우”증상: IAM Policy를 붙였는데 실제로 작동하지 않음. Policy Simulator에서는 Allow인데 콘솔/API에서는 Denied
원인 1: SCP(Service Control Policy)가 조직 레벨에서 해당 작업을 Deny하고 있음
원인 2: 권한 경계(Permissions Boundary)가 Policy의 범위를 제한하고 있음
원인 3: 리소스 기반 정책(Bucket Policy, SQS Policy 등)에서 해당 Role을 Deny하고 있음
해결:
# 1. IAM Policy Simulator에서 SCP 포함 시뮬레이션# 경로: https://policysim.aws.amazon.com/# → "Simulation Settings"에서 "Simulate Organizations SCP" 체크
# 2. AWS CloudTrail에서 실제 거부된 이벤트 확인aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole \ --start-time "2024-01-15T09:00:00Z" \ --query 'Events[?contains(CloudTrailEvent, `AccessDenied`)].{Time:EventTime,Event:CloudTrailEvent}'
# 3. IAM Access Analyzer로 정책 검증aws accessanalyzer validate-policy \ --policy-document file://my-policy.json \ --policy-type IDENTITY_POLICY# → 정책 문법 오류나 잠재적 문제를 자동으로 탐지7. 체크리스트
섹션 제목: “7. 체크리스트”- User, Group, Role, Policy의 차이를 설명할 수 있다
- 최소 권한 원칙이 뭔지 설명할 수 있다
- “Access Denied” 에러가 나면 어디를 확인해야 하는지 안다
- 서비스에 Role을 부여하는 이유를 설명할 수 있다
- ECS/EC2/Lambda에서 Access Key 대신 Role을 써야 하는 이유를 설명할 수 있다
- Explicit Deny가 Allow보다 우선한다는 것을 설명할 수 있다
8. 추가 학습 키워드
섹션 제목: “8. 추가 학습 키워드”AWS STS, AssumeRole, MFA 적용, IAM Policy Simulator, Service Control Policy(SCP), Cross-Account Access, IAM Identity Center, OIDC
📚 추천 리소스
섹션 제목: “📚 추천 리소스”- 📖 AWS IAM Policy Evaluation Logic — Explicit Deny가 Always Win인 이유, 정책 평가 순서 공식 문서 (중급)
- 📖 IAM Troubleshoot Access Denied — AccessDenied 에러 원인 유형별 진단 방법 공식 가이드 (입문)
- 📖 AWS IAM Roles Deep Dive — Role, Trust Policy, Assume Role 개념을 예시와 함께 설명 (입문)
- 🎬 IAM Policy Evaluation Chains Explained — AWS 공식 영상으로 정책 평가 흐름 시각적 설명 (입문)
- 📖 AWS IAM Best Practices 2025 — Access Analyzer, SCP, OIDC 등 2025년 기준 IAM 보안 강화 실전 가이드 (중급)
9. 내가 직접 확인해볼 것
섹션 제목: “9. 내가 직접 확인해볼 것”- AWS 콘솔에서 내 IAM User의 권한 확인
경로: IAM → Users → <내 이름> → Permissions 탭확인: 어떤 그룹에 속해있고 어떤 정책이 붙어있는지
- 팀에서 사용 중인 IAM Role 목록 훑어보기
경로: IAM → Roles → 검색창에 서비스명 입력 (예: "ecs", "lambda")
- IAM Policy Simulator로 특정 작업의 허용/거부 테스트
-
aws sts get-caller-identity로 현재 내 자격증명 확인Terminal window aws sts get-caller-identity# 예상 출력:# {# "UserId": "AIDAXXXXXXXXXXXXXXXXX",# "Account": "123456789012",# "Arn": "arn:aws:iam::123456789012:user/my-user"# } - IAM Access Analyzer에서 Unused access Findings 확인
경로: IAM → Access Analyzer → Findings → Unused access 탭확인: 90일 이상 사용하지 않은 권한/Access Key 목록
10. 5줄 요약
섹션 제목: “10. 5줄 요약”- IAM은 AWS의 모든 접근을 통제하는 핵심이며, 보안 사고의 대부분은 IAM 설정 실수에서 시작된다
- User(사람) → Role(서비스) → Policy(규칙) 조합으로 권한을 관리하되, 사람은 IAM Identity Center(SSO)로 관리하는 것이 2025년 AWS 공식 권고이다
- 최소 권한 원칙 — Access Analyzer의 Unused Access 기능으로 90일 미사용 권한을 자동 탐지해 정기 정리한다
- “Access Denied”가 나면 정책 평가 순서(Explicit Deny → Allow → Implicit Deny)를 따라 CloudTrail + Policy Simulator로 추적한다
- CI/CD에서 AWS 접근은 Access Key 대신 OIDC(GitHub Actions) 또는 Instance Profile(EC2/ECS)을 통한 임시 자격증명을 사용한다
프론트엔드 → 플랫폼 브릿지
섹션 제목: “프론트엔드 → 플랫폼 브릿지”localStorage 권한 vs IAM Role — 왜 비슷한가
프론트엔드 개발 시 사용자 권한을 관리하는 방식을 생각해보자. 예를 들어 localStorage에 role: "admin"을 저장해서 UI 요소를 보여주고 숨기는 방식이 있다. 하지만 이건 클라이언트에서만 동작하는 “UI 권한”이고, 서버는 API 요청이 올 때마다 실제로 사용자 권한을 다시 확인한다.
IAM은 바로 이 “서버가 권한을 확인하는 시스템”을 AWS 인프라 전체에 적용한 것이다:
[프론트엔드 권한 흐름]사용자 로그인 → JWT 토큰 발급 → API 요청마다 토큰 검증 서버: "이 토큰의 역할이 admin인가?"
[AWS IAM 권한 흐름]ECS Task 시작 → IAM Role 부여 → AWS API 요청마다 자격증명 검증 AWS: "이 Role이 s3:GetObject를 허용받았는가?"핵심 차이: localStorage는 클라이언트가 조작할 수 있지만, IAM Role은 AWS가 발급한 임시 자격증명이라 외부에서 위조할 수 없다.
“이 API Key를 React 코드에 넣으면 안 된다”의 이유
React 빌드 결과물(bundle.js)에 포함된 값은 누구나 볼 수 있다. 이것이 IAM Access Key를 서버사이드에만 두고, 프론트에는 절대 내려주면 안 되는 이유다:
❌ 잘못된 패턴:.env → REACT_APP_AWS_ACCESS_KEY=AKIA... → bundle.js에 포함브라우저 개발자 도구 → Sources → bundle.js → Access Key 노출!
✅ 올바른 패턴:NestJS 서버 → IAM Role (ECS Task Role)NestJS 코드 → AWS SDK → Role 기반 임시 자격증명 자동 사용프론트 → NestJS API (인증 토큰만) → NestJS가 AWS 서비스 대신 호출실무 아키텍처 패턴 — IAM 거버넌스 계층
섹션 제목: “실무 아키텍처 패턴 — IAM 거버넌스 계층”조직 전체 가드레일 └─ SCP (Service Control Policy) — 금지 리전, 금지 서비스 등 조직 전체 상한선 └─ 계정 레벨 └─ IAM Permission Boundary — 개발자가 부여할 수 있는 권한 상한선 └─ IAM Role (Task/EC2/Lambda별) └─ IAM Policy — 실제 허용/거부 규칙어느 레이어에서든 Deny가 나오면 무조건 거부다. “IAM Policy는 있는데 왜 안 되지?”라는 상황은 위 계층에서 막히고 있는 것이다.
2025년 변경사항: 2025년 7월부터 IAM Identity Center의 CloudTrail 이벤트 구조가 변경됐다.
userName/principalId필드 대신userId와 Identity Store ARN이 기록된다. CloudTrail 기반 알림이나 SIEM 연동이 있다면 이 변경에 맞게 쿼리를 업데이트해야 한다.