AWS 자격증명 완전 가이드
TL;DR
- AWS 자격증명은 장기 키에서 임시 토큰과 역할 기반으로 진화했다.
- Credential Chain과 AssumeRole이 표준 운영 방식이 되었다.
- IRSA, IMDSv2, Permission Boundary 등으로 최소 권한을 강화한다.
1. 개념
AWS 자격증명은 IAM, STS, 역할을 통해 리소스 접근을 제어하는 체계다.
2. 배경
장기 키 유출 위험과 멀티 계정 확대로 임시 자격증명이 필요해졌다.
3. 이유
최소 권한과 자동화를 확보하고 운영 리스크를 줄이기 위함이다.
4. 특징
AssumeRole, IRSA/EKS Pod Identity, IMDSv2, SCP/Permission Boundary를 포함한다.
5. 상세 내용
AWS 자격증명 완전 가이드
작성일: 2026-03-05 카테고리: Cloud / AWS / Authentication & Authorization 포함 내용: IAM, STS, IRSA, EKS Pod Identity, Instance Profile, IMDS, DefaultCredentialsProvider, Credential Chain, AssumeRole, OIDC, SAML, Cognito, Cross-Account Access, Permission Boundary, SCP, MFA, External ID
1. 용어 사전 — 약자와 명명 유래
모든 약어를 풀어쓰고, 왜 그렇게 이름 붙었는지 설명한다.
| 약어 | 풀어쓰기 (Full Name) | 한국어 의미 | 명명 유래 |
|---|---|---|---|
| IAM | Identity and Access Management | 신원 확인 및 접근 관리 | “누구인가(Identity)”와 “무엇을 할 수 있는가(Access)”를 관리(Management)하는 서비스. 2012년 AWS가 사용자/권한 관리 전용 서비스로 출시 |
| STS | Security Token Service | 보안 토큰 서비스 | 보안(Security) 목적의 임시 토큰(Token)을 발급하는 서비스(Service). 장기 자격증명 없이 임시 권한을 부여하기 위해 설계 |
| IRSA | IAM Roles for Service Accounts | 서비스 어카운트용 IAM 역할 | Kubernetes의 ServiceAccount에 IAM Role을 연결하는 메커니즘. 2019년 EKS에서 Pod 단위 권한 부여를 위해 도입 |
| IMDS | Instance Metadata Service | 인스턴스 메타데이터 서비스 | EC2 인스턴스가 자기 자신의 메타데이터(IP, Role, 보안그룹 등)를 조회하는 내부 HTTP 서비스. 169.254.169.254 링크로컬 주소 사용 |
| OIDC | OpenID Connect | 오픈아이디 커넥트 | OpenID 재단이 만든 인증 프로토콜. OAuth 2.0 위에 신원 확인(Identity) 레이어를 추가. “Connect”는 기존 OpenID와 OAuth를 연결한다는 의미 |
| SAML | Security Assertion Markup Language | 보안 어설션 마크업 언어 | 보안(Security) 주장(Assertion)을 XML 마크업(Markup Language)으로 표현하는 OASIS 표준. 2002년 등장하여 기업 SSO의 사실상 표준 |
| SCP | Service Control Policy | 서비스 제어 정책 | AWS Organizations에서 멤버 계정의 서비스(Service) 접근을 제어(Control)하는 정책(Policy). 가드레일 역할 |
| RCP | Resource Control Policy | 리소스 제어 정책 | AWS Organizations에서 리소스(Resource) 수준의 접근을 제어(Control)하는 정책(Policy). 2024년 도입 |
| MFA | Multi-Factor Authentication | 다중 인증 | 비밀번호 외에 추가(Multi) 요소(Factor)를 통한 인증(Authentication). OTP, 하드웨어 키 등 |
| ARN | Amazon Resource Name | 아마존 리소스 이름 | AWS 내 모든 리소스(Resource)의 고유 식별자(Name). 형식: arn:aws:service:region:account:resource |
| ABAC | Attribute-Based Access Control | 속성 기반 접근 제어 | 리소스나 사용자의 속성(Attribute, 예: 태그)을 기반(Based)으로 접근(Access)을 제어(Control)하는 모델 |
| RBAC | Role-Based Access Control | 역할 기반 접근 제어 | 역할(Role)을 기반(Based)으로 접근(Access)을 제어(Control)하는 전통적 모델 |
| SSO | Single Sign-On | 단일 로그인 | 한 번(Single) 로그인(Sign-On)으로 여러 서비스에 접근. AWS IAM Identity Center의 핵심 기능 |
| EKS | Elastic Kubernetes Service | 탄력적 쿠버네티스 서비스 | 자동 확장(Elastic) 가능한 관리형 Kubernetes 서비스. 2018년 정식 출시 |
| ECS | Elastic Container Service | 탄력적 컨테이너 서비스 | AWS 자체 컨테이너 오케스트레이션 서비스. EKS보다 먼저 출시(2015년) |
| EC2 | Elastic Compute Cloud | 탄력적 컴퓨팅 클라우드 | AWS의 가상 서버 서비스. “Elastic”은 수요에 따라 탄력적으로 확장/축소, “Compute Cloud”는 클라우드 컴퓨팅 |
| ACL | Access Control List | 접근 제어 목록 | 리소스에 대한 접근(Access) 권한을 목록(List)으로 제어(Control). S3 버킷 등에서 사용 |
| JWT | JSON Web Token | JSON 웹 토큰 | JSON 형식의 웹(Web) 토큰(Token). 헤더.페이로드.서명 3부분으로 구성. OIDC ID Token에 사용 |
| IdP | Identity Provider | 신원 제공자 | 사용자의 신원(Identity)을 확인하고 제공(Provider)하는 시스템. Cognito, Okta, Active Directory 등 |
| ECR | Elastic Container Registry | 탄력적 컨테이너 레지스트리 | Docker 이미지를 저장하는 AWS 관리형 컨테이너(Container) 레지스트리(Registry) |
2. AWS 자격증명의 역사와 진화
┌─────────────────────────────────────────────────────────────────────────┐
│ AWS 자격증명 진화 타임라인 │
├──────┬──────────────────────────────────────────────────────────────────┤
│ 2006 │ AWS 출시. IAM User + 영구 Access Key만 존재 │
│ │ └── 모든 인증이 장기 자격증명 기반 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2011 │ IAM Role 도입 │
│ │ └── "누가 이 역할을 맡을 수 있는가"라는 신뢰 관계 개념 등장 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2012 │ STS (Security Token Service) AssumeRole 출시 │
│ │ └── 임시 자격증명 시대 개막. Role Chaining 가능 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2012 │ EC2 Instance Profile 도입 │
│ │ └── EC2에서 Access Key 없이 IAM Role 사용 가능 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2014 │ SAML 2.0 Federation 지원 │
│ │ └── 기업 Active Directory와 AWS 계정 연동 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2015 │ OIDC (OpenID Connect) Federation 지원 │
│ │ └── Google, Facebook 등 소셜 로그인으로 AWS 접근 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2017 │ ECS Task Role 도입 │
│ │ └── 컨테이너 단위 권한 부여. EC2 Instance Profile의 컨테이너판 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2017 │ AWS Organizations + SCP (Service Control Policy) 출시 │
│ │ └── 멀티 계정 환경의 권한 가드레일 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2019 │ IRSA (IAM Roles for Service Accounts) 출시 │
│ │ └── EKS에서 Pod 단위 세밀한 권한 부여. OIDC 기반 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2019 │ IMDSv2 (Instance Metadata Service v2) 출시 │
│ │ └── SSRF 공격 방어. 토큰 기반 메타데이터 접근 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2020 │ AWS SSO (현 IAM Identity Center) 출시 │
│ │ └── 중앙 집중식 멀티 계정 접근 관리 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2022 │ IAM Roles Anywhere 출시 │
│ │ └── 온프레미스에서도 IAM Role 사용 가능. X.509 인증서 기반 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2022 │ Permission Boundary 강화 │
│ │ └── 위임된 관리자가 부여할 수 있는 최대 권한을 제한 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2023 │ EKS Pod Identity 출시 │
│ │ └── IRSA의 복잡한 OIDC 설정 없이 Pod에 Role 연결 │
├──────┼──────────────────────────────────────────────────────────────────┤
│ 2024 │ IAM Identity Center 확장 + RCP (Resource Control Policy) 도입 │
│ │ └── 리소스 수준 가드레일 추가. Organizations 기능 강화 │
└──────┴──────────────────────────────────────────────────────────────────┘
핵심 흐름: 장기 자격증명(Access Key) → 임시 자격증명(STS) → 역할 기반(IAM Role) → 자동화(SDK 체인) → 세분화(Pod 단위)
3. 자격증명 유형 총정리
3.1 장기 자격증명 (Long-term Credentials)
┌─────────────────────────────────────────────────────────────┐
│ 장기 자격증명 (Long-term Credentials) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 구성 요소: │
│ ├── Access Key ID (예: AKIAIOSFODNN7EXAMPLE) │
│ │ └── "AKIA" 접두어 = 영구(permanent) IAM User Key │
│ └── Secret Access Key (예: wJalrXUtnFEMI/K7MDENG/bPx...) │
│ └── 절대 노출되면 안 되는 비밀 키 │
│ │
│ 특징: │
│ ├── 만료 없음 (삭제하거나 비활성화할 때까지 유효) │
│ ├── IAM User 1명당 최대 2개까지 발급 가능 │
│ ├── 프로그래밍 방식 접근에 사용 │
│ └── Root 계정 Access Key는 절대 사용 금지 │
│ │
│ 위험성: │
│ ├── 유출 시 즉시 악용 가능 (만료가 없으므로) │
│ ├── Git에 커밋되면 봇이 수 분 내에 탐지하여 악용 │
│ └── AWS는 GitHub Secret Scanning으로 자동 탐지 후 알림 │
│ │
│ 필요한 경우: │
│ ├── CI/CD 파이프라인 (IAM Role 사용 불가 시) │
│ ├── 온프레미스 서버 (IAM Roles Anywhere 전에) │
│ └── 서드파티 서비스 연동 (제한적 경우) │
│ │
└─────────────────────────────────────────────────────────────┘
3.2 임시 자격증명 (Temporary Credentials)
┌─────────────────────────────────────────────────────────────┐
│ 임시 자격증명 (Temporary Credentials) │
├─────────────────────────────────────────────────────────────┤
│ │
│ STS (Security Token Service)가 발급 │
│ │
│ 구성 요소 (4가지): │
│ ├── Access Key ID (예: ASIAIXNL7EXAMPLE) │
│ │ └── "ASIA" 접두어 = 임시(temporary) STS 자격증명 │
│ ├── Secret Access Key │
│ ├── Session Token (임시 자격증명의 핵심 구분자) │
│ └── Expiration (만료 시간 — UTC 타임스탬프) │
│ │
│ 수명: │
│ ├── 기본: 1시간 (3,600초) │
│ ├── 최소: 15분 (900초) │
│ ├── 최대: 12시간 (43,200초) │
│ │ └── IAM Role의 MaxSessionDuration 설정에 따름 │
│ └── Role Chaining 시: 최대 1시간으로 제한 │
│ │
│ 장점: │
│ ├── 자동 만료 → 유출되어도 피해 범위 제한 │
│ ├── CloudTrail에 세션 정보 기록 │
│ └── 조건부 권한 부여 가능 (Session Policy) │
│ │
└─────────────────────────────────────────────────────────────┘
3.3 Access Key ID 접두어 식별표
| 접두어 | 의미 | 설명 |
|---|---|---|
AKIA |
IAM User 영구 키 | 장기 자격증명. 만료 없음 |
ASIA |
STS 임시 키 | 임시 자격증명. Session Token 필수 동반 |
AROA |
IAM Role ID | Role의 고유 식별자 (자격증명 아님) |
AIDA |
IAM User ID | User의 고유 식별자 (자격증명 아님) |
ANPA |
Managed Policy | 관리형 정책의 고유 식별자 |
AGPA |
IAM Group | 그룹의 고유 식별자 |
3.4 자격증명 방식 비교표
| 항목 | IAM User Key | STS 임시 | Instance Profile | IRSA | EKS Pod Identity |
|---|---|---|---|---|---|
| 수명 | 영구 | 15분~12시간 | 자동 갱신 (6시간) | 자동 갱신 | 자동 갱신 |
| 구성 요소 | AK + SK | AK + SK + ST | AK + SK + ST | AK + SK + ST | AK + SK + ST |
| 갱신 | 수동 교체 | AssumeRole 재호출 | SDK 자동 | SDK 자동 | SDK 자동 |
| 보안 수준 | 낮음 | 높음 | 높음 | 매우 높음 | 매우 높음 |
| 권한 범위 | User 단위 | Session 단위 | EC2 인스턴스 단위 | Pod 단위 | Pod 단위 |
| 설정 복잡도 | 낮음 | 중간 | 낮음 | 높음 | 낮음 |
| Access Key 접두어 | AKIA | ASIA | ASIA | ASIA | ASIA |
| 사용 환경 | 어디서든 | 어디서든 | EC2 | EKS | EKS |
| 권장 여부 | 비권장 | 권장 | 권장 | 권장 | 가장 권장 |
AK = Access Key ID, SK = Secret Access Key, ST = Session Token
4. IAM (Identity and Access Management) 핵심 개념
4.1 IAM User (IAM 사용자)
┌─────────────────────────────────────────────────────────────┐
│ IAM User │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: AWS 계정 내에서 특정 사람이나 서비스를 나타내는 엔티티│
│ │
│ 인증 방식: │
│ ├── Console 접근: 사용자 이름 + 비밀번호 (+ MFA) │
│ └── API 접근: Access Key ID + Secret Access Key │
│ │
│ 특징: │
│ ├── 1 User = 1 신원 (사람 또는 애플리케이션) │
│ ├── 최대 2개의 Access Key 보유 가능 │
│ ├── 직접 Policy 부착 또는 Group 소속으로 권한 획득 │
│ └── ARN: arn:aws:iam::123456789012:user/username │
│ │
│ 모범 사례: │
│ ├── 사람 사용자 → IAM Identity Center (SSO) 사용 권장 │
│ ├── 서비스 → IAM Role 사용 권장 │
│ └── IAM User는 최후의 수단으로만 사용 │
│ │
└─────────────────────────────────────────────────────────────┘
4.2 IAM Group (IAM 그룹)
┌─────────────────────────────────────────────────────────────┐
│ IAM Group │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: IAM User의 집합. 여러 User에게 동일 권한 일괄 부여 │
│ │
│ 특징: │
│ ├── Group에 Policy를 부착 → 소속 User 전원에게 적용 │
│ ├── User는 최대 10개 Group에 소속 가능 │
│ ├── Group은 중첩(nesting) 불가 │
│ ├── Group으로 로그인 불가 (인증 주체가 아님) │
│ └── ARN: arn:aws:iam::123456789012:group/groupname │
│ │
│ 예시: │
│ ├── Developers 그룹 → S3, Lambda, DynamoDB 접근 │
│ ├── Admins 그룹 → AdministratorAccess │
│ └── ReadOnly 그룹 → ReadOnlyAccess │
│ │
└─────────────────────────────────────────────────────────────┘
4.3 IAM Role (IAM 역할)
┌─────────────────────────────────────────────────────────────┐
│ IAM Role │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: 특정 권한을 가진 "역할". 누구든 맡을(Assume) 수 있음 │
│ │
│ 핵심 구성 (2가지 Policy): │
│ │
│ 1) Trust Policy (신뢰 정책) │
│ └── "누가 이 역할을 맡을 수 있는가?" │
│ └── Principal 필드에 허용 대상 명시 │
│ └── 예: EC2 서비스, 특정 IAM User, 다른 AWS 계정 │
│ │
│ 2) Permission Policy (권한 정책) │
│ └── "이 역할을 맡으면 무엇을 할 수 있는가?" │
│ └── S3 읽기, DynamoDB 쓰기 등 실제 작업 권한 │
│ │
│ 비유: │
│ ├── Trust Policy = 출입증 발급 대상 목록 │
│ └── Permission Policy = 출입증으로 열 수 있는 문 목록 │
│ │
└─────────────────────────────────────────────────────────────┘
Trust Policy 예시:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
위 예시의 의미: “EC2 서비스가 이 역할을 맡을 수 있다(AssumeRole).”
4.4 IAM Policy 유형 (7가지)
┌──────────────────────────────────────────────────────────────────────┐
│ IAM Policy 유형 7가지 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1. Identity-based Policy (자격 증명 기반 정책) │
│ └── User, Group, Role에 부착 │
│ └── "이 주체가 무엇을 할 수 있는가" │
│ └── Managed Policy (AWS/고객 관리형) 또는 Inline Policy │
│ │
│ 2. Resource-based Policy (리소스 기반 정책) │
│ └── S3 Bucket, SQS Queue, Lambda 등 리소스에 직접 부착 │
│ └── "이 리소스에 누가 접근할 수 있는가" │
│ └── 교차 계정 접근 시 필수 │
│ │
│ 3. Permissions Boundary (권한 경계) │
│ └── IAM User/Role에 설정 │
│ └── 부여 가능한 "최대 권한"을 제한 │
│ └── Identity Policy와 교집합만 허용 │
│ │
│ 4. SCP = Service Control Policy (서비스 제어 정책) │
│ └── AWS Organizations에서 OU/계정에 적용 │
│ └── 계정 전체의 최대 권한을 제한하는 가드레일 │
│ └── Root 사용자에게도 적용됨 │
│ │
│ 5. RCP = Resource Control Policy (리소스 제어 정책) │
│ └── AWS Organizations에서 리소스 수준으로 적용 │
│ └── 2024년 도입. SCP의 리소스 버전 │
│ │
│ 6. ACL = Access Control List (접근 제어 목록) │
│ └── S3, VPC 등에서 사용하는 레거시 접근 제어 │
│ └── JSON이 아닌 고유 형식 │
│ └── 교차 계정 접근에 사용 (점차 Resource Policy로 대체) │
│ │
│ 7. Session Policy (세션 정책) │
│ └── AssumeRole 시 추가로 전달하는 인라인 정책 │
│ └── Role의 Permission Policy와 교집합만 허용 │
│ └── 동적으로 권한을 축소할 때 사용 │
│ │
└──────────────────────────────────────────────────────────────────────┘
4.5 Policy 평가 로직
┌──────────────────────────────────────────────────────────────────────┐
│ IAM Policy 평가 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 요청 수신 │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 1. 명시적 Deny 확인 │ ← 어떤 정책이든 Deny가 있으면 │
│ └────────┬────────────┘ 즉시 거부 (최우선) │
│ │ Deny 없음 │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 2. SCP 확인 │ ← Organizations 가드레일 │
│ └────────┬────────────┘ Allow 없으면 → 묵시적 거부 │
│ │ Allow 있음 │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 3. Resource Policy │ ← 리소스 기반 정책 확인 │
│ │ 확인 │ (교차 계정 시 필수) │
│ └────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 4. Permission │ ← 권한 경계 확인 │
│ │ Boundary 확인 │ 설정 시 교집합만 허용 │
│ └────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 5. Session Policy │ ← 세션 정책 확인 │
│ │ 확인 │ 설정 시 교집합만 허용 │
│ └────────┬────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 6. Identity Policy │ ← 사용자/역할의 정책 확인 │
│ │ 확인 │ Allow 있으면 → 허용 │
│ └────────┬────────────┘ Allow 없으면 → 묵시적 거부 │
│ │ │
│ ▼ │
│ 최종 결정: Allow 또는 Deny │
│ │
│ ※ 핵심 원칙: Explicit Deny > Allow > Implicit Deny │
│ │
└──────────────────────────────────────────────────────────────────────┘
4.6 RBAC vs ABAC 비교
| 항목 | RBAC (Role-Based Access Control) | ABAC (Attribute-Based Access Control) |
|---|---|---|
| 의미 | 역할 기반 접근 제어 | 속성 기반 접근 제어 |
| 접근 방식 | Role별로 Policy 부여 | 태그(속성)로 권한 결정 |
| Policy 수 | Role 수만큼 필요 | 소수의 Policy로 다수 커버 |
| 확장성 | 새 리소스마다 Policy 수정 | 태그만 붙이면 자동 적용 |
| 예시 | DevRole → dev-* 리소스 접근 | Project=X 태그가 같으면 접근 |
| 장점 | 직관적, 감사 용이 | 유연, 확장성 우수 |
| 단점 | Role 폭증 (Role Explosion) | 태그 관리 복잡 |
| AWS 지원 | IAM Role + Policy | Condition에서 aws:PrincipalTag 사용 |
5. STS (Security Token Service) 심층 분석
5.1 STS란?
┌─────────────────────────────────────────────────────────────┐
│ STS = Security Token Service │
│ (보안 토큰 서비스) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 역할: 임시 보안 자격증명(Temporary Security Credentials) │
│ 을 발급하는 글로벌 웹 서비스 │
│ │
│ 입력: 기존 자격증명 + 맡고자 하는 역할(Role) │
│ 출력: Access Key + Secret Key + Session Token + 만료시간 │
│ │
│ 엔드포인트: │
│ ├── 글로벌: https://sts.amazonaws.com │
│ ├── 리전별: https://sts.ap-northeast-2.amazonaws.com │
│ └── 리전별 사용 권장 (지연시간 감소, 가용성 향상) │
│ │
│ 주요 API: │
│ ├── AssumeRole │
│ ├── AssumeRoleWithWebIdentity │
│ ├── AssumeRoleWithSAML │
│ ├── GetSessionToken │
│ ├── GetFederationToken │
│ └── GetCallerIdentity (인증 확인용, 권한 불필요) │
│ │
└─────────────────────────────────────────────────────────────┘
5.2 AssumeRole — 역할 맡기
┌─────────────────────────────────────────────────────────────┐
│ AssumeRole 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 호출자 (IAM User/Role) │
│ │ │
│ │ sts:AssumeRole 호출 │
│ │ ├── RoleArn: 맡고 싶은 Role │
│ │ ├── RoleSessionName: 세션 식별자 (CloudTrail 기록) │
│ │ ├── DurationSeconds: 토큰 수명 (900~43200) │
│ │ ├── ExternalId: (선택) Confused Deputy 방지 │
│ │ └── Policy: (선택) Session Policy로 권한 축소 │
│ │ │
│ ▼ │
│ STS (Security Token Service) │
│ │ │
│ │ 검증: │
│ │ 1. 호출자에게 sts:AssumeRole 권한 있는가? │
│ │ 2. 대상 Role의 Trust Policy가 호출자를 허용하는가? │
│ │ 3. ExternalId가 맞는가? (설정된 경우) │
│ │ │
│ ▼ │
│ 임시 자격증명 반환 │
│ ├── AccessKeyId (ASIA...) │
│ ├── SecretAccessKey │
│ ├── SessionToken │
│ └── Expiration │
│ │
└─────────────────────────────────────────────────────────────┘
Java SDK 예시:
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
import software.amazon.awssdk.services.sts.model.AssumeRoleResponse;
import software.amazon.awssdk.services.sts.model.Credentials;
StsClient stsClient = StsClient.create();
AssumeRoleResponse response = stsClient.assumeRole(
AssumeRoleRequest.builder()
.roleArn("arn:aws:iam::123456789012:role/CrossAccountRole")
.roleSessionName("my-session-" + System.currentTimeMillis())
.durationSeconds(3600) // 1시간
.build()
);
Credentials creds = response.credentials();
// creds.accessKeyId() → ASIA...
// creds.secretAccessKey() → ...
// creds.sessionToken() → ...
// creds.expiration() → 2026-03-05T11:00:00Z
5.3 AssumeRoleWithWebIdentity — OIDC 기반
┌─────────────────────────────────────────────────────────────┐
│ AssumeRoleWithWebIdentity 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ OIDC Provider (Google, GitHub, EKS OIDC 등) │
│ │ │
│ │ 1. 사용자/Pod 인증 → ID Token (JWT) 발급 │
│ │ │
│ ▼ │
│ 애플리케이션 │
│ │ │
│ │ 2. sts:AssumeRoleWithWebIdentity 호출 │
│ │ ├── RoleArn: 맡고 싶은 Role │
│ │ ├── WebIdentityToken: OIDC ID Token (JWT) │
│ │ └── RoleSessionName: 세션 이름 │
│ │ │
│ ▼ │
│ STS │
│ │ │
│ │ 검증: │
│ │ 1. JWT 서명 검증 (OIDC Provider의 공개 키) │
│ │ 2. aud(audience) 클레임 확인 │
│ │ 3. sub(subject) 클레임 확인 │
│ │ 4. Role Trust Policy에서 OIDC Provider 허용 확인 │
│ │ │
│ ▼ │
│ 임시 자격증명 반환 │
│ │
│ ※ IRSA가 이 API를 내부적으로 사용 │
│ │
└─────────────────────────────────────────────────────────────┘
5.4 AssumeRoleWithSAML — 기업 SSO
┌─────────────────────────────────────────────────────────────┐
│ AssumeRoleWithSAML 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 사용자 → 기업 IdP (Active Directory 등) │
│ │ │
│ │ 1. 사용자 인증 (ID/PW, Kerberos 등) │
│ │ │
│ ▼ │
│ IdP = Identity Provider (신원 제공자) │
│ │ │
│ │ 2. SAML Assertion (XML) 발급 │
│ │ └── 사용자 신원 + 속성 + 서명 │
│ │ │
│ ▼ │
│ 애플리케이션/브라우저 │
│ │ │
│ │ 3. sts:AssumeRoleWithSAML 호출 │
│ │ ├── RoleArn: 맡을 Role │
│ │ ├── PrincipalArn: SAML Provider ARN │
│ │ └── SAMLAssertion: Base64 인코딩된 SAML 응답 │
│ │ │
│ ▼ │
│ STS → 임시 자격증명 반환 │
│ │
└─────────────────────────────────────────────────────────────┘
5.5 GetSessionToken — MFA 연계
┌─────────────────────────────────────────────────────────────┐
│ GetSessionToken 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 사용 목적: IAM User가 MFA 인증 후 임시 자격증명 획득 │
│ │
│ 호출: │
│ ├── SerialNumber: MFA 장치 ARN │
│ │ (예: arn:aws:iam::123456789012:mfa/user1) │
│ └── TokenCode: MFA 장치의 6자리 OTP │
│ │
│ 결과: │
│ ├── MFA 인증이 포함된 임시 자격증명 반환 │
│ └── 이 자격증명으로 MFA 필수 작업 수행 가능 │
│ │
│ ※ AssumeRole과 달리 Role을 맡는 것이 아님 │
│ ※ IAM User 자신의 임시 버전 자격증명을 받는 것 │
│ │
└─────────────────────────────────────────────────────────────┘
5.6 GetFederationToken — 연합 사용자
┌─────────────────────────────────────────────────────────────┐
│ GetFederationToken 흐름 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 사용 목적: 연합(Federated) 사용자에게 임시 자격증명 부여 │
│ │
│ 특징: │
│ ├── IAM User(또는 Root)가 호출 │
│ ├── 호출자의 권한 범위 내에서만 권한 부여 가능 │
│ ├── 최대 36시간 유효 (IAM User 호출 시) │
│ ├── Session Policy 전달 필수 │
│ └── MFA 지원하지 않음 │
│ │
│ 사용 사례: │
│ ├── 프록시 서버가 각 요청마다 다른 권한 부여 │
│ └── 멀티 테넌트 앱에서 테넌트별 제한된 접근 제공 │
│ │
└─────────────────────────────────────────────────────────────┘
5.7 STS API 비교표
| API | 호출 주체 | 용도 | 최대 수명 | MFA 지원 |
|---|---|---|---|---|
| AssumeRole | User/Role | 역할 전환 | 12시간 | 선택적 |
| AssumeRoleWithWebIdentity | OIDC 토큰 보유자 | OIDC 연합 | 12시간 | 불가 |
| AssumeRoleWithSAML | SAML Assertion 보유자 | 기업 SSO | 12시간 | 불가 |
| GetSessionToken | IAM User | MFA 강화 | 36시간 | 필수 |
| GetFederationToken | IAM User/Root | 연합 사용자 | 36시간 | 불가 |
| GetCallerIdentity | 누구든 | 신원 확인 | - | - |
5.8 토큰 갱신 전략
┌─────────────────────────────────────────────────────────────┐
│ 토큰 갱신 전략 │
├─────────────────────────────────────────────────────────────┤
│ │
│ ※ AWS STS에는 OAuth의 Refresh Token 개념이 없음! │
│ ※ 만료 전에 원본 자격증명으로 재발급 필요 │
│ │
│ 전략 1: SDK 자동 갱신 (권장) │
│ └── StsAssumeRoleCredentialsProvider 사용 │
│ └── asyncCredentialUpdateEnabled(true) 설정 │
│ └── 만료 5분 전에 자동으로 백그라운드 갱신 │
│ │
│ 전략 2: Custom Provider 구현 │
│ └── resolveCredentials()에서 만료 시간 체크 │
│ └── 만료 임박 시 AssumeRole 재호출 │
│ └── 동시성 제어 필요 (synchronized 또는 Lock) │
│ │
│ 전략 3: IAM Role (EC2/ECS/EKS) │
│ └── SDK가 IMDS/Container Endpoint에서 자동 갱신 │
│ └── 개발자 개입 불필요 │
│ │
│ 전략 4: MaxSessionDuration 연장 │
│ └── Role 설정에서 최대 12시간까지 확장 │
│ └── 배치 작업에 유용하지만 보안 trade-off 존재 │
│ │
└─────────────────────────────────────────────────────────────┘
6. EC2 자격증명 — Instance Profile & IMDS
6.1 Instance Profile이란?
┌─────────────────────────────────────────────────────────────┐
│ Instance Profile = EC2 ↔ IAM Role 어댑터 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 문제: EC2에 IAM Role을 직접 연결할 수 없음 │
│ 이유: IAM Role은 여러 서비스가 공유하는 범용 개념이지만, │
│ EC2 출시(2006) 시점에 IAM Role(2011)이 없었음. │
│ 나중에 연결 메커니즘이 필요해서 "어댑터" 도입 │
│ │
│ 구조: │
│ │
│ ┌──────────────┐ ┌──────────────────┐ ┌─────────┐ │
│ │ EC2 Instance │────▶│ Instance Profile │────▶│IAM Role │ │
│ └──────────────┘ └──────────────────┘ └─────────┘ │
│ (1:1 연결 어댑터) │
│ │
│ AWS Console에서 EC2에 Role 연결 시: │
│ └── 내부적으로 같은 이름의 Instance Profile 자동 생성 │
│ └── 그래서 사용자는 Instance Profile을 의식하지 못함 │
│ │
│ CLI/SDK에서는 명시적으로 Instance Profile을 다룸: │
│ └── aws iam create-instance-profile │
│ └── aws iam add-role-to-instance-profile │
│ │
└─────────────────────────────────────────────────────────────┘
6.2 IMDS v1 vs v2
IMDS = Instance Metadata Service (인스턴스 메타데이터 서비스)
EC2 인스턴스가 자기 자신의 정보(메타데이터, 자격증명 등)를 조회하는 내부 HTTP 서비스.
┌─────────────────────────────────────────────────────────────┐
│ IMDSv1 vs IMDSv2 비교 │
├─────────────────────────────────────────────────────────────┤
│ │
│ IMDSv1 (레거시): │
│ ├── 단순 HTTP GET 요청 │
│ ├── curl http://169.254.169.254/latest/meta-data/ │
│ ├── 인증 없이 누구나 접근 가능 │
│ └── SSRF (Server-Side Request Forgery) 취약 │
│ └── 2019년 Capital One 해킹 사건의 원인 │
│ │
│ IMDSv2 (권장): │
│ ├── 토큰 기반 2단계 접근 │
│ │ │
│ │ Step 1: PUT으로 세션 토큰 발급 │
│ │ TOKEN=$(curl -X PUT │
│ │ "http://169.254.169.254/latest/api/token" │
│ │ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") │
│ │ │
│ │ Step 2: GET에 토큰 첨부하여 메타데이터 조회 │
│ │ curl http://169.254.169.254/latest/meta-data/ │
│ │ -H "X-aws-ec2-metadata-token: $TOKEN" │
│ │ │
│ ├── PUT은 HTTP 리다이렉트를 따르지 않음 → SSRF 방어 │
│ ├── TTL=1인 패킷 → 네트워크 홉 제한 → 외부 접근 차단 │
│ └── AWS SDK v2는 기본적으로 IMDSv2 먼저 시도 │
│ │
│ 필수화 추세: │
│ ├── 2024년부터 신규 인스턴스 IMDSv2 기본값 │
│ └── HttpTokens=required 설정으로 v1 차단 권장 │
│ │
└─────────────────────────────────────────────────────────────┘
| 항목 | IMDSv1 | IMDSv2 |
|---|---|---|
| 접근 방식 | GET만 | PUT(토큰) → GET(토큰 첨부) |
| 인증 | 없음 | 세션 토큰 |
| SSRF 방어 | 취약 | 강력 |
| 네트워크 홉 | 제한 없음 | TTL=1 (로컬만) |
| AWS SDK v2 | 폴백으로 지원 | 기본 시도 |
| 권장 여부 | 비권장 | 강력 권장 |
6.3 EC2 자격증명 흐름
┌─────────────────────────────────────────────────────────────────────┐
│ EC2 Instance → AWS API 호출 흐름 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 애플리케이션이 S3Client.create() 으로 SDK 초기화 │
│ │ │
│ ▼ │
│ 2. DefaultCredentialsProvider가 체인 탐색 │
│ ├── 환경변수 → 없음 │
│ ├── 시스템속성 → 없음 │
│ ├── Web Identity → 없음 │
│ ├── Profile 파일 → 없음 │
│ ├── ECS Container → 없음 │
│ └── IMDS → 발견! │
│ │ │
│ ▼ │
│ 3. IMDS (169.254.169.254) 에서 임시 자격증명 획득 │
│ ├── GET .../iam/security-credentials/ │
│ │ └── Role 이름 반환 (예: "MyEC2Role") │
│ └── GET .../iam/security-credentials/MyEC2Role │
│ └── AccessKeyId, SecretAccessKey, Token, Expiration 반환 │
│ │ │
│ ▼ │
│ 4. 임시 자격증명으로 AWS API 호출 (S3, DynamoDB 등) │
│ │ │
│ ▼ │
│ 5. 만료 전에 SDK가 자동으로 IMDS에서 새 자격증명 조회 │
│ └── 개발자 개입 불필요 │
│ │
└─────────────────────────────────────────────────────────────────────┘
7. 컨테이너 자격증명
7.1 ECS Task Role
┌─────────────────────────────────────────────────────────────────────┐
│ ECS = Elastic Container Service 자격증명 │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 두 가지 Role을 구분해야 함: │
│ │
│ 1) Task Role (태스크 역할) │
│ └── 컨테이너 내 애플리케이션이 AWS API 호출할 때 사용 │
│ └── 예: S3에서 파일 읽기, DynamoDB에 쓰기 │
│ └── 환경변수: AWS_CONTAINER_CREDENTIALS_RELATIVE_URI │
│ └── SDK가 http://169.254.170.2$URI 에서 자격증명 획득 │
│ │
│ 2) Task Execution Role (태스크 실행 역할) │
│ └── ECS Agent가 태스크를 시작할 때 사용 │
│ └── 예: ECR에서 이미지 Pull, CloudWatch에 로그 쓰기 │
│ └── 애플리케이션 코드와 무관 │
│ │
│ 비유: │
│ ├── Task Execution Role = 배달원이 식당에서 음식을 가져오는 권한 │
│ └── Task Role = 음식을 받은 사람이 식당에 리뷰를 쓰는 권한 │
│ │
└─────────────────────────────────────────────────────────────────────┘
| 항목 | Task Role | Task Execution Role |
|---|---|---|
| 사용 주체 | 컨테이너 내 애플리케이션 | ECS Agent |
| 목적 | AWS API 호출 (S3, DynamoDB 등) | 태스크 준비 (ECR pull, 로그) |
| 설정 위치 | Task Definition의 taskRoleArn |
Task Definition의 executionRoleArn |
| SDK 인식 | DefaultCredentialsProvider 자동 | 개발자가 신경 쓸 필요 없음 |
7.2 IRSA (IAM Roles for Service Accounts)
IRSA = IAM Roles for Service Accounts (서비스 어카운트용 IAM 역할)
EKS에서 Pod 단위로 세밀한 AWS 권한을 부여하는 메커니즘. 2019년 도입.
┌──────────────────────────────────────────────────────────────────────┐
│ IRSA 인증 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 사전 설정: │
│ ├── EKS 클러스터에 OIDC Provider 생성 (클러스터당 1개) │
│ ├── IAM Role 생성 + Trust Policy에 OIDC Provider ARN 등록 │
│ └── Kubernetes ServiceAccount에 Role ARN annotation │
│ │
│ 런타임 흐름: │
│ │
│ ┌───────────┐ ┌──────────────────┐ ┌─────────────────┐ │
│ │ Pod 시작 │───▶│ Mutating Webhook │───▶│ 환경변수 주입 │ │
│ └───────────┘ │ (EKS가 자동) │ │ AWS_ROLE_ARN │ │
│ └──────────────────┘ │ AWS_WEB_IDENTITY│ │
│ │ _TOKEN_FILE │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Projected Service Account Token │ │
│ │ (JWT, /var/run/secrets/...token) │ │
│ │ ├── iss: EKS OIDC Endpoint │ │
│ │ ├── sub: system:serviceaccount:ns:sa │ │
│ │ └── aud: sts.amazonaws.com │ │
│ └───────────────────┬──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ AWS SDK: DefaultCredentialsProvider │ │
│ │ → WebIdentityTokenCredentials 발견 │ │
│ │ → STS AssumeRoleWithWebIdentity 호출 │ │
│ └───────────────────┬──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ STS 검증: │ │
│ │ 1. JWT 서명 → OIDC Provider 공개 키 │ │
│ │ 2. aud 클레임 → sts.amazonaws.com │ │
│ │ 3. sub 클레임 → Trust Policy 조건 │ │
│ │ → 임시 자격증명 반환 │ │
│ └──────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
ServiceAccount 설정 예시:
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-app
namespace: production
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/MyPodRole
IAM Role Trust Policy 예시:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::123456789012:oidc-provider/oidc.eks.ap-northeast-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"oidc.eks.ap-northeast-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:aud": "sts.amazonaws.com",
"oidc.eks.ap-northeast-2.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE:sub": "system:serviceaccount:production:my-app"
}
}
}
]
}
IRSA의 한계:
- 클러스터당 OIDC Provider를 별도로 생성해야 함
- IAM Trust Policy에 OIDC Provider ARN을 하드코딩해야 함
- 클러스터를 재생성하면 OIDC Provider ARN이 바뀌어 모든 Role 수정 필요
- 설정 과정이 복잡 (OIDC 생성 → Role 생성 → SA annotation)
7.3 EKS Pod Identity (2023+)
EKS Pod Identity = IRSA의 후속 솔루션으로, OIDC Provider 설정 없이 Pod에 IAM Role을 연결하는 메커니즘.
┌──────────────────────────────────────────────────────────────────────┐
│ EKS Pod Identity 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 사전 설정 (IRSA보다 훨씬 간단): │
│ ├── EKS Pod Identity Agent (DaemonSet) 설치 (EKS 애드온) │
│ ├── IAM Role 생성 + Trust Policy에 pods.eks.amazonaws.com 지정 │
│ └── Pod Identity Association 생성 (클러스터 + 네임스페이스 + SA) │
│ │
│ 런타임 흐름: │
│ │
│ ┌───────────┐ ┌──────────────────┐ ┌─────────────────┐ │
│ │ Pod 시작 │───▶│ Mutating Webhook │───▶│ 환경변수 주입 │ │
│ └───────────┘ │ (EKS 자동) │ │ AWS_CONTAINER_ │ │
│ └──────────────────┘ │ _CREDENTIALS_.. │ │
│ │ _FULL_URI │ │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ Pod Identity Agent (노드의 DaemonSet)│ │
│ │ └── 169.254.170.23:80 에서 리슨 │ │
│ │ └── AssumeRoleForPodIdentity API 호출│ │
│ └───────────────────┬──────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────┐ │
│ │ EKS Auth Service │ │
│ │ └── Pod의 ServiceAccount 확인 │ │
│ │ └── Association 매칭 │ │
│ │ → 임시 자격증명 반환 │ │
│ │ │ │
│ │ 추가: Session Tags 자동 포함 │ │
│ │ ├── eks-cluster-arn │ │
│ │ ├── eks-cluster-name │ │
│ │ ├── kubernetes-namespace │ │
│ │ ├── kubernetes-service-account │ │
│ │ └── kubernetes-pod-name │ │
│ └──────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────┘
IAM Role Trust Policy (Pod Identity용):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}
Pod Identity Association 생성:
aws eks create-pod-identity-association \
--cluster-name my-cluster \
--namespace production \
--service-account my-app \
--role-arn arn:aws:iam::123456789012:role/MyPodRole
7.4 IRSA vs EKS Pod Identity 비교표
| 항목 | IRSA | EKS Pod Identity |
|---|---|---|
| 도입 시기 | 2019 | 2023 |
| OIDC Provider 필요 | 필수 (클러스터당 1개) | 불필요 |
| Trust Policy 내용 | OIDC Provider ARN 하드코딩 | pods.eks.amazonaws.com 서비스 |
| 클러스터 재생성 시 | 모든 Role Trust Policy 수정 필요 | 영향 없음 |
| 설정 단계 | 4단계 (OIDC→Role→Policy→SA) | 2단계 (Role→Association) |
| Session Tags | 미지원 | 자동 포함 (namespace, SA 등) |
| ABAC 지원 | 제한적 | Session Tags로 자연스럽게 지원 |
| SDK 인식 방식 | Web Identity Token 파일 | Container Credentials URI |
| 교차 계정 | 지원 | 지원 |
| 최소 SDK 버전 | 오래전부터 지원 | Java SDK 2.21.x+, Boto3 1.28.57+ |
| 기존 IRSA 호환 | - | 공존 가능 (점진적 마이그레이션) |
| AWS 권장 | 레거시 | 신규 프로젝트에 권장 |
8. DefaultCredentialsProvider — SDK 자격증명 체인
8.1 개념
┌─────────────────────────────────────────────────────────────┐
│ DefaultCredentialsProvider 개념 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 정의: AWS SDK가 제공하는 "자동 자격증명 탐색 체인" │
│ │
│ 원리: │
│ ├── 미리 정의된 여러 소스를 순서대로 탐색 │
│ ├── 첫 번째로 발견된 유효한 자격증명을 사용 │
│ └── 모든 소스에서 실패 시 예외 발생 │
│ │
│ 장점: │
│ ├── 코드 변경 없이 환경에 따라 자격증명 자동 전환 │
│ │ └── 로컬: ~/.aws/credentials 파일 │
│ │ └── EC2: IMDS Instance Profile │
│ │ └── EKS: IRSA 또는 Pod Identity │
│ │ └── ECS: Task Role │
│ ├── 하드코딩 불필요 → 보안 강화 │
│ └── 12-factor app 원칙 준수 (환경별 설정 분리) │
│ │
│ 핵심 코드: │
│ └── S3Client.create() │
│ └── 내부에서 DefaultCredentialsProvider.create() 사용 │
│ └── 명시적 지정도 가능 │
│ │
└─────────────────────────────────────────────────────────────┘
8.2 Java SDK v2 탐색 순서 (상세)
┌──────────────────────────────────────────────────────────────────────┐
│ Java SDK v2 — DefaultCredentialsProvider 탐색 순서 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ [1] SystemPropertyCredentialsProvider │
│ └── Java 시스템 속성에서 탐색 │
│ └── -Daws.accessKeyId=AKIA... │
│ └── -Daws.secretAccessKey=... │
│ └── -Daws.sessionToken=... (선택) │
│ │ │
│ ▼ (없으면 다음) │
│ │
│ [2] EnvironmentVariableCredentialsProvider │
│ └── OS 환경 변수에서 탐색 │
│ └── AWS_ACCESS_KEY_ID │
│ └── AWS_SECRET_ACCESS_KEY │
│ └── AWS_SESSION_TOKEN (선택) │
│ │ │
│ ▼ (없으면 다음) │
│ │
│ [3] WebIdentityTokenCredentialsProvider │
│ └── OIDC 기반 Web Identity Token에서 탐색 │
│ └── AWS_WEB_IDENTITY_TOKEN_FILE (토큰 파일 경로) │
│ └── AWS_ROLE_ARN (맡을 Role) │
│ └── → STS AssumeRoleWithWebIdentity 호출 │
│ └── ※ IRSA가 이 방식을 사용 │
│ │ │
│ ▼ (없으면 다음) │
│ │
│ [4] ProfileCredentialsProvider │
│ └── AWS 설정 파일에서 탐색 │
│ └── ~/.aws/credentials (자격증명 파일) │
│ └── ~/.aws/config (설정 파일) │
│ └── [default] 프로필 또는 AWS_PROFILE 지정 프로필 │
│ └── role_arn 있으면 AssumeRole 자동 수행 │
│ │ │
│ ▼ (없으면 다음) │
│ │
│ [5] ContainerCredentialsProvider │
│ └── ECS/EKS 컨테이너 자격증명 엔드포인트에서 탐색 │
│ └── AWS_CONTAINER_CREDENTIALS_RELATIVE_URI (ECS Task Role) │
│ └── AWS_CONTAINER_CREDENTIALS_FULL_URI (EKS Pod Identity) │
│ └── http://169.254.170.2$RELATIVE_URI │
│ │ │
│ ▼ (없으면 다음) │
│ │
│ [6] InstanceProfileCredentialsProvider │
│ └── EC2 Instance Metadata Service (IMDS)에서 탐색 │
│ └── http://169.254.169.254/latest/meta-data/iam/... │
│ └── IMDSv2 먼저 시도 → 실패 시 IMDSv1 폴백 │
│ └── Instance Profile에 연결된 IAM Role의 임시 자격증명 │
│ │
│ ※ 모든 소스에서 실패 → SdkClientException 발생 │
│ │
└──────────────────────────────────────────────────────────────────────┘
Java 코드 예시:
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.regions.Region;
// 방법 1: 명시적 지정
S3Client s3 = S3Client.builder()
.region(Region.AP_NORTHEAST_2)
.credentialsProvider(DefaultCredentialsProvider.create())
.build();
// 방법 2: 생략 (내부적으로 동일)
S3Client s3 = S3Client.builder()
.region(Region.AP_NORTHEAST_2)
.build();
// 방법 3: 가장 간결 (리전도 환경변수/설정에서 자동 탐색)
S3Client s3 = S3Client.create();
8.3 Python (Boto3) 탐색 순서
┌──────────────────────────────────────────────────────────────────────┐
│ Python Boto3 — 자격증명 탐색 순서 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ [1] 코드 내 명시적 전달 │
│ └── boto3.Session(aws_access_key_id=..., ...) │
│ └── ※ 하드코딩 비권장 │
│ │
│ [2] 환경 변수 │
│ └── AWS_ACCESS_KEY_ID │
│ └── AWS_SECRET_ACCESS_KEY │
│ └── AWS_SESSION_TOKEN │
│ │
│ [3] 공유 자격증명 파일 │
│ └── ~/.aws/credentials │
│ │
│ [4] AWS 설정 파일 │
│ └── ~/.aws/config │
│ │
│ [5] Assume Role Provider │
│ └── config 파일의 role_arn 설정 │
│ │
│ [6] Boto2 설정 파일 (레거시) │
│ └── /etc/boto.cfg, ~/.boto │
│ │
│ [7] ECS Container Credentials │
│ └── AWS_CONTAINER_CREDENTIALS_RELATIVE_URI │
│ │
│ [8] EC2 Instance Metadata (IMDS) │
│ └── http://169.254.169.254/... │
│ │
│ ※ Java SDK와 순서가 약간 다름에 주의 │
│ ※ Java: 시스템속성 > 환경변수 > WebIdentity > Profile │
│ ※ Python: 명시적 > 환경변수 > credentials > config │
│ │
└──────────────────────────────────────────────────────────────────────┘
Python 코드 예시:
import boto3
# 방법 1: 기본 (DefaultCredentialsProvider와 동일 개념)
s3 = boto3.client('s3')
# 방법 2: 프로필 지정
session = boto3.Session(profile_name='dev-account')
s3 = session.client('s3')
# 방법 3: 명시적 자격증명 (비권장 — 테스트용)
s3 = boto3.client(
's3',
aws_access_key_id='AKIA...',
aws_secret_access_key='...',
aws_session_token='...' # 임시 자격증명 시
)
8.4 CustomCredentialProvider 구현
┌─────────────────────────────────────────────────────────────┐
│ CustomCredentialProvider 구현 가이드 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 목적: 표준 체인으로 해결 불가능한 특수한 인증 요구사항 │
│ │
│ 사용 사례: │
│ ├── HashiCorp Vault에서 동적 AWS 자격증명 획득 │
│ ├── 자체 Secret Manager 연동 │
│ ├── 멀티 테넌트 (요청마다 다른 계정의 자격증명) │
│ ├── 커스텀 캐싱/갱신 로직 │
│ └── 감사 로깅이 필요한 경우 │
│ │
│ 인터페이스: AwsCredentialsProvider │
│ └── resolveCredentials() 메서드 1개만 구현 │
│ │
└─────────────────────────────────────────────────────────────┘
Vault 연동 Custom Provider 예시:
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
public class VaultAwsCredentialProvider implements AwsCredentialsProvider {
private final VaultClient vaultClient;
private volatile AwsCredentials cached;
private volatile Instant expiration;
private final Duration refreshBuffer = Duration.ofMinutes(5);
public VaultAwsCredentialProvider(VaultClient vaultClient) {
this.vaultClient = vaultClient;
}
@Override
public AwsCredentials resolveCredentials() {
if (needsRefresh()) {
synchronized (this) {
if (needsRefresh()) {
refresh();
}
}
}
return cached;
}
private boolean needsRefresh() {
return cached == null
|| Instant.now().isAfter(expiration.minus(refreshBuffer));
}
private void refresh() {
// Vault의 AWS Secrets Engine에서 동적 자격증명 획득
VaultResponse response = vaultClient.read("aws/creds/my-role");
Map<String, Object> data = response.getData();
this.cached = AwsSessionCredentials.create(
(String) data.get("access_key"),
(String) data.get("secret_key"),
(String) data.get("security_token")
);
// Vault lease TTL 기반 만료 시간 설정
int leaseDurationSec = response.getLeaseDuration();
this.expiration = Instant.now().plusSeconds(leaseDurationSec);
}
}
사용:
S3Client s3 = S3Client.builder()
.region(Region.AP_NORTHEAST_2)
.credentialsProvider(new VaultAwsCredentialProvider(vaultClient))
.build();
Kotlin 예시:
class VaultAwsCredentialProvider(
private val vaultClient: VaultClient,
private val refreshBuffer: Duration = Duration.ofMinutes(5)
) : AwsCredentialsProvider {
@Volatile private var cached: AwsCredentials? = null
@Volatile private var expiration: Instant = Instant.MIN
override fun resolveCredentials(): AwsCredentials {
if (needsRefresh()) {
synchronized(this) {
if (needsRefresh()) refresh()
}
}
return cached!!
}
private fun needsRefresh(): Boolean =
cached == null || Instant.now().isAfter(expiration.minus(refreshBuffer))
private fun refresh() {
val response = vaultClient.read("aws/creds/my-role")
val data = response.data
cached = AwsSessionCredentials.create(
data["access_key"] as String,
data["secret_key"] as String,
data["security_token"] as String
)
expiration = Instant.now().plusSeconds(response.leaseDuration.toLong())
}
}
8.5 환경별 실전 패턴
| 환경 | 권장 방식 | 코드 변경 필요 | 설명 |
|---|---|---|---|
| 로컬 개발 | ~/.aws/credentials 파일 |
없음 | aws configure로 설정. DefaultCredentialsProvider 자동 탐색 |
| CI/CD (GitHub Actions) | 환경 변수 | 없음 | AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 시크릿 설정 |
| CI/CD (GitHub OIDC) | Web Identity | 없음 | GitHub OIDC → AssumeRoleWithWebIdentity. Access Key 불필요 |
| EC2 | Instance Profile | 없음 | IAM Role 연결. SDK 자동 IMDS 탐색 |
| ECS Fargate | Task Role | 없음 | taskRoleArn 설정. SDK 자동 Container Credentials 탐색 |
| EKS (신규) | EKS Pod Identity | 없음 | Pod Identity Association. SDK 자동 탐색 |
| EKS (기존) | IRSA | 없음 | ServiceAccount annotation. SDK 자동 WebIdentity 탐색 |
| Lambda | 실행 역할 | 없음 | Lambda 함수에 IAM Role 자동 연결 |
| 온프레미스 | IAM Roles Anywhere | 약간 | X.509 인증서 기반. credential_process 설정 |
| Vault 연동 | Custom Provider | 필요 | AwsCredentialsProvider 구현 |
9. 연합 인증 (Federation)
9.1 OIDC Federation
OIDC = OpenID Connect (오픈아이디 커넥트)
OAuth 2.0 프로토콜 위에 신원 확인(Identity) 레이어를 추가한 인증 프로토콜. OpenID 재단에서 관리하며, “Connect”는 기존 OpenID 2.0과 OAuth 2.0을 연결(Connect)한다는 의미.
┌──────────────────────────────────────────────────────────────────────┐
│ OIDC Federation 개념 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ OAuth 2.0과의 관계: │
│ ├── OAuth 2.0 = 인가(Authorization) 프로토콜 │
│ │ └── "이 앱이 내 리소스에 접근해도 되는가?" │
│ │ └── Access Token 발급 │
│ └── OIDC = OAuth 2.0 + 인증(Authentication) │
│ └── "이 사용자가 누구인가?" │
│ └── ID Token (JWT) 추가 발급 │
│ │
│ ID Token (JWT = JSON Web Token) 구조: │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Header │ {"alg":"RS256","typ":"JWT"} │ │
│ ├─────────┼───────────────────────────────────────┤ │
│ │ Payload │ { │ │
│ │ │ "iss": "https://accounts.google.com"│ ← 발급자 │
│ │ │ "sub": "110169484474386276334" │ ← 주체(사용자)│
│ │ │ "aud": "my-app-client-id" │ ← 대상(앱) │
│ │ │ "exp": 1709625600 │ ← 만료시간 │
│ │ │ "iat": 1709622000 │ ← 발급시간 │
│ │ │ "email": "user@example.com" │ ← 클레임 │
│ │ │ } │ │
│ ├─────────┼───────────────────────────────────────┤ │
│ │Signature│ RSASHA256(header.payload, privateKey) │ ← 서명 │
│ └─────────┴───────────────────────────────────────┘ │
│ │
│ AWS에서의 OIDC Federation 사용: │
│ ├── IAM OIDC Provider 등록 (Google, GitHub, Cognito 등) │
│ ├── IAM Role Trust Policy에 OIDC Provider 지정 │
│ ├── 앱이 IdP에서 ID Token 획득 │
│ └── STS AssumeRoleWithWebIdentity로 임시 AWS 자격증명 획득 │
│ │
└──────────────────────────────────────────────────────────────────────┘
9.2 SAML 2.0 Federation
SAML = Security Assertion Markup Language (보안 어설션 마크업 언어)
2002년 OASIS 표준 기관에서 제정. “Assertion”은 “이 사용자는 인증되었다”는 보안 주장(Security Assertion)을 XML 마크업 언어(Markup Language)로 표현한다는 의미.
┌──────────────────────────────────────────────────────────────────────┐
│ SAML 2.0 Federation 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ 사용자 │────▶│ 기업 IdP │────▶│ AWS STS │ │
│ │(브라우저) │ │(AD, Okta 등) │ │ │ │
│ └──────────┘ └──────────────┘ └────────────┘ │
│ │
│ 상세 흐름: │
│ │
│ 1. 사용자가 AWS Console 접근 시도 │
│ │ │
│ ▼ │
│ 2. 기업 IdP (Identity Provider)로 리다이렉트 │
│ └── Active Directory, Okta, PingFederate 등 │
│ │ │
│ ▼ │
│ 3. IdP에서 인증 (ID/PW, Kerberos, MFA 등) │
│ │ │
│ ▼ │
│ 4. IdP가 SAML Assertion (XML) 발급 │
│ └── 사용자 이름, 이메일, 그룹, 맡을 Role ARN 포함 │
│ └── IdP의 비밀 키로 서명 │
│ │ │
│ ▼ │
│ 5. SAML Assertion → AWS STS (AssumeRoleWithSAML) │
│ │ │
│ ▼ │
│ 6. STS 검증 후 임시 자격증명 반환 │
│ └── AWS Console 자동 로그인 또는 API 접근 │
│ │
│ 장점: │
│ ├── AWS에 별도 IAM User 생성 불필요 │
│ ├── 기업 계정 비활성화 시 AWS 접근도 자동 차단 │
│ └── 기존 기업 인증 인프라 재활용 │
│ │
└──────────────────────────────────────────────────────────────────────┘
9.3 AWS IAM Identity Center (구 AWS SSO)
IAM Identity Center = 기존 AWS SSO (Single Sign-On)가 2022년에 이름이 바뀐 서비스. SSO = Single Sign-On (단일 로그인) — 한 번 로그인하면 여러 AWS 계정과 애플리케이션에 접근 가능.
┌──────────────────────────────────────────────────────────────────────┐
│ IAM Identity Center (구 AWS SSO) 구조 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ IAM Identity Center │ │
│ │ (중앙 집중식 접근 관리) │ │
│ ├──────────────────────────────────────────────────┤ │
│ │ │ │
│ │ Identity Source (신원 출처): │ │
│ │ ├── IAM Identity Center 자체 디렉토리 │ │
│ │ ├── Active Directory (AD Connector / AWS MAD) │ │
│ │ └── 외부 IdP (Okta, Azure AD, OneLogin 등) │ │
│ │ │ │
│ │ Permission Set (권한 세트): │ │
│ │ ├── 미리 정의된 권한 묶음 │ │
│ │ ├── IAM Policy와 유사하지만 멀티 계정 적용 │ │
│ │ └── 예: "ReadOnlyAccess", "PowerUserAccess" │ │
│ │ │ │
│ │ 할당 (Assignment): │ │
│ │ ├── 사용자/그룹 + Permission Set + 대상 계정 │ │
│ │ └── "이 사용자가 이 계정에서 이 권한을 가진다" │ │
│ │ │ │
│ └──────────────────────────────────────────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 계정 A (Dev) │ │ 계정 B (Stg) │ │ 계정 C (Prd) │ │
│ │ PowerUser │ │ ReadOnly │ │ ReadOnly │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
│ │
│ CLI 접근: │
│ ├── aws configure sso │
│ ├── 브라우저에서 SSO 로그인 │
│ └── ~/.aws/config에 SSO 프로필 자동 생성 │
│ │
└──────────────────────────────────────────────────────────────────────┘
9.4 Cognito Identity Pool
Cognito = AWS의 사용자 인증/인가 서비스. “Cognito”는 라틴어 “cognoscere”(알다, 인식하다)에서 유래.
┌──────────────────────────────────────────────────────────────────────┐
│ Cognito Identity Pool 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 목적: 모바일/웹 앱 사용자에게 임시 AWS 자격증명 제공 │
│ │
│ 두 가지 컴포넌트: │
│ ├── User Pool: 사용자 회원가입/로그인 (인증) │
│ │ └── JWT 토큰 (ID Token, Access Token, Refresh Token) 발급 │
│ └── Identity Pool: AWS 자격증명 교환 (인가) │
│ └── User Pool 토큰 → 임시 AWS 자격증명 │
│ │
│ 흐름: │
│ │
│ ┌─────────┐ ┌───────────┐ ┌──────────────┐ ┌────────────┐│
│ │ 앱 사용자│───▶│ User Pool │───▶│ Identity Pool│───▶│ AWS 서비스 ││
│ │(모바일/웹)│ │ (인증) │ │ (STS 교환) │ │(S3,DDB 등)││
│ └─────────┘ └───────────┘ └──────────────┘ └────────────┘│
│ │
│ Authenticated vs Unauthenticated: │
│ ├── Authenticated (인증된 접근) │
│ │ └── 로그인한 사용자 → 더 많은 권한의 IAM Role │
│ │ └── 예: S3 읽기/쓰기, DynamoDB 자기 데이터 접근 │
│ └── Unauthenticated (미인증 접근) │
│ └── 로그인하지 않은 사용자 → 제한된 IAM Role │
│ └── 예: 공개 S3 읽기만 허용 │
│ │
│ 지원 IdP: │
│ ├── Cognito User Pool │
│ ├── Google, Apple, Facebook, Amazon │
│ ├── SAML 2.0 기업 IdP │
│ └── OIDC 호환 IdP │
│ │
└──────────────────────────────────────────────────────────────────────┘
9.5 Federation 방식 비교표
| 항목 | OIDC Federation | SAML 2.0 | IAM Identity Center | Cognito |
|---|---|---|---|---|
| 대상 | 서비스/앱 | 기업 사용자 | 기업 멀티 계정 | 모바일/웹 앱 |
| 프로토콜 | OIDC (OAuth 2.0+) | SAML 2.0 (XML) | SAML/OIDC 내부 처리 | 자체 + OIDC/SAML |
| 토큰 형식 | JWT | XML Assertion | 내부 관리 | JWT → AWS Credentials |
| 설정 복잡도 | 중간 | 높음 | 낮음 | 중간 |
| AWS 권장 여부 | 서비스 연동용 | 레거시 | 사람 사용자에 강력 권장 | 앱 사용자용 |
| Console 접근 | 가능 | 가능 | 가능 | 불가 (API만) |
| CLI 접근 | AssumeRoleWithWebIdentity | AssumeRoleWithSAML | aws configure sso |
Cognito SDK |
10. Cross-Account Access (교차 계정 접근)
10.1 왜 필요한가
┌──────────────────────────────────────────────────────────────────────┐
│ 교차 계정 접근이 필요한 이유 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ AWS 모범 사례: 환경/목적별 계정 분리 │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 개발 계정 │ │ 스테이징 │ │ 프로덕션 │ │ 보안/감사 │ │
│ │ 111111111│ │ 222222222│ │ 333333333│ │ 444444444│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ 필요 상황: │
│ ├── 개발 계정에서 프로덕션 S3 데이터 읽기 │
│ ├── 중앙 보안 계정에서 모든 계정의 CloudTrail 수집 │
│ ├── 공유 서비스 계정의 리소스를 여러 계정에서 사용 │
│ ├── 서드파티 SaaS가 고객의 AWS 리소스에 접근 │
│ └── CI/CD 계정에서 프로덕션 배포 │
│ │
└──────────────────────────────────────────────────────────────────────┘
10.2 Role-based 방식 (AssumeRole)
┌──────────────────────────────────────────────────────────────────────┐
│ 교차 계정 AssumeRole 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 계정 A (111111111111) 계정 B (222222222222) │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ │ │ │ │
│ │ IAM User/Role │ │ IAM Role │ │
│ │ (호출자) │ │ (CrossAccountRole) │ │
│ │ │ │ │ │
│ │ Permission Policy: │ │ Trust Policy: │ │
│ │ sts:AssumeRole │──────▶│ 계정 A 허용 │ │
│ │ Resource: 계정B Role│ │ │ │
│ │ │ │ Permission Policy: │ │
│ └─────────────────────┘ │ S3 읽기 권한 │ │
│ │ │ │
│ └─────────────────────┘ │
│ │
│ 단계: │
│ 1. 계정 B에서 Role 생성 + Trust Policy에 계정 A 허용 │
│ 2. 계정 A의 User/Role에 sts:AssumeRole 권한 부여 │
│ 3. 계정 A에서 sts:AssumeRole 호출 → 계정 B의 임시 자격증명 획득 │
│ 4. 임시 자격증명으로 계정 B의 리소스 접근 │
│ │
└──────────────────────────────────────────────────────────────────────┘
Java 예시:
// 계정 A에서 계정 B의 Role 맡기
StsClient stsClient = StsClient.create();
AssumeRoleResponse response = stsClient.assumeRole(
AssumeRoleRequest.builder()
.roleArn("arn:aws:iam::222222222222:role/CrossAccountRole")
.roleSessionName("cross-account-session")
.build()
);
// 계정 B의 임시 자격증명으로 S3 클라이언트 생성
Credentials tempCreds = response.credentials();
S3Client s3AccountB = S3Client.builder()
.credentialsProvider(StaticCredentialsProvider.create(
AwsSessionCredentials.create(
tempCreds.accessKeyId(),
tempCreds.secretAccessKey(),
tempCreds.sessionToken()
)
))
.build();
10.3 Resource-based 방식
┌──────────────────────────────────────────────────────────────────────┐
│ Resource-based 교차 계정 접근 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 계정 A (111111111111) 계정 B (222222222222) │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ │ │ S3 Bucket │ │
│ │ IAM User/Role │ │ │ │
│ │ │──────▶│ Bucket Policy: │ │
│ │ (AssumeRole 불필요)│ │ 계정 A의 Principal │ │
│ │ │ │ 허용 │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
│ 특징: │
│ ├── AssumeRole 불필요 → 호출자가 자신의 자격증명 그대로 사용 │
│ ├── 호출자의 원래 권한 + 리소스 정책 권한 합집합 │
│ ├── S3, SQS, SNS, Lambda, KMS 등 Resource Policy 지원 서비스만 │
│ └── Role 전환이 없으므로 CloudTrail에 원래 신원이 기록 │
│ │
└──────────────────────────────────────────────────────────────────────┘
| 항목 | Role-based (AssumeRole) | Resource-based (Bucket Policy 등) |
|---|---|---|
| 메커니즘 | STS AssumeRole | 리소스에 직접 Policy 부착 |
| 자격증명 | 대상 계정의 임시 자격증명 | 호출자 자신의 자격증명 |
| 권한 범위 | 대상 Role의 권한 | 호출자 권한 + 리소스 정책 합집합 |
| 지원 서비스 | 모든 서비스 | Resource Policy 지원 서비스만 |
| CloudTrail 기록 | 대상 계정의 Role 세션 | 호출자 원래 신원 |
| 유연성 | 높음 (어떤 서비스든) | 제한적 (일부 서비스만) |
10.4 External ID — Confused Deputy 방지
┌──────────────────────────────────────────────────────────────────────┐
│ Confused Deputy Problem (혼동된 대리인 문제) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 시나리오: │
│ │
│ 고객 A SaaS 서비스 고객 A의 AWS 계정 │
│ ┌──────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ │───▶│ │────────▶│ Role: SaaSAccess │ │
│ │ │ │ (계정X) │ │ Trust: 계정X 허용│ │
│ └──────┘ └──────────┘ └──────────────────┘ │
│ │ │
│ 악의적 사용자 B │ │
│ ┌──────┐ │ │
│ │ │────────▶│ "나도 고객이니 고객 A 계정의 │
│ │ │ │ Role을 맡아줘" (속임) │
│ └──────┘ │ │
│ ▼ │
│ SaaS가 속아서 고객 A의 Role을 맡음 → 고객 A 데이터 유출! │
│ │
│ 해결: External ID │
│ ├── 고객 A가 Role Trust Policy에 ExternalId 조건 추가 │
│ ├── SaaS에 고객별 고유 ExternalId 발급 │
│ ├── AssumeRole 시 ExternalId 매칭 필수 │
│ └── 악의적 사용자 B는 고객 A의 ExternalId를 모름 → 접근 불가 │
│ │
└──────────────────────────────────────────────────────────────────────┘
Trust Policy에 External ID 추가:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::999999999999:root"
},
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": {
"sts:ExternalId": "customer-a-unique-id-12345"
}
}
}
]
}
AssumeRole 호출 시:
stsClient.assumeRole(AssumeRoleRequest.builder()
.roleArn("arn:aws:iam::111111111111:role/SaaSAccess")
.roleSessionName("saas-session")
.externalId("customer-a-unique-id-12345") // 필수
.build());
11. 고급 보안 개념
11.1 Permission Boundary (권한 경계)
Permission Boundary = 권한 경계. IAM User 또는 Role이 가질 수 있는 최대 권한을 제한하는 관리형 정책.
┌──────────────────────────────────────────────────────────────────────┐
│ Permission Boundary (권한 경계) 개념 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 목적: 위임된 관리자가 부여할 수 있는 권한의 상한선을 설정 │
│ │
│ 원리: │
│ ┌─────────────────────────────────────────────┐ │
│ │ │ │
│ │ Identity Policy Permission │ │
│ │ (부여된 권한) Boundary │ │
│ │ ┌──────────────┐ ┌──────────────┐ │ │
│ │ │ S3 │ │ S3 │ │ │
│ │ │ DynamoDB │ │ Lambda │ │ │
│ │ │ Lambda ─────┼───┼─ Lambda │ │ │
│ │ │ EC2 │ │ CloudWatch │ │ │
│ │ └──────────────┘ └──────────────┘ │ │
│ │ │ │
│ │ 실제 유효 권한 = 교집합 = Lambda만 │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ 사용 사례: │
│ ├── 팀 리더에게 IAM User 생성 권한을 주되, 그 User의 최대 권한 │
│ │ 을 S3/Lambda로 제한 │
│ ├── 개발자가 자체 Role 생성 시 과도한 권한 방지 │
│ └── "내가 만든 사용자도 나보다 높은 권한을 가질 수 없다" │
│ │
└──────────────────────────────────────────────────────────────────────┘
11.2 Session Policy (세션 정책)
┌──────────────────────────────────────────────────────────────────────┐
│ Session Policy (세션 정책) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 정의: AssumeRole 시 인라인으로 전달하는 추가 정책 │
│ Role의 권한을 동적으로 축소할 때 사용 │
│ │
│ 원리: │
│ ├── Role Permission Policy ∩ Session Policy = 유효 권한 │
│ ├── Session Policy는 권한을 확대할 수 없음 (축소만 가능) │
│ └── GetFederationToken, AssumeRole 등에서 사용 │
│ │
│ 사용 사례: │
│ ├── 멀티 테넌트: 같은 Role이지만 테넌트마다 S3 접두어 제한 │
│ └── 임시 권한 축소: 특정 작업에만 필요한 권한만 부여 │
│ │
└──────────────────────────────────────────────────────────────────────┘
// Session Policy로 S3 특정 접두어만 접근 허용
String sessionPolicy = """
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/tenant-a/*"
}]
}
""";
stsClient.assumeRole(AssumeRoleRequest.builder()
.roleArn("arn:aws:iam::123456789012:role/SharedRole")
.roleSessionName("tenant-a-session")
.policy(sessionPolicy)
.build());
11.3 Service-Linked Role (서비스 연결 역할)
┌──────────────────────────────────────────────────────────────────────┐
│ Service-Linked Role (서비스 연결 역할) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 정의: AWS 서비스가 자동으로 생성하고 관리하는 특수 IAM Role │
│ │
│ 특징: │
│ ├── 이름 형식: AWSServiceRoleFor{ServiceName} │
│ │ 예: AWSServiceRoleForElasticLoadBalancing │
│ ├── Trust Policy가 해당 AWS 서비스만 허용 │
│ ├── Permission Policy는 AWS가 정의 (사용자 수정 불가) │
│ ├── 서비스 활성화 시 자동 생성 │
│ └── 삭제하면 서비스 기능에 영향 │
│ │
│ 사용 서비스 예시: │
│ ├── ELB (Elastic Load Balancing = 탄력적 부하 분산) │
│ ├── RDS (Relational Database Service = 관계형 데이터베이스 서비스) │
│ ├── Auto Scaling │
│ └── Organizations │
│ │
└──────────────────────────────────────────────────────────────────────┘
11.4 IAM Roles Anywhere (2022)
┌──────────────────────────────────────────────────────────────────────┐
│ IAM Roles Anywhere (2022 출시) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 목적: 온프레미스 서버에서도 IAM Role 사용 가능 │
│ → 장기 Access Key 제거 │
│ │
│ 원리: X.509 인증서 기반 인증 │
│ │
│ ┌───────────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ 온프레미스 서버│ │ IAM Roles │ │ AWS 서비스 │ │
│ │ │────▶│ Anywhere │────▶│ (S3, DDB 등) │ │
│ │ X.509 인증서 │ │ Trust Anchor │ │ │ │
│ │ 보유 │ │ Profile → Role │ │ │ │
│ └───────────────┘ └──────────────────┘ └──────────────┘ │
│ │
│ 구성 요소: │
│ ├── Trust Anchor: 신뢰할 CA (Certificate Authority) 등록 │
│ │ └── AWS Private CA 또는 자체 CA │
│ ├── Profile: Role 매핑 규칙 + 세션 기간 설정 │
│ └── X.509 인증서: 서버에 설치된 인증서 │
│ │
│ 장점: │
│ ├── 장기 Access Key 제거 → 유출 위험 감소 │
│ ├── 인증서 자동 갱신 가능 (ACME 프로토콜 등) │
│ ├── CloudTrail에 인증서 주체 기록 │
│ └── 기존 PKI 인프라 재활용 │
│ │
│ CLI 도구: aws_signing_helper │
│ └── credential_process로 ~/.aws/config에 연동 │
│ │
└──────────────────────────────────────────────────────────────────────┘
~/.aws/config 설정 예시:
[profile roles-anywhere]
credential_process = aws_signing_helper credential-process \
--certificate /path/to/cert.pem \
--private-key /path/to/key.pem \
--trust-anchor-arn arn:aws:rolesanywhere:ap-northeast-2:123456789012:trust-anchor/abc123 \
--profile-arn arn:aws:rolesanywhere:ap-northeast-2:123456789012:profile/def456 \
--role-arn arn:aws:iam::123456789012:role/OnPremRole
11.5 MFA with STS
MFA = Multi-Factor Authentication (다중 인증). 비밀번호(지식 요소) 외에 추가 요소(소유 요소: OTP 장치, 생체 요소: 지문 등)로 인증을 강화.
┌──────────────────────────────────────────────────────────────────────┐
│ MFA + STS 연계 흐름 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ MFA 종류: │
│ ├── 가상 MFA (Virtual MFA): Google Authenticator, Authy 등 앱 │
│ ├── 하드웨어 MFA: YubiKey, Gemalto 토큰 │
│ ├── SMS MFA: 문자 메시지 (보안 약함, 비권장) │
│ └── FIDO2 보안 키: WebAuthn 기반 (가장 안전) │
│ │
│ MFA 필수 정책 예시 (특정 작업에 MFA 요구): │
│ │
│ { │
│ "Effect": "Deny", │
│ "Action": ["ec2:StopInstances", "ec2:TerminateInstances"], │
│ "Resource": "*", │
│ "Condition": { │
│ "BoolIfExists": { │
│ "aws:MultiFactorAuthPresent": "false" │
│ } │
│ } │
│ } │
│ │
│ CLI에서 MFA 사용: │
│ 1. GetSessionToken + MFA 코드로 임시 자격증명 획득 │
│ 2. 그 임시 자격증명으로 MFA 필수 작업 수행 │
│ │
│ aws sts get-session-token \ │
│ --serial-number arn:aws:iam::123456789012:mfa/user1 \ │
│ --token-code 123456 │
│ │
└──────────────────────────────────────────────────────────────────────┘
12. 자격증명 방식 선택 가이드 (의사결정 트리)
┌──────────────────────────────────────────────────────────────────────┐
│ 자격증명 방식 의사결정 트리 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 어디서 실행되는가? │
│ │ │
│ ├── EC2 인스턴스 │
│ │ └── Instance Profile (IAM Role 연결) │
│ │ └── IMDS에서 자동 자격증명 획득 │
│ │ └── ★ DefaultCredentialsProvider 자동 탐색 │
│ │ │
│ ├── ECS (Elastic Container Service) / Fargate │
│ │ └── Task Role (taskRoleArn 설정) │
│ │ └── Container Credentials Endpoint 자동 │
│ │ └── ★ DefaultCredentialsProvider 자동 탐색 │
│ │ │
│ ├── EKS (Elastic Kubernetes Service) │
│ │ ├── 신규 프로젝트 → EKS Pod Identity (2023+) │
│ │ │ └── Pod Identity Association 생성 │
│ │ │ └── ★ DefaultCredentialsProvider 자동 탐색 │
│ │ └── 기존 프로젝트 → IRSA │
│ │ └── ServiceAccount + OIDC Provider │
│ │ └── ★ DefaultCredentialsProvider 자동 탐색 │
│ │ │
│ ├── Lambda │
│ │ └── 실행 역할 (Execution Role) 자동 연결 │
│ │ └── 환경변수로 자격증명 자동 주입 │
│ │ └── ★ DefaultCredentialsProvider 자동 탐색 │
│ │ │
│ ├── 온프레미스 서버 │
│ │ ├── PKI 인프라 있음 → IAM Roles Anywhere (X.509) │
│ │ └── PKI 없음 → IAM User Access Key (최후 수단) │
│ │ └── 주기적 키 로테이션 필수 (90일 권장) │
│ │ │
│ ├── CI/CD 파이프라인 │
│ │ ├── GitHub Actions → OIDC Federation (Access Key 불필요) │
│ │ ├── GitLab CI → OIDC Federation 지원 │
│ │ └── Jenkins → IAM User Key 또는 IAM Roles Anywhere │
│ │ │
│ ├── 로컬 개발 환경 │
│ │ ├── IAM Identity Center 사용 가능 → aws configure sso │
│ │ └── 불가능 → ~/.aws/credentials (aws configure) │
│ │ │
│ ├── 모바일/웹 앱 │
│ │ └── Cognito Identity Pool │
│ │ └── 소셜 로그인 → 임시 AWS 자격증명 │
│ │ │
│ └── 교차 계정 접근 │
│ ├── 같은 Organization → IAM Identity Center │
│ └── 다른 Organization → AssumeRole + External ID │
│ │
│ ★ = 코드 변경 없이 DefaultCredentialsProvider가 자동 처리 │
│ │
└──────────────────────────────────────────────────────────────────────┘
13. 보안 베스트 프랙티스
13.1 하지 말 것 (Anti-patterns)
┌──────────────────────────────────────────────────────────────────────┐
│ 하지 말 것 (Anti-patterns) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1. 코드에 Access Key 하드코딩 │
│ └── Git에 커밋되면 수 분 내에 봇이 탐지하여 악용 │
│ └── AWS TruffleHog 같은 도구로 자동 스캔됨 │
│ │
│ 2. Root 계정 Access Key 생성 │
│ └── Root = 모든 권한. 유출 시 전체 계정 탈취 │
│ └── Root Access Key는 삭제하고, IAM User/Role 사용 │
│ │
│ 3. IAM User 공유 (1 User = 여러 사람) │
│ └── CloudTrail에서 누가 했는지 추적 불가 │
│ └── 사람당 별도 IAM User 또는 IAM Identity Center 사용 │
│ │
│ 4. 와일드카드 권한 부여 ("Action": "*", "Resource": "*") │
│ └── 최소 권한 원칙(Principle of Least Privilege) 위반 │
│ └── 필요한 작업과 리소스만 명시 │
│ │
│ 5. MFA 미설정 │
│ └── 특히 Console 접근 + 관리자 권한 User는 MFA 필수 │
│ └── SCP로 조직 전체 MFA 강제 가능 │
│ │
│ 6. Access Key 로테이션 안 함 │
│ └── 장기 Access Key는 90일마다 교체 권장 │
│ └── IAM Access Analyzer로 미사용 키 탐지 │
│ │
│ 7. 로그에 자격증명 출력 │
│ └── logger.info("credentials: " + creds) → 절대 금지 │
│ └── AWS SDK는 toString()에서 자격증명 마스킹 │
│ │
│ 8. IMDSv1 허용 │
│ └── SSRF 공격에 취약 │
│ └── HttpTokens=required로 IMDSv2만 허용 │
│ │
└──────────────────────────────────────────────────────────────────────┘
13.2 해야 할 것 (Best practices)
┌──────────────────────────────────────────────────────────────────────┐
│ 해야 할 것 (Best Practices) │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1. IAM Role 사용 (Access Key 대신) │
│ └── EC2 → Instance Profile │
│ └── ECS → Task Role │
│ └── EKS → Pod Identity 또는 IRSA │
│ └── Lambda → Execution Role │
│ │
│ 2. 최소 권한 원칙 (Least Privilege) │
│ └── 필요한 서비스, 작업, 리소스만 허용 │
│ └── IAM Access Analyzer로 미사용 권한 탐지 │
│ └── 처음에 넓은 권한 → Access Analyzer로 축소 전략 │
│ │
│ 3. 임시 자격증명 사용 (STS) │
│ └── 자동 만료 → 유출 피해 제한 │
│ └── Session Policy로 추가 제한 가능 │
│ │
│ 4. MFA 활성화 │
│ └── 모든 IAM User (특히 Console 접근자) │
│ └── 중요 작업에 MFA 필수 정책 적용 │
│ └── FIDO2 보안 키 권장 (피싱 방어) │
│ │
│ 5. CloudTrail 활성화 │
│ └── 모든 API 호출 기록 │
│ └── S3 버킷에 로그 저장 + 무결성 검증 활성화 │
│ └── 별도 보안 계정에서 중앙 수집 │
│ │
│ 6. IAM Access Analyzer 사용 │
│ └── 외부 접근 가능한 리소스 탐지 │
│ └── 미사용 접근 권한 탐지 │
│ └── 정책 생성 지원 (CloudTrail 기반) │
│ │
│ 7. SCP로 가드레일 설정 │
│ └── 특정 리전 외 서비스 사용 금지 │
│ └── Root 사용자 제한 │
│ └── 특정 서비스 사용 금지 (예: 비용 큰 서비스) │
│ │
│ 8. Permission Boundary 활용 │
│ └── 위임 관리자가 과도한 권한 부여 방지 │
│ └── 개발자 자체 Role 생성 시 상한선 설정 │
│ │
│ 9. 정기적인 자격증명 감사 │
│ └── IAM Credential Report (자격증명 보고서) 생성 │
│ └── 미사용 User/Key 비활성화 │
│ └── 90일 이상 미사용 접근 → 삭제 검토 │
│ │
└──────────────────────────────────────────────────────────────────────┘
13.3 자격증명 유출 대응 플레이북
┌──────────────────────────────────────────────────────────────────────┐
│ 자격증명 유출 대응 플레이북 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 1단계: 즉시 차단 (5분 이내) │
│ ├── IAM User Key 유출 시: │
│ │ ├── IAM Console → 해당 Access Key 비활성화(Deactivate) │
│ │ ├── 바로 삭제하지 말 것 (조사에 필요) │
│ │ └── 새 Access Key 생성 후 애플리케이션 업데이트 │
│ └── 임시 자격증명 유출 시: │
│ ├── 해당 Role의 Session 즉시 취소 │
│ ├── IAM → Role → Revoke Sessions │
│ └── 인라인 정책으로 특정 시간 이전 세션 모두 거부 │
│ │
│ 2단계: 영향 범위 파악 (1시간 이내) │
│ ├── CloudTrail에서 유출된 자격증명의 API 호출 검색 │
│ │ └── 필터: Access Key ID 또는 Session Name │
│ ├── 비정상 활동 확인: │
│ │ ├── 새 IAM User/Role 생성 │
│ │ ├── 새 EC2 인스턴스 (암호화폐 채굴 등) │
│ │ ├── S3 데이터 대량 다운로드 │
│ │ ├── Lambda 함수 생성 (백도어) │
│ │ └── 비정상 리전에서의 활동 │
│ └── AWS GuardDuty 알림 확인 │
│ │
│ 3단계: 복구 (24시간 이내) │
│ ├── 비정상 리소스 삭제 (EC2, Lambda, IAM User 등) │
│ ├── 영향받은 데이터 범위 확인 │
│ ├── 필요 시 규제 기관/고객 통보 (GDPR 등) │
│ └── Access Key 완전 삭제 │
│ │
│ 4단계: 재발 방지 │
│ ├── 원인 분석 (어떻게 유출되었는가?) │
│ ├── git-secrets 또는 pre-commit 훅 설정 │
│ ├── IAM Role로 전환 (Access Key 제거) │
│ ├── AWS Secrets Manager 또는 Parameter Store 사용 │
│ └── GuardDuty + Security Hub 알림 설정 │
│ │
└──────────────────────────────────────────────────────────────────────┘
14. 흔한 트러블슈팅
14.1 ExpiredTokenException
┌──────────────────────────────────────────────────────────────────────┐
│ ExpiredTokenException 해결 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 증상: "The security token included in the request is expired" │
│ │
│ 원인별 해결: │
│ │
│ 원인 1: 장시간 실행 프로세스에서 토큰 만료 │
│ ├── 해결: StsAssumeRoleCredentialsProvider 사용 (자동 갱신) │
│ └── asyncCredentialUpdateEnabled(true) 설정 │
│ │
│ 원인 2: 수동으로 받은 STS 토큰의 만료 │
│ ├── 해결: AssumeRole 재호출하여 새 토큰 발급 │
│ └── 또는 MaxSessionDuration 연장 │
│ │
│ 원인 3: 시스템 시계 오차 │
│ ├── 해결: NTP 동기화 확인 │
│ └── AWS는 5분 이상 시계 오차 시 요청 거부 │
│ │
│ 원인 4: Role Chaining (최대 1시간 제한) │
│ ├── 해결: 중간 Role 건너뛰고 직접 AssumeRole │
│ └── 또는 직접 대상 Role의 Trust Policy 수정 │
│ │
└──────────────────────────────────────────────────────────────────────┘
14.2 Access Denied 디버깅
┌──────────────────────────────────────────────────────────────────────┐
│ Access Denied 디버깅 가이드 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 증상: "User: arn:aws:... is not authorized to perform: ..." │
│ │
│ 디버깅 순서: │
│ │
│ 1단계: 누구로 인증되었는지 확인 │
│ aws sts get-caller-identity │
│ └── 예상한 User/Role인지 확인 │
│ └── 의도치 않게 다른 자격증명 사용 중일 수 있음 │
│ │
│ 2단계: 명시적 Deny 확인 │
│ └── SCP에 Deny가 있는가? │
│ └── Permission Boundary에 해당 Action이 없는가? │
│ └── Resource Policy에 Deny가 있는가? │
│ │
│ 3단계: Allow 확인 │
│ └── Identity Policy에 해당 Action + Resource Allow가 있는가? │
│ └── Resource Policy에 Allow가 있는가? │
│ └── 와일드카드(*) 범위 확인 │
│ │
│ 4단계: 조건(Condition) 확인 │
│ └── IP 제한, VPC 제한, MFA 요구 등 │
│ └── 태그 조건, 시간 조건 등 │
│ │
│ 유용한 도구: │
│ ├── IAM Policy Simulator (Console) │
│ ├── IAM Access Analyzer │
│ ├── CloudTrail Event History │
│ └── aws iam simulate-principal-policy (CLI) │
│ │
└──────────────────────────────────────────────────────────────────────┘
14.3 AssumeRole 실패
┌──────────────────────────────────────────────────────────────────────┐
│ AssumeRole 실패 디버깅 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 오류: "is not authorized to perform: sts:AssumeRole" │
│ │
│ 체크 포인트: │
│ │
│ 1. 호출자에게 sts:AssumeRole 권한이 있는가? │
│ └── Identity Policy에 해당 Role ARN에 대한 권한 확인 │
│ │
│ 2. 대상 Role의 Trust Policy가 호출자를 허용하는가? │
│ └── Principal에 호출자의 ARN 또는 계정 포함 확인 │
│ └── Action에 sts:AssumeRole 포함 확인 │
│ │
│ 3. 교차 계정 시 양쪽 모두 설정되었는가? │
│ └── 호출자 계정: sts:AssumeRole 허용 │
│ └── 대상 계정: Trust Policy에 호출자 허용 │
│ │
│ 4. ExternalId 불일치 │
│ └── Trust Policy에 Condition으로 ExternalId 요구 시 │
│ └── AssumeRole 호출에 동일한 ExternalId 전달 필요 │
│ │
│ 5. SCP가 sts:AssumeRole을 차단하는가? │
│ └── Organizations의 SCP 확인 │
│ │
│ 6. Session Policy의 크기 제한 초과 │
│ └── 인라인 Session Policy: 최대 2,048자 │
│ └── Managed Session Policy: 최대 10개 │
│ │
└──────────────────────────────────────────────────────────────────────┘
14.4 IRSA 설정 오류
┌──────────────────────────────────────────────────────────────────────┐
│ IRSA 설정 오류 디버깅 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 증상: Pod에서 AWS API 호출 시 Access Denied 또는 기본 Node Role │
│ 사용 (IRSA가 무시됨) │
│ │
│ 체크 1: ServiceAccount annotation 확인 │
│ kubectl get sa my-app -n production -o yaml │
│ └── eks.amazonaws.com/role-arn 값이 올바른 Role ARN인지 │
│ │
│ 체크 2: Pod의 환경변수 확인 │
│ kubectl exec -it <pod> -- env | grep AWS │
│ └── AWS_ROLE_ARN 이 설정되어 있는지 │
│ └── AWS_WEB_IDENTITY_TOKEN_FILE 이 설정되어 있는지 │
│ └── 없으면 Mutating Webhook이 동작하지 않은 것 │
│ │
│ 체크 3: OIDC Provider 설정 확인 │
│ aws eks describe-cluster --name my-cluster │
│ └── identity.oidc.issuer 값 확인 │
│ aws iam list-open-id-connect-providers │
│ └── 위 issuer와 매칭되는 Provider가 존재하는지 │
│ │
│ 체크 4: Trust Policy 조건 확인 │
│ └── OIDC Provider ARN이 정확한지 │
│ └── :sub 조건의 namespace:serviceaccount 이 맞는지 │
│ └── :aud 조건이 sts.amazonaws.com 인지 │
│ │
│ 체크 5: 토큰 파일 존재 확인 │
│ kubectl exec -it <pod> -- \ │
│ cat /var/run/secrets/eks.amazonaws.com/serviceaccount/token │
│ └── JWT 토큰이 존재하고 비어있지 않은지 │
│ │
│ 체크 6: Pod가 올바른 ServiceAccount를 사용하는지 │
│ └── Pod spec의 serviceAccountName 확인 │
│ └── 기본 'default' SA에는 annotation이 없음 │
│ │
└──────────────────────────────────────────────────────────────────────┘
14.5 IMDS 접근 불가
┌──────────────────────────────────────────────────────────────────────┐
│ IMDS 접근 불가 디버깅 │
├──────────────────────────────────────────────────────────────────────┤
│ │
│ 증상: EC2에서 "Unable to load credentials from IMDS" │
│ 또는 169.254.169.254 연결 시간 초과 │
│ │
│ 체크 1: Instance Profile이 연결되어 있는가? │
│ aws ec2 describe-instances --instance-ids i-xxxx \ │
│ --query 'Reservations[].Instances[].IamInstanceProfile' │
│ └── null이면 Instance Profile 미연결 │
│ │
│ 체크 2: IMDSv2 only 설정에서 v1으로 접근하는가? │
│ aws ec2 describe-instances --instance-ids i-xxxx \ │
│ --query '...MetadataOptions' │
│ └── HttpTokens: "required"이면 IMDSv2만 허용 │
│ └── SDK 버전이 IMDSv2를 지원하는지 확인 │
│ │
│ 체크 3: IMDS가 비활성화되어 있는가? │
│ └── HttpEndpoint: "disabled"이면 IMDS 자체가 꺼져 있음 │
│ │
│ 체크 4: 홉 제한 (HttpPutResponseHopLimit) │
│ └── 컨테이너에서 IMDS 접근 시 hop limit이 1이면 도달 불가 │
│ └── Docker/컨테이너 환경에서는 hop limit을 2로 설정 필요 │
│ │
│ 체크 5: 네트워크/방화벽 설정 │
│ └── 169.254.169.254에 대한 iptables/nftables 규칙 확인 │
│ └── 일부 보안 도구가 링크 로컬 주소 차단할 수 있음 │
│ │
│ 체크 6: SDK 타임아웃 │
│ └── EC2가 아닌 환경(로컬 등)에서 IMDS 탐색 시 타임아웃 발생 │
│ └── AWS_EC2_METADATA_DISABLED=true 환경변수로 비활성화 │
│ │
└──────────────────────────────────────────────────────────────────────┘
관련 키워드
IAM, STS, IRSA, OIDC, SAML, MFA, ARN, ABAC, RBAC, SSO, EKS, ECS, EC2, ACL, JWT, IdP, ECR, SCP, RCP, IMDS, IMDSv2, Instance Profile, Task Role, Task Execution Role, Pod Identity, DefaultCredentialsProvider, AwsCredentialsProvider, CustomCredentialProvider, AssumeRole, AssumeRoleWithWebIdentity, AssumeRoleWithSAML, GetSessionToken, GetFederationToken, GetCallerIdentity, Trust Policy, Permission Policy, Identity-based Policy, Resource-based Policy, Permission Boundary, Session Policy, Service-Linked Role, IAM Roles Anywhere, IAM Identity Center, Cognito Identity Pool, Cognito User Pool, Cross-Account Access, External ID, Confused Deputy, Credential Chain, Access Key, Secret Access Key, Session Token, ExpiredTokenException, Least Privilege, CloudTrail, GuardDuty, IAM Access Analyzer, X.509, FIDO2, WebAuthn, Projected Service Account Token, Mutating Webhook, Pod Identity Agent, StsAssumeRoleCredentialsProvider, credential_process