개요
IAM(Identity and Access Management)은 “누가 AWS에서 무엇을 할 수 있는가"를 제어하는 서비스입니다. EC2 하나 만들려고 해도 IAM 권한이 없으면 불가능합니다.
잘못 설정하면 보안 사고로 이어지고, 너무 빡빡하면 개발이 안 됩니다. 이 글은 IAM의 핵심 구성요소와 설계 원칙을 정리합니다.
1. IAM 구성 요소
상세 내용
4가지 핵심
| 구성요소 | 설명 |
|---|---|
| User | 사람에 해당하는 자격 증명 (개발자, 운영자) |
| Group | User 묶음. 그룹에 붙인 정책이 소속 User 전부에 적용됨 |
| Role | 서비스나 외부 주체가 임시로 맡아 쓰는 권한 |
| Policy | 권한 규칙을 정의한 JSON 문서 |
관계
Policy (권한 정의)
├── 붙이는 대상: User
├── 붙이는 대상: Group (→ 안에 있는 User 전부 적용)
└── 붙이는 대상: Role (→ 이 Role을 맡은 주체에 적용)User vs Role 차이
| User | Role | |
|---|---|---|
| 누가 쓰냐 | 사람 | 서비스(EC2, Lambda), 외부 계정, CI/CD |
| 인증 방식 | Access Key or 콘솔 비밀번호 | STS로 임시 자격증명 발급 |
| 영구성 | 영구 | 임시 (세션 만료) |
| 권장 | 최소화 (사람만) | 서비스 간 통신은 전부 Role |
# 유저 생성
aws iam create-user --user-name developer-a
# 그룹에 추가
aws iam add-user-to-group --user-name developer-a --group-name developers
# Role 목록
aws iam list-roles2. Policy (정책) 작성법
상세 내용
Policy = JSON으로 된 권한 규칙
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-bucket/*"
},
{
"Effect": "Deny",
"Action": "s3:DeleteObject",
"Resource": "*"
}
]
}Statement 구성요소
| 키 | 의미 | 예시 |
|---|---|---|
| Effect | 허용/거부 | Allow, Deny |
| Action | 어떤 동작 | s3:GetObject, ec2:RunInstances |
| Resource | 어떤 리소스에 대해 | arn:aws:s3:::my-bucket/* |
| Condition | 조건 (선택) | 특정 IP에서만, MFA 인증 시만 |
Allow와 Deny가 같이 있으면 뭐가 이기냐
공식 문서의 정책 평가 로직은 이렇습니다. 요청은 기본적으로 거부(암시적 거부)되고, 적용되는 정책 어딘가에 명시적 Deny가 하나라도 있으면 최종 결과는 Deny입니다. 명시적 Deny가 없고 Allow가 있을 때만 허용됩니다. 위 예시에서 s3:DeleteObject는 다른 정책이 아무리 허용해도 막힙니다.
Policy 종류
| 종류 | 설명 |
|---|---|
| AWS Managed | AWS가 미리 만들어둔 것 (ReadOnlyAccess 등) |
| Customer Managed | 직접 만든 커스텀 정책 |
| Inline | 특정 User/Role에 직접 붙인 것 (비추, 관리 어려움) |
대표적인 AWS Managed Policy
| 정책 | 권한 |
|---|---|
| AdministratorAccess | 전체 관리자 (모든 것 가능) |
| ReadOnlyAccess | 읽기만 (변경 불가) |
| AmazonEC2FullAccess | EC2 전체 권한 |
| AmazonS3ReadOnlyAccess | S3 읽기만 |
| AmazonEKSClusterPolicy | EKS 클러스터 관리 |
# 정책 붙이기 (User에)
aws iam attach-user-policy --user-name developer-a --policy-arn arn:aws:iam::aws:policy/ReadOnlyAccess
# 정책 붙이기 (Role에)
aws iam attach-role-policy --role-name app-role --policy-arn arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess3. Role과 AssumeRole
상세 내용
Role = “이 권한을 빌려 쓸 수 있게 해줄게”
EC2가 S3에 접근해야 할 때, Access Key를 EC2에 넣는 게 아니라 Role을 붙입니다. Role은 임시 자격증명을 발급받아서 사용합니다.
Trust Policy = “누가 이 Role을 맡을 수 있냐”
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ec2.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}이 Trust Policy는 “EC2 서비스가 이 Role을 맡을 수 있다"는 뜻.
사용 예시들
| 시나리오 | Principal | 설명 |
|---|---|---|
| EC2가 S3 접근 | ec2.amazonaws.com | Instance Profile로 연결 |
| Lambda가 DynamoDB 접근 | lambda.amazonaws.com | Lambda 실행 역할 |
| 다른 AWS 계정에서 접근 | arn:aws:iam::111111111111:root | 크로스 계정 |
| GitHub Actions에서 접근 | OIDC Provider | 키 없이 인증 |
AssumeRole (수동으로 Role 전환)
# 임시 자격증명 발급
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/deploy-role \
--role-session-name my-session
# 반환된 값으로 환경변수 설정
export AWS_ACCESS_KEY_ID="임시키"
export AWS_SECRET_ACCESS_KEY="임시시크릿"
export AWS_SESSION_TOKEN="임시토큰"이렇게 하면 다른 계정의 Role 권한으로 작업 가능 (크로스 계정).
4. 최소 권한 원칙
상세 내용
“필요한 것만, 필요한 리소스에만, 필요한 시간만”
| 원칙 | 예시 |
|---|---|
| Action 최소화 | s3:* 대신 s3:GetObject, s3:PutObject |
| Resource 최소화 | * 대신 arn:aws:s3:::my-bucket/* |
| Condition 활용 | 특정 IP, MFA 인증 시만 허용 |
| 임시 자격증명 사용 | Access Key 대신 Role (자동 만료) |
Condition 예시 — MFA 없으면 차단
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
}
}
}Condition 예시 — 특정 IP에서만 허용
{
"Condition": {
"IpAddress": {
"aws:SourceIp": "203.0.113.0/24"
}
}
}확인 도구
# 내가 지금 어떤 권한이 있는지
aws iam get-user
aws sts get-caller-identity
# 특정 동작 가능한지 시뮬레이션
aws iam simulate-principal-policy \
--policy-source-arn arn:aws:iam::111111111111:user/developer-a \
--action-names s3:GetObject5. IAM 설계 패턴
상세 내용
팀/역할 기반 구조
Groups:
├── admins → AdministratorAccess
├── developers → 개발에 필요한 권한 (EC2, S3, CloudWatch 읽기)
├── devops → 배포 권한 (EKS, ECR, CodePipeline)
└── readonly → ReadOnlyAccess
Users:
├── admin-kim → admins 그룹
├── dev-park → developers 그룹
└── devops-lee → devops 그룹서비스별 Role
Roles:
├── ec2-app-role → S3 읽기 + CloudWatch 쓰기
├── lambda-processor → DynamoDB 읽기/쓰기 + SQS
├── eks-node-role → ECR pull + CloudWatch
└── ci-deploy-role → ECR push + EKS 배포권한 경계 (Permission Boundary)
“이 유저가 아무리 정책을 붙여도 이 범위를 넘을 수 없다"는 상한선.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*", "ec2:*", "cloudwatch:*"],
"Resource": "*"
}
]
}개발자가 스스로 정책을 만들어도, Permission Boundary 안에서만 가능합니다. IAM 자체 권한 남용 방지.
6. 크로스 계정 접근
상세 내용
계정 A에서 계정 B의 리소스에 접근하기
계정 A (개발) → AssumeRole → 계정 B (운영)의 deploy-role → S3, EKS 접근계정 B에서 Role 생성 (Trust Policy에 A 계정 허용)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::111111111111:root"
},
"Action": "sts:AssumeRole"
}
]
}계정 A에서 사용
aws sts assume-role \
--role-arn arn:aws:iam::222222222222:role/deploy-role \
--role-session-name cross-account이 패턴은 멀티 계정 환경에서 필수입니다. 계정마다 유저를 만드는 게 아니라, 하나의 계정에서 Role 전환으로 다른 계정에 접근합니다.
정책 평가에서는 Allow를 여러 개 붙여도 명시적 Deny 하나가 있으면 전부 막힙니다. 명시적 Deny가 다른 모든 Allow보다 우선합니다.