IAM User vs IAM Role 차이점 완전 정리 — EC2에서 S3 접근 시 무엇을 써야 하는가

IAM User와 IAM Role의 차이를 명확히 이해하지 못하면, EC2 인스턴스에서 S3에 접근할 때 자격증명을 하드코딩하거나 불필요하게 장기 키를 발급하는 실수를 반복하게 된다. 이 글은 두 개념의 구조적 차이와, EC2 인스턴스가 S3에 접근하는 실제 운영 시나리오에서 어떤 선택이 올바른지를 명확히 설명한다.

TL;DR — IAM User vs IAM Role 핵심 비교

EC2 인스턴스에서 S3에 접근할 때는 IAM Role(인스턴스 프로파일)을 사용하는 것이 AWS 공식 권장 방식이다. IAM User의 액세스 키를 인스턴스에 직접 저장하는 방식은 키 노출 위험이 있고, 자격증명 교체 비용이 높다.

항목IAM UserIAM Role
자격증명 유형장기 액세스 키 (Access Key ID + Secret)임시 보안 토큰 (STS 발급)
주체(Principal)사람 또는 애플리케이션AWS 서비스, 계정, 사람 등
자격증명 수명명시적으로 삭제하기 전까지 유효기본 1시간, 최대 12시간 (설정에 따라 다름)
EC2 사용 권장 여부❌ 비권장 (키 하드코딩 위험)✅ 권장 (인스턴스 프로파일)
자격증명 자동 교체수동 교체 필요STS가 자동 갱신
멀티 계정 접근제한적Cross-account Role Assumption 지원

IAM User와 IAM Role의 작동 원리

IAM User는 AWS 계정 내에 영구적으로 존재하는 자격증명 주체다. 콘솔 로그인용 패스워드와 API 호출용 액세스 키를 가지며, 이 키는 명시적으로 비활성화하거나 삭제하지 않는 한 계속 유효하다. 사람이 직접 AWS 콘솔이나 CLI를 사용하는 경우에 적합하다.

IAM Role은 자격증명을 '소유'하는 개체가 아니라, 특정 조건에서 '위임'받아 사용하는 권한 집합이다. Role을 Assume하면 AWS STS(Security Token Service)가 임시 자격증명(Access Key ID, Secret Access Key, Session Token)을 발급한다. 이 임시 자격증명은 만료 시간이 있고, SDK가 자동으로 갱신한다.

EC2 인스턴스에 IAM Role을 연결하면 '인스턴스 프로파일(Instance Profile)'이라는 컨테이너를 통해 Role이 인스턴스에 바인딩된다. 인스턴스 내부의 애플리케이션은 인스턴스 메타데이터 서비스(IMDS)를 통해 임시 자격증명을 자동으로 획득한다. 코드에 키를 한 줄도 작성할 필요가 없다.

graph LR A["EC2 Instance"] -->|"자격증명 요청"| B["IMDS 169.254.169.254"] B -->|"임시 토큰 반환"| A B <-->|"Role Assume"| C["AWS STS"] C -->|"신뢰 정책 검증"| D["IAM Role EC2S3AccessRole"] A -->|"S3 API 호출 (임시 토큰 사용)"| E["Amazon S3 my-app-bucket"] F["IAM User 방식 (비권장)"] -->|"액세스 키 하드코딩 노출 위험"| E
  1. EC2 인스턴스에 IAM Role이 인스턴스 프로파일로 연결된다.
  2. 애플리케이션(또는 AWS SDK)이 IMDS 엔드포인트(169.254.169.254)에 자격증명을 요청한다.
  3. IMDS가 STS로부터 발급된 임시 자격증명을 반환한다.
  4. SDK는 이 자격증명을 사용해 S3 API를 호출하고, 만료 전에 자동 갱신한다.
  5. IAM User 방식은 액세스 키를 인스턴스 내 파일이나 환경변수에 직접 저장해야 하므로 노출 위험이 존재한다.

IAM Role 기반 EC2-S3 접근 설정 방법

설정은 세 단계로 구성된다. Role 생성 → 권한 정책 연결 → EC2 인스턴스에 연결. 이미 실행 중인 인스턴스에도 Role을 연결하거나 교체할 수 있다.

1단계: IAM Role 생성 (EC2 신뢰 정책 포함)

EC2 서비스가 이 Role을 Assume할 수 있도록 신뢰 정책(Trust Policy)을 지정해야 한다. 신뢰 정책 없이 권한 정책만 붙이면 EC2가 Role을 사용할 수 없다 — 이 부분을 빠뜨리는 실수가 생각보다 많다.

🔽 신뢰 정책 JSON (trust-policy.json)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
# IAM Role 생성
aws iam create-role \
  --role-name EC2S3AccessRole \
  --assume-role-policy-document file://trust-policy.json

2단계: S3 접근 권한 정책 생성 및 연결

최소 권한 원칙에 따라 특정 버킷에 대한 읽기/쓰기만 허용하는 인라인 정책을 작성한다. s3:ListAllMyBuckets처럼 계정 전체 버킷 목록 조회가 필요한 액션은 리소스 수준 제한이 불가능하므로 "Resource": "*"가 필요하다 — 이는 서비스 인가 레퍼런스에서 확인된 동작이다.

🔽 S3 권한 정책 JSON (s3-policy.json)
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": "arn:aws:s3:::my-app-bucket/*"
    },
    {
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::my-app-bucket"
    }
  ]
}
# 권한 정책 생성
aws iam create-policy \
  --policy-name EC2S3AccessPolicy \
  --policy-document file://s3-policy.json

# Role에 정책 연결
aws iam attach-role-policy \
  --role-name EC2S3AccessRole \
  --policy-arn arn:aws:iam::123456789012:policy/EC2S3AccessPolicy

3단계: 인스턴스 프로파일 생성 및 EC2에 연결

IAM Role을 EC2에 직접 연결할 수 없다. 반드시 인스턴스 프로파일이라는 래퍼 객체를 거쳐야 한다. AWS 콘솔에서 Role을 생성하면 같은 이름의 인스턴스 프로파일이 자동 생성되지만, CLI로 생성할 때는 명시적으로 만들어야 한다.

# 인스턴스 프로파일 생성
aws iam create-instance-profile \
  --instance-profile-name EC2S3AccessProfile

# 인스턴스 프로파일에 Role 추가
aws iam add-role-to-instance-profile \
  --instance-profile-name EC2S3AccessProfile \
  --role-name EC2S3AccessRole

# 실행 중인 EC2 인스턴스에 인스턴스 프로파일 연결
aws ec2 associate-iam-instance-profile \
  --instance-id i-0abcdef1234567890 \
  --iam-instance-profile Name=EC2S3AccessProfile

4단계: 인스턴스 내에서 자격증명 확인

연결이 정상적으로 이루어졌다면, 인스턴스 내부에서 IMDS를 통해 임시 자격증명이 조회된다. 이 단계를 확인하지 않고 애플리케이션 오류를 디버깅하는 건 시간 낭비다.

# IMDSv2 방식으로 자격증명 확인 (IMDSv2 사용 권장)
TOKEN=$(curl -s -X PUT 'http://169.254.169.254/latest/api/token' \
  -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600')

curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/iam/security-credentials/EC2S3AccessRole

응답에 AccessKeyId, SecretAccessKey, Token, Expiration 필드가 포함되어 있으면 정상이다. Expiration이 존재한다는 것 자체가 이 자격증명이 임시 토큰임을 의미한다.

실제 운영에서 자주 겪는 오진 패턴

EC2에서 S3 접근이 안 된다는 티켓이 들어왔을 때, 첫 번째 반응은 보통 '버킷 정책 문제겠지'다. 버킷 정책을 열어보고, 퍼블릭 접근 차단 설정을 확인하고, 그래도 안 되면 IAM 정책을 다시 들여다본다.

그런데 실제 원인이 인스턴스 프로파일 자체가 연결되지 않은 경우였다. 인스턴스에 Role을 붙였다고 생각했지만, 인스턴스 프로파일 생성 단계를 빠뜨린 것이다. 애플리케이션 로그에는 Unable to load credentials 또는 NoCredentialProviders 계열의 에러가 찍히는데, 이걸 IAM 권한 문제로 오해하고 정책만 계속 수정하는 루프에 빠진다.

IAM 권한 오류(AccessDenied)와 자격증명 로드 실패(CredentialProviderError)는 다른 문제다. 전자는 자격증명은 있지만 권한이 없는 것이고, 후자는 자격증명 자체를 찾지 못한 것이다. 인스턴스 프로파일 연결 여부를 먼저 확인하는 것이 순서다.

# 인스턴스에 연결된 인스턴스 프로파일 확인
aws ec2 describe-instances \
  --instance-ids i-0abcdef1234567890 \
  --query 'Reservations[0].Instances[0].IamInstanceProfile'

이 명령어 결과가 null이면 인스턴스 프로파일이 연결되지 않은 것이다. 정책 디버깅보다 이 확인이 먼저다.

graph TD A["S3 접근 실패"] --> B{"에러 유형 분류"} B -->|"CredentialProviderError"| C["인스턴스 프로파일 연결 여부 확인"] B -->|"AccessDenied"| D["IAM 정책 확인"] C -->|"프로파일 없음"| E["인스턴스 프로파일 생성 및 연결"] C -->|"프로파일 있음"| F["IMDS 응답 확인 curl 169.254.169.254"] D --> G["버킷 정책 확인 (Deny override 여부)"]
  1. 애플리케이션에서 S3 접근 실패 발생 시, 에러 유형을 먼저 분류한다.
  2. CredentialProviderError 계열이면 인스턴스 프로파일 연결 여부를 확인한다.
  3. AccessDenied이면 IAM 정책과 버킷 정책을 순서대로 점검한다.
  4. 버킷 정책의 Deny 구문은 IAM Allow를 override하므로 버킷 정책 확인이 필수다.

IAM User를 써야 하는 경우는 언제인가

IAM Role이 권장된다고 해서 IAM User가 쓸모없는 것은 아니다. 사람이 직접 AWS CLI를 사용하거나 콘솔에 로그인하는 경우, 또는 AWS 외부에서 실행되는 시스템(온프레미스 서버, 서드파티 CI/CD 도구 등)이 AWS API를 호출해야 하는 경우에는 IAM User의 액세스 키가 현실적인 선택이 될 수 있다.

다만 AWS 외부 시스템에 대해서도 IAM Roles Anywhere를 통해 X.509 인증서 기반으로 임시 자격증명을 발급하는 방식이 제공되고 있으므로, 장기 액세스 키 사용을 최소화하는 방향이 권장된다.

IAM User의 액세스 키는 금고 열쇠를 복사해서 여러 곳에 나눠주는 것과 같다. 열쇠 하나가 유출되면 금고 전체가 위험하고, 어떤 열쇠가 어디 있는지 추적하기 어렵다. IAM Role의 임시 토큰은 시간 제한이 있는 방문증에 가깝다 — 만료되면 자동으로 무효화된다.

IAM Role 관련 주요 IAM 권한 정리

Role을 생성하고 인스턴스에 연결하는 작업 자체에도 IAM 권한이 필요하다. 자동화 파이프라인이나 IaC 도구에서 이 작업을 수행할 때 권한 부족으로 막히는 경우가 있으므로 미리 확인한다.

작업필요한 IAM 액션리소스 수준 제한
Role 생성iam:CreateRoleARN 지정 가능
정책 연결iam:AttachRolePolicyARN 지정 가능
인스턴스 프로파일 생성iam:CreateInstanceProfileARN 지정 가능
프로파일에 Role 추가iam:AddRoleToInstanceProfileARN 지정 가능
EC2에 프로파일 연결ec2:AssociateIamInstanceProfile인스턴스 ARN 지정 가능
Role Assume (EC2 내부)sts:AssumeRole (신뢰 정책으로 허용)신뢰 정책에서 제어

IAM User vs IAM Role — 의사결정 가이드

graph TD A["자격증명 주체는 누구인가?"] --> B{"사람 vs 시스템"} B -->|"AWS 서비스/리소스 (EC2, Lambda 등)"| C["✅ IAM Role 인스턴스 프로파일"] B -->|"사람"| D{"접근 방식"} D -->|"콘솔 / CLI 직접 사용"| E["IAM User 또는 IAM Identity Center"] D -->|"AWS 외부 시스템 (온프레미스 등)"| F["IAM Roles Anywhere 또는 IAM User 액세스 키"]
  1. 자격증명 주체가 사람인지 AWS 서비스/리소스인지를 먼저 판단한다.
  2. AWS 서비스(EC2, Lambda 등)라면 IAM Role이 유일한 올바른 선택이다.
  3. 사람이지만 AWS 외부 시스템을 통해 접근한다면 IAM Roles Anywhere 또는 IAM User 액세스 키를 검토한다.
  4. 사람이 직접 콘솔/CLI를 사용한다면 IAM User(또는 IAM Identity Center)를 사용한다.

마무리 및 다음 단계

EC2 인스턴스에서 S3에 접근하는 올바른 방법은 IAM Role + 인스턴스 프로파일이다. 액세스 키를 코드나 환경변수에 저장하는 방식은 키 노출 위험과 수동 교체 부담을 동시에 안고 가는 구조다. IAM Role 기반 임시 자격증명은 SDK가 자동으로 갱신하므로 운영 부담도 낮다.

다음 단계로 고려할 수 있는 주제:

  • IAM Identity Center(SSO)를 통한 사람 사용자 관리 중앙화
  • IAM Roles Anywhere를 통한 온프레미스 워크로드의 임시 자격증명 발급
  • S3 버킷 정책과 IAM 정책의 평가 순서 및 Deny override 동작
  • AWS Organizations SCP와 IAM 정책의 상호작용

공식 참고 문서: Using an IAM role to grant permissions to applications running on Amazon EC2 instances

핵심 용어 정리 (Glossary)

용어설명
IAM UserAWS 계정 내 영구 자격증명 주체. 장기 액세스 키를 보유한다.
IAM Role신뢰 정책에 의해 위임받아 사용하는 권한 집합. STS 임시 토큰을 통해 동작한다.
인스턴스 프로파일 (Instance Profile)IAM Role을 EC2 인스턴스에 연결하기 위한 컨테이너 객체.
IMDS (Instance Metadata Service)EC2 인스턴스 내부에서 메타데이터 및 임시 자격증명을 조회하는 링크-로컬 HTTP 엔드포인트.
STS (Security Token Service)임시 보안 자격증명을 발급하는 AWS 서비스. Role Assume 시 토큰을 생성한다.

댓글

이 블로그의 인기 게시물

EC2 SSH 연결 시간 초과: 확인해야 할 보안 그룹(Security Group) 규칙

EC2 SSH 연결 타임아웃 완전 해결 가이드: Security Group 인바운드 규칙부터 라우팅까지