Cert Notes/ 출퇴근 학습 노트
로드맵
KOEN
CLF-C02 · FoundationalCloud Practitioner - Foundational
DVA-C02 · AssociateDeveloper - Associate
SAA-C03 · AssociateSolutions Architect - Associate
SOA-C02 · AssociateCloudOps Engineer - Associate
SAP-C02 · ProfessionalSolutions Architect - Professional
DOP-C02 · ProfessionalDevOps Engineer - Professional
SCS-C03 · SpecialtySecurity - Specialty
  • Week 1
    • 1.공동 책임 모델과 SCS-C03 6개 도메인: 보안 엔지니어의 큰 그림
    • 2.IAM 핵심: 사용자·그룹·역할·정책과 정책 평가의 기본 흐름
    • 3.IAM 정책 심화: Identity vs Resource 정책, 조건 키, 최소 권한 설계
    • 4.STS와 임시 자격 증명: AssumeRole, 페더레이션, 역할 체이닝, Confused Deputy 방지
    • 5.Week 1 종합: IAM과 자격 증명을 시나리오로 통합 복습
  • Week 2
    • 1.정책 평가 로직 완전 정복: Explicit Deny가 모든 것을 이긴다
    • 2.권한 경계와 위임: 개발자에게 안전하게 권한을 넘기는 기술
    • 3.AWS Organizations와 SCP: 계정 단위 가드레일 설계
    • 4.IAM Identity Center와 페더레이션: SAML, OIDC, 그리고 ABAC
    • 5.Week 2 종합: 멀티계정 IAM 거버넌스 시나리오 통합
  • Week 3
    • 1.VPC 보안 설계: 네트워크가 첫 번째 방어선이다
    • 2.보안 그룹 vs 네트워크 ACL: 상태 저장과 비저장의 본질
    • 3.VPC Flow Logs와 트래픽 가시성: 로그로 침해를 읽는다
    • 4.프라이빗 연결: VPC 엔드포인트와 데이터 유출 봉쇄
    • 5.Week 3 종합: 네트워크 격리와 트래픽 통제를 하나로
  • Week 4
    • 1.AWS WAF: 웹 ACL, 규칙·규칙 그룹, 속도 기반 규칙, SQLi/XSS 방어
    • 2.AWS Shield(Standard/Advanced)와 DDoS 방어: 계층별 방어, CloudFront/Route 53 결합
    • 3.AWS Network Firewall와 DNS Firewall: 상태 저장 검사, 도메인 필터링, 중앙 집중식 검사 VPC
    • 4.엣지 보안 통합: CloudFront(OAC, 서명 URL), ACM 인증서, 경계 보안 아키텍처
    • 5.Week 4 종합: 엣지·경계 방어 시나리오 통합 복습
  • Week 5
    • 1.AWS KMS 기초: CMK 종류, 키 정책 vs IAM, 대칭/비대칭 키
    • 2.엔벨로프 암호화와 데이터 키: GenerateDataKey, 암호화 컨텍스트
    • 3.키 정책·그랜트·교차계정 공유: ViaService 조건과 키 거버넌스
    • 4.전송 중/저장 암호화: TLS, 서비스별 저장 암호화, 키 회전
    • 5.Week 5 종합: 암호화·키 관리 시나리오 통합 복습
  • Week 6
    • 1.Secrets Manager: 자동 회전(Lambda), Parameter Store 비교, 교차계정 시크릿
    • 2.S3 데이터 보호: SSE-S3/SSE-KMS/DSSE, 버킷 키, 객체 잠금, 버전관리, 퍼블릭 액세스 차단
    • 3.S3 접근 통제 심화: 버킷 정책·ACL·Access Points, 암호화 강제, 데이터 유출 방지
    • 4.ACM과 Macie: 인증서 수명주기·통합, Macie 민감정보(PII) 탐지·분류
    • 5.Week 6 종합: 시크릿·스토리지·민감데이터 시나리오 통합 복습
  • Week 7
    • 1.CloudTrail: 관리/데이터 이벤트, 조직 트레일, 로그 파일 무결성 검증, CloudTrail Lake
    • 2.AWS Config: 구성 항목·기록, 규칙(관리형/커스텀 Lambda), Conformance Pack, 자동 교정
    • 3.VPC Flow Logs와 네트워크 로깅: 트래픽으로 침해·오구성 탐지, Route 53 Resolver 쿼리 로그
    • 4.로그 무결성·보존·중앙화: S3 Object Lock, 교차 계정 로그 집계, KMS 암호화 로그
    • 5.Week 7 종합: 감사·구성 추적 시나리오 통합 복습
  • Week 8
    • 1.CloudWatch: 로그 그룹·지표 필터·알람, 비정상 탐지, 보안 이벤트 알림
    • 2.Security Hub: 보안 표준(CIS/FSBP), 통합 점수, 핀딩 집계·정규화(ASFF), 자동 대응
    • 3.로그 분석: Athena로 CloudTrail/VPC Flow 쿼리, OpenSearch, CloudWatch Logs Insights
    • 4.EventBridge 보안 자동화: 핀딩 라우팅, 알림 파이프라인, 보안 데이터 레이크 개념
    • 5.Week 8 종합: 모니터링·집계·분석 시나리오 통합 복습
  • Week 9
    • 1.Amazon GuardDuty: 위협 탐지 원리, 핀딩 유형, 위협 인텔, 멀티계정 위임 관리자
    • 2.Amazon Detective: 핀딩 조사·근본원인, 동작 그래프, GuardDuty 연계
    • 3.Amazon Inspector: EC2/ECR/Lambda 취약점 스캔, CVE, 자동 평가
    • 4.탐지 통합: GuardDuty + Security Hub + Detective + Inspector 한 그림, 멀티계정 탐지 베이스라인
    • 5.Week 9 종합: 위협 탐지 시나리오 통합 복습
  • Week 10
    • 1.자동 대응 파이프라인: EventBridge + SSM Automation + Lambda로 핀딩 자동 교정
    • 2.침해 인스턴스 대응: 격리, 스냅샷·포렌식 보존, 자격증명 회수
    • 3.자격증명 유출 대응: 액세스 키 노출, 루트 침해, IAM 무력화·회전 플레이북
    • 4.인시던트 대응 프레임워크: NIST 단계, 런북, 자동화 vs 사람 판단의 경계
    • 5.Week 10 종합: 인시던트 대응 시나리오 통합 복습
  • Week 11
    • 1.AWS Organizations 보안 거버넌스: SCP 설계, 위임 관리자, 중앙 보안 계정 모델
    • 2.Control Tower와 랜딩 존: 가드레일(예방/탐지), 계정 팩토리, 규정 준수 베이스라인
    • 3.Audit Manager와 규정 준수: 증거 자동 수집, 프레임워크(CIS/PCI), Config와 연계
    • 4.멀티계정 보안 운영: Firewall Manager, 중앙 정책 배포, 비용·태그 거버넌스, 보안 베이스라인 자동화
    • 5.Week 11 종합: 거버넌스 시나리오 통합 복습
  • Week 12
    • 1.도메인 1·2 통합 복습: 위협 탐지·인시던트 대응 ↔ 로깅·모니터링
    • 2.도메인 3·4 통합 복습: 인프라 보안 ↔ 자격 증명·액세스 관리
    • 3.도메인 5·6 통합 복습: 데이터 보호 ↔ 관리·거버넌스
    • 4.전체 모의고사 페이스: 6개 도메인 종합 시나리오 점검
    • 5.D-Day 마무리: 시험장 전략 · 키워드→서비스 번역 · 함정 총정리
MLA-C01 · AssociateMachine Learning Engineer - Associate
AIF-C01 · FoundationalAI Practitioner - Foundational
DEA-C01 · AssociateData Engineer - Associate
MLS-C01 · SpecialtyMachine Learning - Specialty
합격 후기
← SCS-C03/Week 1/Day 4
SCS-C03· AssociateWeek 1 · Day 4읽기 약 22분

Day 4 - STS와 임시 자격 증명: AssumeRole, 페더레이션, 역할 체이닝, Confused Deputy 방지

지난 사흘 동안 "장기 자격 증명(IAM User access key)을 쓰지 말고 Role을 쓰라"는 말을 반복했다. 오늘은 그 Role이 실제로 어떻게 "맡아지는지", 그 메커니즘인 STS(Security Token Service)가 무엇을 발급하고, 외부 신원(페더레이션)이 어떻게 AWS 자격 증명으로 교환되는지를 판다. SCS-C03의 도메인 4에서 가장 깊은 변별력이 여기 있다 — AssumeRole의 trust 관계, 역할 체이닝의 제약, 그리고 cross-account 위임에서 반드시 막아야 하는 Confused Deputy 공격이다.

핵심 한 문장을 먼저: STS는 만료되는 임시 자격 증명(AccessKeyId + SecretAccessKey + SessionToken)을 발급하고, "누가 이 역할을 맡을 수 있나"는 역할의 trust policy가 결정한다.

STS가 발급하는 것: 임시 자격 증명 3종

장기 IAM User 자격 증명은 키 2개(AccessKeyId, SecretAccessKey)지만, STS 임시 자격 증명은 3개다.

구성역할
AccessKeyId식별자
SecretAccessKey서명 키
SessionToken임시 세션 증명(장기 키엔 없음)

이 자격 증명에는 만료 시간이 있다. AssumeRole은 기본 1시간, 최대 12시간(역할의 MaxSessionDuration 범위 내). 만료되면 다시 발급받아야 한다. 노출돼도 시간적으로 피해가 제한되는 것이 장기 키보다 근본적으로 안전한 이유다.

주요 STS API:

API용도
AssumeRole같은/다른 계정의 IAM Role 맡기 (가장 일반적)
AssumeRoleWithSAMLSAML 2.0 IdP(예: AD FS, Okta) 페더레이션
AssumeRoleWithWebIdentityOIDC(예: Cognito, Google, GitHub Actions) 페더레이션
GetSessionTokenMFA 적용된 임시 자격 증명(IAM User용)
GetFederationToken레거시 페더레이션

각 API를 언제 쓰는지가 시험 포인트다. "누가 호출하는가"와 "무엇을 증거로 제시하는가"로 구분하면 헷갈리지 않는다.

API호출하는 쪽제시하는 증거결과 신원대표 상황
AssumeRoleAWS 자격 증명을 이미 가진 주체자기 AWS 서명대상 역할교차 계정 접근, EC2·Lambda 실행 역할
AssumeRoleWithSAML기업 IdP를 거친 사용자SAML assertion대상 역할AD FS·Okta 기반 워크포스 로그인
AssumeRoleWithWebIdentityOIDC 토큰을 가진 주체OIDC ID 토큰대상 역할GitHub Actions, EKS 파드, 모바일 앱
GetSessionTokenIAM 사용자 본인자기 키 (+ MFA 코드)같은 사용자MFA를 붙인 세션이 필요할 때
GetFederationTokenIAM 사용자 또는 루트자기 키페더레이션 사용자레거시 — 신규 설계에는 쓰지 않음

⚠️ 함정: GetSessionToken과 AssumeRole을 바꿔 쓰는 실수가 잦다. GetSessionToken은 역할을 바꾸지 않는다 — 같은 IAM 사용자의 신원 그대로, MFA가 반영된 임시 자격 증명을 받을 뿐이다. 그래서 "MFA를 요구하는 정책 조건을 만족시키고 싶다"면 GetSessionToken이고, "다른 권한 집합으로 갈아입고 싶다"면 AssumeRole이다. 또 하나 — GetSessionToken으로 받은 자격 증명으로는 대부분의 IAM·STS 호출이 제한된다는 제약이 있다.

임시 자격 증명이 어디서 오는지를 한 장으로 정리하면 이렇다. 세 경로 모두 끝은 같다.

[ 임시 자격 증명에 도달하는 세 갈래 ]

 ① 워크로드가 자동으로 받는 경로
    EC2 인스턴스 ──▶ IMDS(v2, 토큰 필요) ──▶ 인스턴스 프로파일의 역할
    Lambda 함수  ──▶ 실행 환경 변수      ──▶ 실행 역할
    ECS 태스크   ──▶ 태스크 자격 증명 엔드포인트 ──▶ 태스크 역할
    EKS 파드     ──▶ OIDC 서비스 계정 토큰 ──▶ 역할(IRSA)
                        └─ 공통점: **코드에 키가 없다**

 ② 사람이 로그인해 받는 경로
    사용자 ──▶ 기업 IdP 로그인 ──▶ SAML/OIDC 증명
           ──▶ IAM Identity Center 또는 STS ──▶ 역할 세션

 ③ 이미 가진 AWS 자격 증명으로 갈아입는 경로
    주체 ──▶ sts:AssumeRole ──▶ 다른 역할 세션 (같은 계정 또는 교차 계정)

  ── 세 경로의 산출물은 동일하다 ────────────────────────
     AccessKeyId(ASIA...) + SecretAccessKey + SessionToken + Expiration

이 그림에서 읽어야 할 것은 **"장기 키가 등장할 자리가 어디에도 없다"**는 사실이다. 워크로드도, 사람도, 교차 계정도 전부 임시 자격 증명으로 해결된다. 그러므로 시험에서 액세스 키가 등장하는 보기는 거의 항상 오답 후보다.

💡 관련 이론: EC2 인스턴스 프로파일, Lambda 실행 역할, ECS task role도 내부적으로 전부 STS AssumeRole이다. EC2의 경우 인스턴스 메타데이터 서비스(IMDS)가 임시 자격 증명을 자동 발급·갱신한다. 그래서 코드에 키를 넣을 필요가 없다. **IMDSv2(토큰 기반)**를 강제해야 SSRF로 메타데이터를 훔치는 공격(Capital One 사고의 핵심 벡터)을 막는다 — 시험 단골이다.

AssumeRole: trust policy와 permission policy의 두 축

Role은 두 개의 정책을 가진다. 이 구분이 IAM에서 가장 헷갈리는 지점이다.

  • Trust policy(신뢰 정책): "누가 이 역할을 맡을 수 있나"(sts:AssumeRole 허용 대상). Principal 포함 = 리소스 기반 정책.
  • Permission policy(권한 정책): "이 역할을 맡으면 무엇을 할 수 있나". Identity 기반 정책.
// Trust policy: 계정 111122223333의 주체가 이 역할을 맡을 수 있다
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"AWS": "arn:aws:iam::111122223333:root"},
    "Action": "sts:AssumeRole",
    "Condition": {
      "StringEquals": {"sts:ExternalId": "unique-secret-2026"},
      "Bool": {"aws:MultiFactorAuthPresent": "true"}
    }
  }]
}

cross-account AssumeRole이 성공하려면 양쪽이 맞아야 한다.

  1. 대상 역할의 trust policy가 호출 계정/주체를 Principal로 허용
  2. 호출 측 신원 정책에 sts:AssumeRole Allow(대상 역할 ARN 지정)

이 "양쪽"이 실제로 어떻게 맞물리는지를 순서대로 그리면 다음과 같다. 화살표 하나하나가 실패할 수 있는 지점이고, 시험 문항은 대개 이 중 한 곳이 비어 있는 상황을 준다.

[ 교차 계정 AssumeRole 전 과정 ]

  계정 A (호출자) 111122223333          계정 B (대상) 444455556666
  ┌────────────────────────┐          ┌──────────────────────────────┐
  │ 주체: role/Auditor     │          │ 역할: role/CrossAccountRead  │
  │                        │          │                              │
  │ ① Identity 정책        │          │ ② 신뢰 정책 (리소스 기반)     │
  │   Allow sts:AssumeRole │          │   Principal: 계정 A          │
  │   Resource: B의 역할ARN│          │   Action: sts:AssumeRole     │
  └───────────┬────────────┘          │   Condition: ExternalId, MFA │
              │                       │                              │
              │                       │ ③ 권한 정책                  │
              │  (1) AssumeRole 호출  │   Allow s3:GetObject ...     │
              ├──────────────────────▶└──────────────┬───────────────┘
              │                                      │
              │            (2) STS가 ①과 ②를 모두 검사
              │                · A가 호출할 권한이 있나 (①)
              │                · B가 A를 받아들이나  (②)
              │                · 조건(ExternalId·MFA)이 맞나
              │                       │
              │  (3) 임시 자격 증명 발급 (기본 1시간)
              │◀──────────────────────┘
              │      ASIA... + SessionToken + Expiration
              │
              │  (4) 새 신원으로 B의 리소스 호출
              │      arn:aws:sts::444455556666:assumed-role/CrossAccountRead/audit-2026
              ▼
        ③ 권한 정책의 범위 안에서만 동작

  ── 실패 지점 진단표 ────────────────────────────────────────
  ①이 없다  → 호출 자체가 AccessDenied (계정 A에서 막힘)
  ②가 없다  → "not authorized to perform sts:AssumeRole" (계정 B가 거절)
  조건 불일치 → 같은 메시지가 나오지만 원인은 ExternalId·MFA·IP
  ③이 좁다  → 역할은 맡아지는데 이후 API가 막힌다

마지막 줄의 구분이 실무에서 특히 유용하다. "역할을 맡을 수 없다"와 "맡았는데 아무것도 못 한다"는 완전히 다른 문제다. 전자는 신뢰 정책, 후자는 권한 정책을 봐야 한다. aws sts get-caller-identity가 대상 역할의 ARN을 반환하면 이미 후자 단계에 와 있는 것이다.

신뢰 정책의 Principal은 무엇을 적느냐에 따라 신뢰 범위가 크게 달라진다.

Principal 표기의미신뢰 범위
{"AWS": "arn:aws:iam::111122223333:root"}계정 111122223333 전체그 계정의 IAM 관리자에게 위임 — 넓다
{"AWS": "arn:aws:iam::111122223333:role/Auditor"}특정 역할만좁다 (권장)
{"Service": "ec2.amazonaws.com"}AWS 서비스출처 조건 없으면 위험
{"Federated": "arn:aws:iam::...:oidc-provider/..."}OIDC 공급자sub 조건으로 반드시 좁혀야 함
{"AWS": "*"}모든 AWS 계정조건 없이 쓰면 치명적

⚠️ 함정: {"AWS": "*"}가 든 신뢰 정책이 보기에 있으면 반사적으로 오답으로 걸러야 한다. 조건이 함께 걸려 있더라도 "누구나 시도해 볼 수 있는 역할"을 만드는 셈이라, 조건 하나만 잘못되면 전 세계에 열린다. IAM Access Analyzer가 외부 접근 발견 사항으로 잡아내는 대표 패턴이기도 하다. 신뢰는 가장 좁게 시작해서 필요할 때 넓히는 것이지, 넓게 열고 조건으로 막는 것이 아니다.

⚠️ 함정: trust policy의 Principal에 "arn:aws:iam::111122223333:root"를 쓰면 "계정 111122223333 전체가 맡을 수 있다"는 뜻이지 root 사용자만이 아니다. 단, 실제로는 그 계정 안에서 sts:AssumeRole 권한을 받은 주체만 맡을 수 있다(2번 조건). "root을 Principal로 쓰면 위험"이라는 직관은 절반만 맞다 — 계정 위임은 정상 패턴이지만, 그 계정 내부의 권한 통제는 그 계정에 맡겨진다.

페더레이션: 외부 신원을 AWS 자격 증명으로

IAM User를 만들지 않고 기업 디렉터리(AD)나 소셜/OIDC 신원으로 AWS에 접근하는 것이 페더레이션이다.

SAML 2.0 페더레이션 (기업 워크포스)

[ SAML 페더레이션 흐름 ]

  사용자 → 기업 IdP(AD FS/Okta) 로그인
         → IdP가 SAML assertion 발급(역할 ARN 포함)
         → AWS STS AssumeRoleWithSAML
         → 임시 자격 증명 발급
         → AWS 리소스 접근

조금 더 자세히 그리면, 페더레이션에서 AWS는 사용자를 직접 인증하지 않는다는 점이 드러난다. AWS가 하는 일은 IdP가 서명한 증명을 검증하고 그 안에 적힌 역할로 세션을 발급하는 것뿐이다.

[ SAML / OIDC 페더레이션 — 신뢰가 어디에 있는가 ]

  사용자                기업 IdP              AWS IAM              AWS STS
    │                     │                     │                    │
    │  (1) 로그인·MFA     │                     │                    │
    ├────────────────────▶│                     │                    │
    │                     │                     │                    │
    │  (2) 서명된 증명     │                     │                    │
    │◀────────────────────┤                     │                    │
    │   SAML assertion     │                     │                    │
    │   또는 OIDC 토큰     │                     │                    │
    │   · 누구인가(sub)    │                     │                    │
    │   · 어떤 역할(Role)  │                     │                    │
    │   · 속성(부서·팀)    │                     │                    │
    │                     │                     │                    │
    │  (3) 증명을 제시하며 AssumeRoleWith… 호출                        │
    ├──────────────────────────────────────────────────────────────▶│
    │                     │                     │                    │
    │                     │  (4) IAM에 등록된 IdP로 서명 검증          │
    │                     │◀────────────────────┤                    │
    │                     │   (SAML 메타데이터 / OIDC 지문·발급자)     │
    │                     │                     │                    │
    │                     │  (5) 대상 역할의 신뢰 정책 검사            │
    │                     │      Principal: Federated = 그 IdP        │
    │                     │      Condition: sub · aud · 속성 일치      │
    │                     │                     │                    │
    │  (6) 임시 자격 증명 발급                                         │
    │◀──────────────────────────────────────────────────────────────┤
    │      ASIA... + SessionToken (+ 세션 태그)                       │
    ▼
  AWS 리소스 접근 — CloudTrail에는 assumed-role 세션으로 기록된다

  ── 신뢰의 위치 ────────────────────────────────────────────
  · **인증**의 책임은 IdP에 있다 (비밀번호·MFA·계정 잠금 정책)
  · **인가**의 책임은 AWS에 있다 (어떤 역할, 어떤 권한)
  · 그래서 IdP가 뚫리면 AWS도 뚫린다 — IdP 보안이 AWS 보안의 전제다

마지막 줄이 시험과 실무 양쪽에서 중요하다. 페더레이션을 도입하면 AWS 쪽 자격 증명 관리 부담은 사라지지만, IdP가 새로운 단일 실패 지점이 된다. 그래서 IdP 측 MFA 강제, 관리자 계정 보호, 그리고 AWS 쪽에서 신뢰 정책 조건을 좁히는 작업이 함께 가야 한다.

오늘날 권장 방식은 **IAM Identity Center(구 AWS SSO)**다. 다계정 환경에서 permission set을 정의하고, 외부 IdP(Okta, Entra ID 등)와 연동해 사용자가 한 번 로그인하면 여러 계정·역할에 임시 자격 증명으로 접근한다. IAM User를 계정마다 만드는 안티패턴을 제거한다.

접근 방식신원 저장 위치계정이 40개일 때권장도
계정마다 IAM User각 계정사용자 1명당 40개 계정 = 관리 불가안티패턴
허브 계정 IAM User + 역할 체이닝허브 계정사용자 1명 + 역할 40개개선이나 장기 키 잔존
SAML 직접 페더레이션기업 IdP계정마다 IdP·역할 등록 필요가능하나 설정 부담
IAM Identity Center기업 IdP(또는 자체 디렉터리)permission set을 계정 그룹에 할당표준

🔍 더 깊이: Identity Center가 계정마다 만드는 것도 결국은 역할이다. permission set을 계정에 할당하면 그 계정에 AWSReservedSSO_...로 시작하는 역할이 자동 생성되고, 사용자는 로그인 후 그 역할을 맡는다. 즉 Identity Center는 새로운 인증 메커니즘이 아니라 역할 생성과 신뢰 관계 관리를 자동화한 계층이다. 이 사실을 알면 "Identity Center를 쓰는데 왜 CloudTrail에 assumed-role이 찍히나", "왜 SCP가 여전히 적용되나" 같은 질문이 자연스럽게 풀린다. 아래층은 언제나 IAM이다.

OIDC / Web Identity 페더레이션 (앱·CI/CD)

모바일 앱(Cognito), GitHub Actions, Kubernetes(EKS IRSA) 등은 OIDC로 AssumeRoleWithWebIdentity를 쓴다. 특히 GitHub Actions의 OIDC는 시험과 실무 모두 중요하다 — 장기 access key를 GitHub secret에 넣는 대신, GitHub의 OIDC 토큰으로 역할을 맡아 키 노출 위험을 없앤다.

🔍 더 깊이: GitHub Actions OIDC의 trust policy는 token.actions.githubusercontent.com을 OIDC provider로 두고, Condition에 token.actions.githubusercontent.com:sub로 특정 repo·브랜치만 허용한다. 이 sub 조건을 repo:org/*처럼 느슨하게 두면 조직의 아무 repo나 역할을 맡을 수 있어 위험하다. repo:org/repo:ref:refs/heads/main처럼 좁혀야 한다. EKS의 IRSA도 같은 OIDC 원리로 pod에 역할을 매핑한다.

역할 체이닝(Role Chaining)과 제약

역할을 맡은 상태에서 또 다른 역할을 맡는 것이 역할 체이닝이다. 계정 A → 역할 X 맡기 → 역할 X로 역할 Y 맡기.

핵심 제약 두 가지가 시험에 나온다.

  1. 체이닝 시 최대 세션 시간은 1시간으로 고정된다. 역할 X의 MaxSessionDuration이 12시간이어도, 체이닝으로 받은 세션은 1시간이 상한이다.
  2. 체이닝된 세션으로는 다시 GetSessionToken 같은 일부 호출이 제한된다.
[ 역할 체이닝과 세션 수명 ]

  사람 또는 워크로드
        │
        │ AssumeRole  ──▶ 역할 X 세션
        │                 MaxSessionDuration 12시간 설정
        │                 → 실제로 **최대 12시간** 받을 수 있다  ✅
        │                        │
        │                        │ 이 세션의 자격 증명으로 다시 AssumeRole
        │                        ▼
        │                  역할 Y 세션  ◀── 여기가 "체이닝"
        │                  Y의 MaxSessionDuration 이 12시간이어도
        │                  → **1시간으로 잘린다**  ⚠️
        │                        │
        │                        │ 또 체이닝하면
        │                        ▼
        │                  역할 Z 세션 — 역시 1시간
        ▼

  ── 증상과 진단 ────────────────────────────────────────────
  "장시간 배치가 정확히 1시간마다 죽는다"
     → 거의 확실히 체이닝 경로다. duration-seconds 를 크게 줘도
       ValidationError 가 나거나 조용히 3600으로 잘린다.
  해결
     ① 자격 증명 갱신 로직을 넣는다 (SDK 자격 증명 공급자 사용)
     ② 체이닝을 없앤다 — 최초 신원에서 최종 역할을 **직접** 맡는다
     ③ 정말 다단이 필요하면 각 단계를 짧게 유지하고 재발급을 전제로 설계

체이닝이 만드는 진짜 문제는 시간이 아니라 추적성이다. 여러 역할을 갈아타면 CloudTrail의 각 이벤트는 직전 역할만 기록하므로, "결국 이 작업을 시킨 사람이 누구였나"를 잇는 데 여러 로그를 이어 붙여야 한다. 이 문제를 정면으로 푸는 것이 sts:SourceIdentity다 — 한 번 설정하면 이후 체이닝 전 과정에서 따라붙어 최초 신원을 잃지 않는다. 세션 이름(RoleSessionName)은 호출자가 매번 자유롭게 정할 수 있어 증거로는 약하다는 점과 대비된다.

식별 수단설정 주체체이닝 시 유지증거로서의 강도
RoleSessionName호출하는 코드유지되지 않음(매번 새로 지정)약함 — 자유롭게 바꿀 수 있음
세션 태그(전이 태그)호출하는 코드전이 지정 시 유지중간 — 속성 전달용
sts:SourceIdentity최초 호출 시 1회끝까지 유지, 변경 불가강함 — 감사 추적의 기준

💡 관련 이론: 역할 체이닝은 권한 추적을 흐리게 만들 수 있어 가급적 피한다. 대신 session policy나 직접 AssumeRole이 권장된다. 다만 cross-account에서 "허브 계정의 역할을 거쳐 스포크 계정에 접근"하는 패턴은 정당한 체이닝이다. 추적성은 CloudTrail의 assumedRole 세션 이름으로 보완한다(sts:RoleSessionName을 의미 있게 설정).

Confused Deputy 방지: ExternalId와 aws:SourceArn

오늘의 보안 핵심. **Confused Deputy(혼동된 대리인)**는 권한 있는 주체(대리인)가 속아서 제3자를 위해 권한을 행사하는 공격이다.

시나리오: 서드파티 SaaS의 cross-account 접근

모니터링 SaaS가 당신의 계정에 AssumeRole로 접근한다고 하자. SaaS는 모든 고객에 대해 같은 SaaS 계정으로 역할을 맡는다. 만약 trust policy가 "SaaS 계정이면 허용"만 검사하면, 악의적 사용자가 SaaS에게 "내 역할은 저 ARN이다"라고 남의 역할 ARN을 등록해 SaaS가 대신 그 역할을 맡게 만들 수 있다.

이 구도가 왜 위험한지는 3자 그림으로 봐야 이해된다. 공격의 주체는 SaaS가 아니라 SaaS를 속이는 제3자이고, SaaS는 "혼동된 대리인"으로서 자기 권한을 남을 위해 행사하게 된다.

[ Confused Deputy — 3자 구도 ]

 ── 방어 없는 상태 ────────────────────────────────────────────────────

   ① 정상 고객 (계정 111122223333)
      "우리 계정의 role/MonitorRole 을 모니터링해 주세요"
                    │  역할 ARN 등록
                    ▼
              ┌───────────────────────────────┐
              │  SaaS 벤더 (계정 999988887777) │  ◀── 이 쪽이 "대리인(deputy)"
              │  모든 고객에 대해              │
              │  같은 계정으로 AssumeRole 한다 │
              └───────────────┬───────────────┘
                    ▲         │
     ② 공격자        │         │ AssumeRole(등록된 ARN)
       "우리 계정의  │         ▼
        역할은 이거" │   ┌──────────────────────────────────┐
        ← 남의 역할  │   │ AWS STS                          │
          ARN을 등록 │   │ 신뢰 정책 검사:                   │
                    │   │  "Principal 이 SaaS 계정인가?" ✅ │
                    │   │  → 통과 (다른 검사 없음)          │
                    │   └───────────────┬──────────────────┘
                    │                   │ 임시 자격 증명 발급
                    │                   ▼
                    │        ┌───────────────────────────┐
                    └────────│ 피해자 계정의 리소스        │
                  데이터 유출 │ role/MonitorRole 권한으로   │
                             │ S3·로그·지표에 접근         │
                             └───────────────────────────┘

     ▲ 공격자는 AWS를 뚫지 않았다. SaaS의 **권한을 빌렸을 뿐**이다.
       SaaS는 자기가 누구를 위해 일하는지 구분할 방법이 없었다.


 ── ExternalId 방어를 넣은 상태 ────────────────────────────────────────

   고객마다 **SaaS가 발급한 고유 값**을 신뢰 정책 조건에 박아 둔다.

   고객 A 신뢰 정책:  sts:ExternalId == "a1b2c3-고객A전용"
   고객 B 신뢰 정책:  sts:ExternalId == "z9y8x7-고객B전용"

              ┌───────────────────────────────┐
              │  SaaS 벤더                     │
              │  고객A 작업 → ExternalId "a1b2c3" 전달
              │  고객B 작업 → ExternalId "z9y8x7" 전달
              └───────────────┬───────────────┘
                              │
                              ▼
              ┌────────────────────────────────────────┐
              │ AWS STS 신뢰 정책 검사                  │
              │  "Principal 이 SaaS 계정인가?"     ✅   │
              │  "ExternalId 가 a1b2c3 인가?"          │
              │      · 고객A 작업이면            ✅ 통과 │
              │      · 공격자가 유도한 호출이면  ❌ 거부 │
              └────────────────────────────────────────┘

     ▲ 공격자가 남의 역할 ARN을 등록해도, SaaS는 **자기 고객의**
       ExternalId를 붙여 보내므로 피해자 역할의 조건과 맞지 않는다.
       → 고객 간 격리가 신뢰 정책 수준에서 성립한다.

여기서 핵심은 누가 ExternalId를 정하는가다. SaaS가 고객마다 다른 값을 발급하고, SaaS가 그 값을 자기 쪽에 저장해 호출 시 붙인다. 고객이 임의로 정하는 구조라면 공격자도 자기 계정에 같은 값을 넣어 등록할 수 있어 격리가 깨진다.

해법은 ExternalId — SaaS가 당신에게만 발급한 고유값을 trust policy의 Condition에 박아둔다.

{
  "Effect": "Allow",
  "Principal": {"AWS": "arn:aws:iam::SAAS-ACCOUNT-ID:root"},
  "Action": "sts:AssumeRole",
  "Condition": {
    "StringEquals": {"sts:ExternalId": "your-unique-external-id-xyz"}
  }
}

SaaS는 당신의 역할을 맡을 때 이 ExternalId를 함께 전달하고, 다른 고객의 ExternalId로는 당신 역할을 맡을 수 없다. 고객 간 격리가 보장된다.

AWS 서비스가 대리인일 때: aws:SourceArn / aws:SourceAccount

서비스 주체(예: CloudWatch, S3, SNS)가 당신의 역할/리소스를 사용할 때도 같은 공격이 가능하다. 이때는 aws:SourceArn(또는 aws:SourceAccount)으로 "오직 이 특정 리소스가 트리거한 호출만 허용"을 강제한다.

{
  "Effect": "Allow",
  "Principal": {"Service": "sns.amazonaws.com"},
  "Action": "sts:AssumeRole",
  "Condition": {
    "StringEquals": {"aws:SourceAccount": "111122223333"},
    "ArnLike": {"aws:SourceArn": "arn:aws:sns:us-east-1:111122223333:my-topic"}
  }
}

둘은 같은 문제를 푸는 서로 다른 도구다. 대리인이 다른 AWS 계정이면 ExternalId, AWS 서비스면 출처 조건을 쓴다.

축sts:ExternalIdaws:SourceArn / aws:SourceAccount
대리인의 정체서드파티 AWS 계정AWS 서비스 주체(*.amazonaws.com)
값을 정하는 쪽서드파티가 고객마다 발급AWS가 요청에 자동으로 채움
붙는 위치역할의 신뢰 정책역할 신뢰 정책 또는 리소스 정책
전달 방법호출 시 --external-id로 명시호출자가 조작할 수 없음
막는 것다른 고객이 내 역할을 맡는 것남의 리소스가 내 리소스를 트리거하는 것
비밀값인가아니다 — 추측돼도 방어가 성립해당 없음
대표 상황모니터링·백업·비용관리 SaaS 연동S3→SNS, CloudWatch→Lambda, 서비스 롤 전반

aws:SourceAccount와 aws:SourceArn을 함께 쓰는 이유도 짚어 둘 만하다. SourceAccount는 계정 단위로 넓게 거르고, SourceArn은 특정 리소스까지 좁힌다. 일부 서비스는 상황에 따라 SourceArn을 채우지 못하는 경우가 있어, 계정 조건을 함께 두면 최소한의 방어선이 남는다. 넓은 조건과 좁은 조건을 겹쳐 두는 것이 이 패턴의 요령이다.

⚠️ 함정: 서비스 주체를 신뢰하는 정책에서 출처 조건을 빼먹는 실수는 놀랄 만큼 흔하다. {"Service": "s3.amazonaws.com"}은 "전 세계의 모든 S3"를 의미하지 "내 S3"를 의미하지 않는다. 서비스 주체는 계정을 구분하지 않기 때문이다. 그래서 SNS 토픽·SQS 큐·Lambda 함수·KMS 키에 서비스 주체를 허용할 때는 거의 예외 없이 aws:SourceArn 또는 aws:SourceAccount가 따라붙어야 한다. 시험에서 Service 주체가 든 정책 조각이 보이면 조건 절이 있는지부터 확인하라.

🎯 시나리오: "서드파티 백업 벤더에게 우리 S3에 접근하는 cross-account 역할을 만들어 줘야 한다." 정답 패턴은 ① IAM User access key를 벤더에 주지 않고(절대 금지) ② IAM Role + trust policy에 벤더 계정 + ExternalId 명시 ③ permission policy는 필요한 버킷·Action만(최소 권한). ExternalId가 없으면 같은 벤더를 쓰는 다른 고객이 우리 자원에 접근할 수 있는 Confused Deputy 구멍이 남는다. 이 패턴은 Datadog·New Relic·PagerDuty 등 모든 서드파티 통합에 동일하다.

⚠️ 함정: ExternalId는 "비밀번호"가 아니다 — 추측 가능해도 공격을 막는다. 핵심은 고객이 스스로 ExternalId를 정하지 않고 서드파티가 발급한다는 점이다. 고객이 임의로 정하면 다른 고객과 충돌하거나 예측돼 격리가 깨진다. 시험에서 "ExternalId를 고객이 자유롭게 설정"이라는 보기는 함정이다.

CLI로 보는 AssumeRole

# 역할 맡기 — 임시 자격 증명 3종 반환
aws sts assume-role \
  --role-arn arn:aws:iam::444455556666:role/CrossAccountReadRole \
  --role-session-name security-audit-2026 \
  --external-id your-unique-external-id-xyz \
  --duration-seconds 3600
 
# 반환된 자격 증명으로 후속 호출 (환경변수 설정 후)
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...   # 임시 자격 증명엔 SessionToken 필수
aws sts get-caller-identity    # 누구로 행동 중인지 확인

실무에서 자주 쓰는 변형들도 함께 익혀 둔다. 각 옵션이 어떤 보안 요구에 대응하는지가 시험 포인트다.

# ① MFA를 요구하는 신뢰 정책을 만족시키며 역할 맡기
aws sts assume-role \
  --role-arn arn:aws:iam::444455556666:role/BreakGlassRole \
  --role-session-name incident-2026-07 \
  --serial-number arn:aws:iam::111122223333:mfa/alice \
  --token-code 123456
 
# ② 세션 태그를 주입해 ABAC 조건이 걸리게 하기
aws sts assume-role \
  --role-arn arn:aws:iam::111122223333:role/ProjectRole \
  --role-session-name alice@example.com \
  --tags Key=Project,Value=atlas Key=Env,Value=prod \
  --transitive-tag-keys Project
 
# ③ 최초 신원을 못 박아 체이닝 전 과정에서 추적되게 하기
aws sts assume-role \
  --role-arn arn:aws:iam::444455556666:role/AuditRole \
  --role-session-name audit-run \
  --source-identity alice@example.com
 
# ④ OIDC 토큰으로 역할 맡기 (CI 환경에서 쓰는 형태)
aws sts assume-role-with-web-identity \
  --role-arn arn:aws:iam::111122223333:role/GitHubDeployRole \
  --role-session-name gh-actions \
  --web-identity-token "$OIDC_TOKEN"
 
# ⑤ 프로파일에 역할을 등록해 두면 SDK·CLI가 알아서 갱신한다 (권장)
#   ~/.aws/config
#   [profile audit]
#   role_arn       = arn:aws:iam::444455556666:role/CrossAccountReadRole
#   source_profile = default
#   external_id    = your-unique-external-id
#   duration_seconds = 3600
aws s3 ls --profile audit
# 신뢰 정책만 따로 꺼내 확인 — "누가 이 역할을 맡을 수 있나"
aws iam get-role --role-name CrossAccountReadRole \
  --query 'Role.AssumeRolePolicyDocument'
 
# 역할의 최대 세션 시간 확인 (체이닝이면 어차피 1시간으로 잘린다)
aws iam get-role --role-name CrossAccountReadRole \
  --query 'Role.MaxSessionDuration'
 
# EC2에서 IMDSv2를 강제하도록 변경 (SSRF 방어의 핵심)
aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc123 \
  --http-tokens required \
  --http-endpoint enabled \
  --http-put-response-hop-limit 1

🔍 더 깊이: 마지막 명령의 --http-put-response-hop-limit 1이 조용히 중요한 옵션이다. 메타데이터 응답이 몇 홉까지 전달될 수 있는지를 제한하는데, 값이 1이면 인스턴스 자신만 메타데이터를 읽을 수 있다. 컨테이너가 도는 호스트에서 이 값이 2 이상이면 컨테이너 안에서 호스트의 인스턴스 자격 증명을 읽을 수 있어, 컨테이너 하나가 뚫리면 인스턴스 역할 전체가 노출된다. --http-tokens required(IMDSv2 강제)와 홉 제한은 짝으로 걸어야 방어가 완성된다.

⚠️ 함정: --profile로 역할을 등록해 쓰는 방식이 CLI에서는 편하지만, external_id가 로컬 설정 파일에 평문으로 남는다는 점을 인지해야 한다. ExternalId는 비밀값이 아니므로 그 자체가 치명적이지는 않으나, 같은 파일에 aws_secret_access_key가 함께 들어 있다면 그건 다른 문제다. 원칙은 하나다 — ~/.aws/credentials에 장기 키를 두지 않는 것. 사람은 Identity Center 로그인으로, 워크로드는 인스턴스·태스크 역할로 자격 증명을 받게 하면 이 파일에 비밀이 남을 이유가 없다.

📚 사례: 2019년 Capital One 사고의 본질은 ① WAF(SSRF 방어 미흡) ② IMDSv1으로 EC2의 임시 자격 증명 탈취 ③ 그 자격 증명으로 S3 접근. 임시 자격 증명 자체는 안전 장치지만, **그것을 훔치는 경로(SSRF → IMDS)**가 열려 있으면 무력화된다. 그래서 IMDSv2 강제 + 최소 권한 인스턴스 역할 + WAF가 한 묶음으로 시험에 나온다. 임시 자격 증명은 "노출 시 시간 제한"이라는 방어선일 뿐, 노출 경로를 막는 건 별개의 통제다.

정리하며 — 임시 자격 증명이 보안의 기본값

오늘의 핵심 세 가지. 첫째, **STS는 만료되는 임시 자격 증명(SessionToken 포함)**을 발급하고, EC2/Lambda/ECS/페더레이션이 모두 그 위에서 동작한다 — 장기 키를 코드·CI에 넣는 안티패턴을 OIDC·인스턴스 역할로 대체하라. 둘째, AssumeRole은 **trust policy(누가)와 permission policy(무엇을)**의 두 축이며 cross-account는 양쪽 허용이 필요하다. 셋째, cross-account 위임에서 **Confused Deputy를 ExternalId(서드파티)·aws:SourceArn(AWS 서비스)**으로 반드시 막아야 한다.

📚 사례: 임시 자격 증명이 유출됐을 때의 대응 순서도 알아 둘 만하다. "만료될 때까지 기다린다"는 답은 틀렸다 — 최대 12시간이 남아 있을 수 있고, 그 사이 공격자는 계속 갱신을 시도한다. 실제 순서는 ① 해당 역할의 권한 정책에 즉시 전면 Deny 문장을 추가해 세션을 무력화하고(발급된 세션도 매 요청마다 정책을 다시 평가받으므로 즉시 효과가 있다) ② 그 역할을 맡을 수 있는 경로(신뢰 정책·인스턴스 프로파일)를 차단한 뒤 ③ CloudTrail에서 그 세션이 무엇을 했는지 전수 조사하고 ④ 근본 원인(메타데이터 노출·토큰 유출 경로)을 고친다. 정책은 발급된 세션에도 소급 적용된다는 성질이 여기서 결정적으로 쓰인다. 이것이 장기 키와의 또 하나의 차이다 — 장기 키는 비활성화가 필요하지만, 역할 세션은 정책 한 줄로 즉시 끌 수 있다.

⚠️ 함정: "역할 세션을 취소하려면 세션을 삭제하는 API를 호출한다"는 보기는 오답이다. STS에는 개별 세션을 회수하는 API가 없다. 대신 역할의 정책에 발급 시각 기준 조건을 건 Deny를 추가해 특정 시점 이전에 발급된 세션 전부를 무효화하는 방식을 쓴다. 콘솔의 "세션 취소(revoke sessions)" 기능도 내부적으로 정확히 이 정책 문장을 자동으로 넣어 주는 것이다. 메커니즘을 알면 왜 그 기능이 역할 정책을 수정하는지 이해된다.

내일은 Week 1의 마무리로, 오늘까지 배운 IAM·STS·정책 평가를 종합 시나리오로 엮는다. "권한이 있는데 왜 거부되는가", "서드파티에 안전하게 권한을 위임하라", "장기 키를 임시 자격 증명으로 전환하라" 같은 실전 상황을 통해 Week 1의 사고 프레임을 굳힌다.

한 줄 요약

STS는 만료되는 임시 자격 증명 3종(AccessKeyId ASIA... + SecretAccessKey + SessionToken)을 발급하며, EC2 인스턴스 프로파일·Lambda 실행 역할·ECS 태스크 역할·EKS IRSA·페더레이션이 전부 이 위에서 돌아간다 — 그래서 장기 키가 등장할 자리가 사실상 없다. 역할은 정책을 두 장 갖는데 **신뢰 정책은 "누가 맡나"(리소스 기반), 권한 정책은 "맡으면 뭘 하나"(Identity 기반)**이고, 교차 계정은 호출 측 sts:AssumeRole Allow와 대상 역할 신뢰 정책이 둘 다 있어야 한다. "맡을 수 없다"와 "맡았는데 아무것도 못 한다"는 서로 다른 층의 문제다. 신뢰 정책의 Principal에 계정 root를 쓰면 그 계정 전체에 위임하는 것이고, {"AWS": "*"}는 조건이 있어도 피해야 한다. Confused Deputy는 대리인이 서드파티 계정이면 **서드파티가 발급한 sts:ExternalId**로, AWS 서비스면 **aws:SourceArn·aws:SourceAccount**로 막는다 — {"Service": "s3.amazonaws.com"}은 "전 세계의 S3"라는 뜻이라 출처 조건 없이는 위험하다. 역할 체이닝은 세션이 1시간으로 잘리고 추적성이 흐려지므로 가급적 피하되, 불가피하면 sts:SourceIdentity로 최초 신원을 끝까지 붙들어 둔다. 자격 증명 탈취 경로는 별도 통제이며 EC2에서는 IMDSv2 강제 + 홉 제한 1이 표준이고, 유출된 세션은 삭제 API가 아니라 역할 정책의 Deny 추가로 즉시 무력화한다.

📝 연습 문제

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

문제 1

STS 임시 자격 증명이 장기 IAM User access key보다 보안상 우수한 가장 본질적인 이유는?

문제 2

서드파티 모니터링 SaaS가 여러 고객의 AWS 계정에 동일한 SaaS 계정으로 AssumeRole 접근한다. 한 고객의 역할을 다른 고객이 SaaS를 통해 맡지 못하게 격리하는 핵심 메커니즘은?

문제 3

역할 체이닝(한 역할을 맡은 상태에서 또 다른 역할을 맡음)에 대한 설명으로 옳은 것은?

문제 4

GitHub Actions가 장기 access key 없이 AWS 역할을 맡도록 구성할 때, 보안상 가장 중요한 trust policy 설정은?

문제 5

EC2 인스턴스에 부여된 임시 자격 증명이 SSRF 공격으로 탈취된 사고를 예방하기 위해 가장 직접적으로 적용해야 할 통제는?

이전IAM 정책 심화: Identity vs Resource 정책, 조건 키, 최소 권한 설계Week 1 · Day 3다음 Week 1 종합: IAM과 자격 증명을 시나리오로 통합 복습Week 1 · Day 5

이 페이지

  • STS가 발급하는 것: 임시 자격 증명 3종
  • AssumeRole: trust policy와 permission policy의 두 축
  • 페더레이션: 외부 신원을 AWS 자격 증명으로
  • SAML 2.0 페더레이션 (기업 워크포스)
  • OIDC / Web Identity 페더레이션 (앱·CI/CD)
  • 역할 체이닝(Role Chaining)과 제약
  • Confused Deputy 방지: ExternalId와 aws:SourceArn
  • 시나리오: 서드파티 SaaS의 cross-account 접근
  • AWS 서비스가 대리인일 때: aws:SourceArn / aws:SourceAccount
  • CLI로 보는 AssumeRole
  • 정리하며 — 임시 자격 증명이 보안의 기본값
  • 한 줄 요약
  • 연습 문제