IAM — 사용자, 그룹, 역할, 정책
AWS에서 누구로 일할지를 정하는 IAM의 네 요소 — 사용자 · 그룹 · 역할 · 정책 — 를 한 번에 정리합니다. JSON 정책 문법과 AssumeRole의 본질, 그리고 작은 팀에서도 통하는 권한 설계 패턴까지 다룹니다.
1장 AWS 입문의 끝에서 “루트 사용자로 일하지 말자"고 했습니다. 그러면 누구로 일해야 할까요. 답은 **IAM (Identity and Access Management)**으로 만든 사용자와 역할입니다. 본 챕터는 가입 직후 가장 먼저 거쳐야 할 첫 셋업의 출발점입니다.
IAM은 글로벌 서비스입니다. 어느 리전에서 콘솔을 열어도 같은 사용자 / 역할 / 정책이 보입니다. 그리고 무료입니다. 추가 비용 없이 사용자를 무한정 만들 수 있습니다. 그래서 AWS에 처음 들어오면 가장 먼저 만나야 하는 서비스입니다.
본 챕터에서는 IAM의 네 요소를 한 번에 정리하고, 운영에서 통하는 권한 설계의 핵심 패턴까지 살펴봅니다. 여기서 만든 사용자와 역할은 4장 CLI와 SDK부터 끊임없이 등장하고, 6장 보안 기본에서 MFA와 최소 권한으로 한 번 더 단단해집니다.
큰 그림 — IAM의 네 요소 #
| 요소 | 무엇 | 누가 / 무엇이 쓰는가 |
|---|---|---|
| User (사용자) | 사람 한 명 또는 머신 한 대에 묶인 영구 자격 | 콘솔 로그인, 액세스 키 |
| Group (그룹) | 사용자 묶음 | 그룹에 정책을 붙이면 안의 사용자 모두 적용 |
| Role (역할) | 임시로 빌려 쓰는 자격 | EC2, Lambda, 다른 계정의 사용자 등 |
| Policy (정책) | 무엇을 허용 / 거부할지의 JSON 문서 | 위 셋에 붙어 권한을 정의 |
핵심은 정책이 곧 권한이라는 것입니다. 사용자 / 그룹 / 역할은 권한을 담는 그릇이고, 그 안의 정책이 진짜 무엇을 할 수 있는지 결정합니다.
Policy — JSON으로 권한 적기 #
정책은 JSON 문서입니다. 이 모양에 익숙해지는 것이 IAM 학습의 80%입니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}읽으면 s3:GetObject 액션을 my-bucket의 모든 객체(*)에 대해 허용한다는 뜻입니다. 각 키의 의미는 다음과 같습니다.
| 키 | 무엇 |
|---|---|
Version | 정책 문법 버전. 항상 2012-10-17 |
Statement | 권한 규칙의 배열 |
Effect | Allow 또는 Deny |
Action | 어떤 API 호출을 허용 / 거부 — <서비스>:<액션> |
Resource | 어떤 리소스에 — ARN으로 |
Condition (옵션) | 추가 조건 — IP, 시간, 태그 등 |
Action의 형식 #
s3:GetObject처럼 <서비스>:<액션> 형식입니다. 와일드카드도 가능합니다.
"Action": "s3:Get*" // s3 의 모든 Get 액션
"Action": "s3:*" // s3 의 모든 액션
"Action": ["s3:GetObject", "s3:PutObject"] // 배열로 여러 개Resource의 형식 #
ARN으로 적습니다. ARN의 모양은 1장에서 봤습니다.
"Resource": "arn:aws:s3:::my-bucket" // 버킷 자체
"Resource": "arn:aws:s3:::my-bucket/*" // 버킷 안의 모든 객체
"Resource": "arn:aws:s3:::my-bucket/uploads/*" // 특정 prefix 만
"Resource": "*" // 모든 리소스 (위험)Condition — 가장 강력한 제어 수단 #
조건이 정책의 진짜 힘을 만드는 부분입니다.
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "arn:aws:s3:::my-bucket/*",
"Condition": {
"IpAddress": {
"aws:SourceIp": ["203.0.113.0/24"]
}
}
}{
"Effect": "Allow",
"Action": "iam:*",
"Resource": "*",
"Condition": {
"Bool": { "aws:MultiFactorAuthPresent": "true" }
}
}자주 쓰는 조건 키는 다음과 같습니다.
| 키 | 무엇 |
|---|---|
aws:SourceIp | 요청 IP |
aws:MultiFactorAuthPresent | MFA 사용 여부 |
aws:RequestTag/<key> | 만들 때 태그 |
aws:ResourceTag/<key> | 리소스 태그 |
aws:CurrentTime | 시간 |
Allow / Deny 평가 순서 #
여러 정책이 겹치면 IAM은 다음 순서로 결정합니다.
1) 명시적 Deny 가 하나라도 있으면 → 거부 (끝)
2) 명시적 Allow 가 하나라도 있으면 → 허용
3) 둘 다 없으면 → 거부 (기본)Deny가 항상 이깁니다. 그래서 “이 사용자는 prod 리소스만은 절대 못 만지게” 같은 가드레일은 Deny로 적습니다. 허용 정책 옆에 Deny를 붙이는 패턴입니다.
User — 사람 / 머신을 위한 영구 자격 #
IAM 사용자는 이메일이 아닌 별도의 ID입니다. 콘솔 로그인 URL도 따로 생깁니다.
https://<계정ID>.signin.aws.amazon.com/console
또는
https://<계정 별칭>.signin.aws.amazon.com/console사용자 만들기 #
콘솔에서 IAM → Users → Add users로 들어갑니다.
| 항목 | 무엇 |
|---|---|
| 사용자 이름 | 이메일이 아님. curtis, dev-bot 같은 식별자 |
| 콘솔 액세스 | 비밀번호 — 사람용 |
| 프로그래밍 액세스 | 액세스 키 — CLI / SDK 용(4장 CLI와 SDK) |
| 권한 | 그룹에 추가, 정책 직접 첨부, 또는 다른 사용자에서 복사 |
모범 사례는 사용자에 정책을 직접 붙이지 않는 것입니다. 그룹을 통해서 붙입니다. 이유는 다음 절에서 다룹니다.
액세스 키 — 사용자가 가진 가장 위험한 자격 증명 #
액세스 키는 두 줄짜리 문자열입니다.
Access Key ID: AKIAIOSFODNN7EXAMPLE
Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY이 둘을 가진 누구나 그 사용자의 모든 권한을 행사할 수 있습니다. 그래서 다음을 지킵니다.
- 사용자 한 명당 액세스 키는 최대 2 개입니다(회전 중 잠시 둘이 공존).
- 절대 git이나 코드에 넣지 않습니다(1장의 루트 키 노출 사례).
- 90일마다 회전합니다(6장 보안 기본에서 자세히 다룹니다).
- 가능하면 사용자 액세스 키 대신 역할(Role)을 씁니다.
Group — 사용자 관리의 단위 #
그룹은 사용자를 묶는 단위입니다. 그룹에 정책을 붙이면 그 그룹의 모든 사용자에게 자동으로 적용됩니다.
Admins → AdministratorAccess
Developers → PowerUserAccess + (IAM 거부 정책)
ReadOnly → ReadOnlyAccess
Billing → 결제 콘솔 접근만왜 사용자에 직접 붙이지 말고 그룹에 붙이는가 #
새 개발자가 입사했다고 해봅시다.
사용자 직접 모델에서는 기존 개발자 한 명을 골라 정책 목록을 따라 붙입니다. 그러다 “저 사람한테 일주일 전에 추가한 정책이 뭐였지?” 하며 누락이 생기고, 시간이 지나면 개발자마다 권한이 미묘하게 달라집니다.
그룹 모델에서는 Developers 그룹에 추가만 하면 끝입니다. 권한 변경은 그룹의 정책만 바꾸면 모두에게 일관 적용되고, 감사와 점검도 그룹 단위로 깔끔합니다.
규칙은 다음과 같습니다. IAM 사용자에는 인라인 정책이나 직접 첨부 정책을 금지하고, 모든 권한은 그룹 또는 역할로 줍니다.
Role — 임시로 빌려 쓰는 자격 #
Role은 누구의 자격이 아니라, 무엇이든 임시로 빌려 쓸 수 있는 자격입니다. 영구 비밀번호나 액세스 키가 없습니다. 대신 누군가 또는 무언가가 AssumeRole이라는 호출을 하면, AWS가 임시 자격(1시간~12시간 유효)을 발급해 줍니다.
이것이 IAM에서 가장 중요한 지점입니다. 처음에는 어렵지만 익숙해지면 IAM의 진짜 힘이 보입니다.
Role이 실제로 쓰이는 경우 #
| 시나리오 | 누가 AssumeRole 하는가 |
|---|---|
| EC2가 S3에 접근 | EC2 인스턴스 (자동으로) |
| Lambda가 DynamoDB에 쓰기 | Lambda (자동으로) |
| ECS Task가 다른 서비스 호출 | Task (자동으로) |
| 다른 AWS 계정 사용자가 이 계정 일부 자원 접근 | 그 사용자가 명시적으로 |
| GitHub Actions가 ECR에 push | OIDC로 GitHub Actions Workflow |
| 임시 권한 상승 (Break-glass) | 사용자가 명시적으로 |
EC2 / Lambda / ECS 같은 환경에서는 AWS가 자동으로 AssumeRole을 해서 자격을 인스턴스에 흘려 줍니다. 코드는 그냥 SDK를 부르면 됩니다. 액세스 키를 다룰 필요가 없습니다. 이것이 핵심입니다.
역할의 두 정책 #
역할에는 두 종류의 정책이 붙습니다.
1) Trust Policy (신뢰 정책) — 누가 이 역할을 빌릴 수 있는지 정합니다.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}]
}Principal 항목에 누가 들어갑니다 — 서비스, 다른 계정, 사용자, OIDC provider 등입니다.
2) Permission Policy (권한 정책) — 빌린 다음 무엇을 할 수 있는지 정합니다.
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}]
}EC2 인스턴스 프로파일 흐름 #
[EC2 인스턴스]
│
│ 1) 인스턴스 메타데이터 (169.254.169.254)에 자격 요청
▼
[IAM]
│ 2) 인스턴스에 붙은 역할의 임시 자격 발급
▼
[EC2 안의 SDK]
│ 3) 자격으로 S3 호출
▼
[S3]EC2 안의 코드는 액세스 키를 모릅니다. boto3나 aws-sdk가 알아서 메타데이터에서 자격을 꺼내 씁니다. 키 노출 사고를 원천적으로 줄여 줍니다.
관리형 정책 vs 인라인 정책 #
정책은 만드는 방식으로 또 나뉩니다.
| 종류 | 무엇 | 추천 |
|---|---|---|
| AWS 관리형 | AWS가 만들어 둔 (예: AdministratorAccess, ReadOnlyAccess) | 입문 / 표준 역할 |
| 고객 관리형 | 내가 만든 정책. 여러 사용자 / 역할에 재사용 가능 | 운영 표준 — 권장 |
| 인라인 | 한 사용자 / 그룹 / 역할에만 직접 부여한 | 비권장 — 재사용 안 됨, 추적 어려움 |
자주 쓰는 AWS 관리형 정책 #
| 이름 | 무엇 |
|---|---|
AdministratorAccess | 모든 권한. 루트 다음으로 위험 |
PowerUserAccess | IAM 빼고 거의 모든 권한 |
ReadOnlyAccess | 모든 서비스 읽기만 |
Billing | 결제 콘솔 |
<Service>FullAccess (예: AmazonS3FullAccess) | 한 서비스 전부 |
<Service>ReadOnlyAccess | 한 서비스 읽기 |
처음에는 관리형으로 시작해 점점 좁혀 고객 관리형으로 옮기는 것이 일반적인 흐름입니다.
운영 권한 설계 — 통하는 패턴 #
작은 팀에서도 통하는 권한 설계의 뼈대입니다.
1) 그룹 4 + 역할 3 #
| 단위 | 이름 | 무엇 |
|---|---|---|
| 그룹 | Admins | AdministratorAccess (MFA 강제) |
| 그룹 | Developers | PowerUserAccess + IAM 거부 |
| 그룹 | ReadOnly | ReadOnlyAccess |
| 그룹 | Billing | 결제 / 비용 |
| 역할 | EC2-AppRole | 앱이 쓰는 역할 (S3, RDS 등) |
| 역할 | Lambda-WorkerRole | 람다용 |
| 역할 | CICDRole | GitHub Actions / CodeBuild가 빌림 |
2) 권한 경계 (Permission Boundary) #
“이 IAM 사용자는 무엇을 하든 이 한도 안에서만"을 정하는 보호막입니다. 신입 개발자가 새 정책을 만들어 자기 권한을 늘리는 사고를 차단합니다.
Developers 그룹 → PowerUserAccess
↓ 그리고 모든 사용자에 권한 경계 부여
권한 경계 → "DevOnly" — dev/* 리소스만 만들 수 있음3) MFA 강제 #
루트와 모든 IAM 사용자에 강제합니다. 강제 정책의 모양은 6장 보안 기본에서 자세히 다룹니다.
4) 사용자 ↔ 역할 분리 #
사용자는 사람만, 머신은 모두 역할로 둡니다. 이것이 명확하면 액세스 키 사고가 거의 나지 않습니다.
5) 조건으로 가드레일 #
{
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": { "aws:ResourceTag/env": "prod" }
}
}태그를 일관되게 쓰면 정책 한 줄로 환경 분리가 됩니다(3장 비용 관리의 태그 전략과 같은 토대입니다).
정책 시뮬레이터 — 검증 도구 #
IAM Policy Simulator(policysim.aws.amazon.com)는 사용자 / 그룹 / 역할에 대해 “이 액션이 가능한가?“를 시뮬레이션해 주는 도구입니다. 정책 변경 후 의도한 대로 됐는지 확인하는 데 씁니다.
1) 사용자 또는 역할 선택
2) 시뮬레이션할 액션 선택 (예: s3:DeleteObject)
3) 리소스 ARN 입력 (선택)
4) "Run Simulation" → Allowed / Denied 와 어떤 정책이 영향을 줬는지6장 보안 기본의 IAM Access Analyzer도 함께 점검에 도움이 됩니다.
IAM 사용자 만들기 — 실습 #
여기까지 왔으면 직접 IAM 사용자 한 명을 만들어 두기를 권합니다. 4장 CLI와 SDK부터는 이 사용자와 역할이 필요합니다.
1. 콘솔 → IAM → Users → Add users
2. 사용자 이름: 본인 이름 (예: curtis)
3. Console access: 활성화, 비밀번호 자동 생성
4. Attach policies directly: AdministratorAccess (학습용 — 나중에 좁히기)
5. 만든 직후 → MFA 즉시 활성화 (강제 방법은 6장)
6. Access keys: CLI 용 한 개만 발급
7. .csv 다운로드 — Secret 은 이 화면에서만 보임이 직후 3장 비용 관리와 6장 보안 기본으로 넘어갑니다.
자주 만나는 함정 #
- 사용자에 정책 직접 첨부 — 10명까지는 괜찮아 보이지만, 30명에서 권한이 미묘하게 달라지기 시작합니다. 침입 시 누구의 권한이 어디까지인지 파악할 수 없습니다. 그룹으로 모이게 합니다.
Resource: "*"의 남발 — 처음에는 편하지만 침입 시 피해 범위가 무한대입니다. 가능한 모든 역할에서 ARN으로 좁힙니다.- 인라인 정책 — 한 번에 박을 땐 빠르지만 한 달 뒤 누가 추가한 정책인지 알 수 없고 재사용도 안 됩니다. 이름이 붙고 버전이 관리되는 고객 관리형 정책으로 옮깁니다.
- 액세스 키를 EC2 안에 직접 부여하기 — EC2 → S3의 자격을 액세스 키로 해결하는 코드는 인스턴스 프로파일(역할)로 옮겨야 합니다. 키 회전을 잊으면 사고가 영원히 잠재합니다.
- “테스트로 만든 사용자"가 그대로 — 전 직원의 액세스 키, 한 번 만들고 잊은 봇 사용자가 남습니다. 30일 / 90일 미사용 사용자는 자동 비활성화 / 삭제 정책을 만들고, IAM Credential Report로 한눈에 확인합니다.
- 루트 사용자에 액세스 키 — 1장의 가장 흔한 사고입니다. 루트는 콘솔과 MFA만, 액세스 키는 절대 만들지 않습니다.
연습문제 #
- §“Allow / Deny 평가 순서"를 근거로, 한 사용자에게
AdministratorAccess가 붙어 있는데도 특정 버킷의 객체를 못 지우게 만들려면 어떤 Statement를 추가해야 하는지 JSON 한 조각으로 적어 보세요. - §“역할의 두 정책"에서 Trust Policy와 Permission Policy가 각각 무엇을 결정하는지 한 문장씩 적고, 4장 CLI와 SDK의
role_arn+source_profile프로파일이 이 중 어느 쪽 흐름을 CLI에서 재현하는지 연결해 보세요. - 본인이 운영할 작은 팀을 가정하고 §“그룹 4 + 역할 3” 표를 본인 환경에 맞게 다시 적어 보세요. 그중 머신용 역할 하나를 골라, 그 역할이 6장 보안 기본의 “사용자 = 사람, 머신 = 역할” 원칙을 어떻게 지키는지 메모해 두세요.
한 줄 요약: IAM은 사용자 · 그룹 · 역할 · 정책의 네 요소로 이뤄지고, 정책이 곧 권한이다. 정책은
Effect+Action+Resource(+Condition)의 JSON이며 Deny가 Allow를 이긴다. 사람은 그룹으로 묶고 머신은 역할로 자격을 받으며, 코드에 키를 넣지 않는 것이 사고를 막는 기본이다.
다음 챕터 #
IAM 사용자가 생겼으니 이제 결제 차례입니다. 처음 며칠 동안 가장 큰 사고는 잠자는 자원이 청구서를 키우는 것입니다. 다음 3장 비용 관리에서는 가입 직후 반드시 켜야 할 결제 알림과 무료 티어 한도 모니터링, 그리고 운영 단계의 Cost Explorer와 태그 전략까지 정리합니다.