본문으로 건너뛰기
김신건의 로그

[AWS] STS / AssumeRole: 임시 자격, cross-account

· 수정 · 📖 약 2분 · 808자/단어 #aws #sts #assume-role #iam #cloud
STS, AssumeRole, AssumeRoleWithWebIdentity, AssumeRoleWithSAML, external ID, cross-account, Instance Profile, Session Policy

정의

STS (Security Token Service) = 임시 자격 증명 발급. short-lived (15분-12시간) credentials. 장기 access key 없이 안전하게 AWS 서비스에 접근.

사용 상황

상황방법
CI/CD에서 deployGitHub OIDC + AssumeRoleWithWebIdentity
멀티 계정 AWS 조직Cross-account AssumeRole
SaaS → 고객 계정 접근AssumeRole + External ID
EC2/Lambda에서 API 호출Instance Profile (자동 갱신)
EKS Pod에서 S3, DynamoDBIRSA (AssumeRoleWithWebIdentity)
MFA 필요 작업GetSessionToken
회사 SSO 로그인AssumeRoleWithSAML

5가지 API

API사용
AssumeRoleIAM role assume
AssumeRoleWithWebIdentityOIDC (EKS IRSA, GitHub OIDC)
AssumeRoleWithSAMLSAML SSO
GetSessionTokenMFA token
GetCallerIdentity누구인지

세션 유효 시간

API최소최대비고
AssumeRole15분12시간role MaxSessionDuration 설정 필요
AssumeRoleWithWebIdentity15분12시간
AssumeRoleWithSAML15분12시간
GetSessionToken15분36시간MFA 필수 작업
Role Chaining15분1시간 고정연장 불가

AssumeRole 흐름

sequenceDiagram
    autonumber
    participant User
    participant STS
    participant TargetRole
    participant S3

    User->>STS: AssumeRole(arn:role/admin)
    Note over STS: 신뢰 관계 + 권한 확인
    STS-->>User: AccessKeyId, SecretAccessKey, SessionToken, Expiration
    User->>S3: GET object (임시 credentials)
    S3-->>User: object
    Note over User: 1시간 후 만료
    User->>STS: AssumeRole 다시

Cross-Account AssumeRole

flowchart LR
    Acct1["Account 1<br/>(User alice)"] -->|AssumeRole| Acct2Role["Account 2<br/>Role: data-reader"]
    Acct2Role -->|trust policy| Trust["Principal: arn:aws:iam::1:user/alice"]
    Acct2Role -->|permission| S3["S3 in Account 2"]

Trust Policy (Account 2 role)

{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": { "AWS": "arn:aws:iam::ACCOUNT-1:root" },
    "Action": "sts:AssumeRole",
    "Condition": {
      "StringEquals": { "sts:ExternalId": "shared-secret-string" }
    }
  }]
}

IMPORTANT

External IDconfused deputy 공격 방어. SaaS 가 우리 계정 접근 시 반드시.

Web Identity (OIDC) - GitHub Actions

permissions:
  id-token: write
steps:
  - uses: aws-actions/configure-aws-credentials@v4
    with:
      role-to-assume: arn:aws:iam::123:role/github-actions
      aws-region: us-east-1

GitHub 의 OIDC token → AWS role assume. long-term access key 없이.

sequenceDiagram
    participant GH as "GitHub Actions"
    participant OIDC as "GitHub OIDC"
    participant STS
    participant AWSOIDC as "AWS OIDC Provider"

    GH->>OIDC: JWT token 요청
    OIDC-->>GH: OIDC token
    GH->>STS: AssumeRoleWithWebIdentity
    STS->>AWSOIDC: token 검증
    AWSOIDC-->>STS: OK
    STS-->>GH: 임시 credentials
    GH->>STS: API 호출

EKS IRSA (위와 동일)

자세한 건 aws-eks 의 IRSA 절.

SAML Federation

기업 IdP (Okta, Active Directory, Azure AD) 로 로그인 후 AWS 콘솔, API 접근.

sequenceDiagram
    participant User
    participant IdP as "Identity Provider"
    participant STS
    participant Console as "AWS Console"

    User->>IdP: SSO 로그인
    IdP-->>User: SAML assertion
    User->>STS: AssumeRoleWithSAML
    STS-->>User: 임시 credentials
    User->>Console: 콘솔 접속

Trust policy 핵심 필드:

{
  "Principal": {
    "Federated": "arn:aws:iam::123:saml-provider/MyIdP"
  },
  "Action": "sts:AssumeRoleWithSAML",
  "Condition": {
    "StringEquals": {
      "SAML:aud": "https://signin.aws.amazon.com/saml"
    }
  }
}

IdP에서 role ARN을 attribute로 매핑. 사용자가 IAM user 없이 AWS 접근 가능.

Instance Profile (EC2, Lambda, ECS)

인스턴스에 붙이는 IAM role. IMDS를 통해 credentials 자동 갱신 (만료 5분 전).

Trust policy:

{
  "Principal": { "Service": "ec2.amazonaws.com" },
  "Action": "sts:AssumeRole"
}

EC2 내부에서 현재 credentials 확인:

TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -sH "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/

SDK 사용 시 credentials 명시 불필요. 자동 갱신.

서비스Principal
EC2ec2.amazonaws.com
Lambdalambda.amazonaws.com
ECS Taskecs-tasks.amazonaws.com
CodeBuildcodebuild.amazonaws.com

Role Chaining

A role이 B role을 assume. 세션 최대 1시간 고정 (MaxSessionDuration 무관).

flowchart LR
    User["개발자"] -->|"AssumeRole"| RoleA["Role A (개발 계정)"]
    RoleA -->|"AssumeRole"| RoleB["Role B (운영 계정)"]
    RoleB --> Limit["세션: 최대 1시간"]
# Role A credentials 로 Role B assume
aws sts assume-role \
  --role-arn arn:aws:iam::PROD:role/deploy \
  --role-session-name chain-session \
  --duration-seconds 3600

WARNING

Role chaining 시 1시간 제한은 MaxSessionDuration 과 무관. 12시간 설정해도 체인이면 1시간. 배포 파이프라인이 1시간 초과할 경우 재assume 로직 필요.

Session Policy

AssumeRole 시 inline permission 추가 제한. role 권한 AND session policy = 실제 권한. 확대 불가.

aws sts assume-role \
  --role-arn arn:role/x \
  --role-session-name session \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Allow",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*"
    }]
  }'

CI/CD에서 최소 권한 세션 발급, 임시 작업자에게 제한된 권한 부여 시 유용.

Session Tags

aws sts assume-role \
  --role-arn arn:role/x \
  --role-session-name session \
  --tags Key=Team,Value=backend
"Condition": {
  "StringEquals": { "aws:PrincipalTag/Team": "backend" }
}

같은 role 의 세션마다 다른 tag세분화 권한.

감사 (CloudTrail)

AssumeRole 이벤트는 CloudTrail에 자동 기록.

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole \
  --max-results 20

주요 필드:

필드의미
userIdentity.arn누가 assume 했는지
requestParameters.roleArn어느 role
requestParameters.externalIdExternal ID 사용 여부
responseElements.assumedRoleUser결과 세션 ARN
// CloudWatch Logs Insights 쿼리 예시
{
  "filter": "eventName = 'AssumeRole'",
  "stats": "count(*) by userIdentity.arn"
}

TIP

비정상 cross-account assume 감지용 EventBridge 룰 설정 권장. 알 수 없는 Account → SNS 알림.

Session 강제 만료

침해된 role 세션을 즉각 무효화:

# DenyAll inline policy 추가 (토큰 발급 시간 이전 세션 차단)
aws iam put-role-policy \
  --role-name compromised-role \
  --policy-name AWSRevokeOlderSessions \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [{
      "Effect": "Deny",
      "Action": "*",
      "Resource": "*",
      "Condition": {
        "DateLessThan": {
          "aws:TokenIssueTime": "2026-07-16T12:00:00Z"
        }
      }
    }]
  }'

# 정리 후 삭제
aws iam delete-role-policy \
  --role-name compromised-role \
  --policy-name AWSRevokeOlderSessions

STS session 자체는 만료 전 취소 불가. 이 방식으로 실질적 무효화.

흔한 함정

WARNING

  1. External ID 누락 = 3rd party 신뢰 약함.
  2. 장기 access key 와 혼용 = role 의 의미 깨짐.
  3. 세션 만료 갱신 안 함 = 1시간 후 API 호출 실패. SDK 의 자동 refresh 확인.
  4. trust policy 의 너무 넓은 Principal = 모든 user 가 assume.
  5. Role Chaining 1시간 제한 간과 = 배포 파이프라인이 1시간 넘으면 자동 실패. 재assume 로직 추가.
  6. SCP가 AssumeRole 차단 = OU 레벨 SCP 에서 sts:AssumeRole 거부 정책 확인 필수.
  7. 세션 tag 상속 누락 = TransitiveTagKeys 지정 안 하면 chaining 시 tag 사라짐.

관련 위키

이 글의 용어 (7개)
[Auth] OAuth 2.0 / 2.1: Authorization Code + PKCEauth-security
정의 OAuth 2.0 (RFC 6749, 2012) 은 제3자 앱이 사용자 동의로 자원에 접근 하게 하는 권한 위임 프레임워크. 인증 (authentication) 이 아니라 …
[Auth] OpenID Connect (OIDC): OAuth 위의 인증 레이어auth-security
정의 OpenID Connect (OIDC) 는 OAuth 2.0 위에 얹은 인증 (authentication) 표준. OAuth 가 권한 위임 (authorization), O…
[Auth] SAML 2.0: XML 기반 기업 SSOauth-security
정의 SAML 2.0 (Security Assertion Markup Language) 는 XML 기반 기업 SSO 표준. 2005년 OASIS 표준화. 모바일 친화도 / 단순성…
[AWS] CloudTrail (API Activity Logging)cloud
정의 AWS CloudTrail 은 AWS 계정의 API 호출 및 사용자 활동을 기록 하는 감사 로깅 서비스입니다. "누가, 언제, 어디서, 어떤 API 를, 어떤 리소스에 대해…
[AWS] EKS: managed Kubernetescloud
정의 EKS (Elastic Kubernetes Service) = AWS 의 managed K8s control plane. worker node 는 사용자 (또는 Fargat…
[AWS] IAM: User, Role, Policy, STScloud
정의 IAM (Identity and Access Management) = AWS 의 권한 관리 전부. User, Group, Role, Policy 로 구성. "누가 어떤 리소…
[CI/CD] GitHub Actions: workflow, action, runnerdevops
정의 GitHub Actions = GitHub 내장 CI/CD. YAML workflow + marketplace action. 2018 출시 → Travis CI 대체. 구조…

💬 댓글

사이트 검색 / 명령어

검색

스크롤 = 확대/축소 · 드래그 = 이동 · 0 = 원래 크기 · ESC = 닫기