AWS 기초 #2 IAM: 사용자, 그룹, 역할, 정책
#1 AWS 입문의 마지막에서 “루트 사용자로 일하지 말자"라고 했습니다. 그러면 누구로 일해야 합니까? 답은 **IAM (Identity and Access Management)**으로 만든 사용자 / 역할입니다.
IAM은 글로벌 서비스입니다. 어느 리전에서 콘솔을 열어도 같은 사용자 / 역할 / 정책이 보입니다. 그리고 무료입니다. 추가 비용 없이 무한정 사용자를 만들 수 있습니다. 그래서 AWS에 처음 들어오면 가장 먼저 만나야 하는 서비스입니다.
이 글에서는 IAM의 4가지 요소를 한 번에 정리하고, 운영 권한 설계의 핵심 패턴까지 살펴보겠습니다.
큰 그림: IAM의 4가지 요소 #
| 요소 | 무엇 | 누가 / 무엇이 쓰는가 |
|---|---|---|
| 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) |
| 권한 | 그룹에 추가, 정책 직접 첨부, 또는 다른 사용자에서 복사 |
모범 사례: 사용자에 정책을 직접 붙이지 말고 그룹을 통해서 붙이세요. 이유는 다음 절에서 설명합니다.
액세스 키: 사용자가 가진 가장 위험한 자격 증명 #
액세스 키는 두 줄짜리 문자열입니다.
Access Key ID: AKIAIOSFODNN7EXAMPLE
Secret Access Key: wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY이 둘을 가진 누구나 그 사용자의 모든 권한을 행사할 수 있습니다. 그래서:
- 사용자 한 명당 액세스 키는 최대 2개 (회전 중 잠시 둘이 공존)
- 절대 git / 코드에 넣지 말 것 (#1 함정 #2 사례)
- 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" }
}
}태그를 일관되게 쓰면 정책 한 줄로 환경 분리가 됩니다.
정책 시뮬레이터: 검증 도구 #
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부터는 이 사용자 / 역할이 필요합니다.
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 보안 기본으로 넘어갑니다.
자주 만나는 함정 #
1) 사용자에 정책 직접 첨부 #
10명까지는 괜찮아 보이지만, 30명에서 권한이 미묘하게 달라지기 시작합니다. 운영 침입 시 누구의 권한이 어디까지인지 파악할 수 없습니다. 그룹으로 모이도록 합니다.
2) Resource: "*"의 남발
#
처음엔 편하지만 침입 시 피해 범위가 무한대가 됩니다. 가능한 모든 역할에서 ARN으로 좁히세요.
3) 인라인 정책 #
한 번에 적용할 땐 빠르지만 한 달 뒤 누가 추가한 정책인지 알 수 없습니다. 재사용도 안 됩니다. 고객 관리형 정책으로 옮기면 이름이 붙고 버전이 관리됩니다.
4) 액세스 키를 EC2 안에 직접 부여하기 #
EC2 → S3의 자격을 액세스 키로 해결하는 코드가 있습니다. **인스턴스 프로파일 (역할)**로 옮겨야 합니다. 키 회전을 잊으면 사고 위험이 영원히 잠재합니다.
5) “테스트로 만든 사용자"가 그대로 #
전 직원의 액세스 키, 한 번 만들고 잊은 봇 사용자가 남습니다. 30일 / 90일 미사용 사용자는 자동 비활성화 / 삭제 정책을 만듭니다. IAM Credential Report로 한눈에 확인할 수 있습니다.
6) 루트 사용자에 액세스 키 #
#1 함정 #2에서 본 가장 흔한 사고입니다. 루트는 콘솔 + MFA만 쓰고, 액세스 키는 절대 만들지 않습니다.
정리 #
이번 글에서 잡은 것:
- IAM의 4가지 구성. User (사람 / 머신 영구 자격), Group (사용자 묶음), Role (임시로 빌려 쓰는 자격), Policy (JSON 권한 문서)로 이뤄집니다.
- 정책의 모양.
Effect+Action+Resource(+Condition)이며, Deny가 Allow를 이깁니다. - 사용자에는 정책을 직접 첨부하지 않고 그룹으로 모읍니다.
- Role의 두 정책. Trust Policy (누가 빌릴 수 있는지)와 Permission Policy (빌린 후 무엇을 할 수 있는지)로 나뉩니다.
- EC2 / Lambda / ECS는 인스턴스 프로파일 / 실행 역할로 자격을 받으므로, 코드에 키를 넣지 않습니다.
- 관리형 vs 인라인. 고객 관리형이 운영 표준입니다.
- 권한 설계 패턴. 그룹 4 + 역할 3, 권한 경계, MFA 강제, 사용자 ↔ 역할 분리, 태그 + Condition 가드레일을 씁니다.
- 함정. 사용자 직접 정책,
Resource:*, 인라인 정책, EC2 안 액세스 키, 잠자는 사용자, 루트 키입니다.
다음: 비용 관리 #
IAM 사용자가 생겼으니 이제 결제 차례입니다. 처음 며칠 동안 가장 큰 사고는 잠자는 자원이 청구서를 키우는 것입니다.
#3 비용 관리: 결제 알림, Cost Explorer, 무료 티어에서는 가입 직후 반드시 켜야 할 결제 알림과 무료 티어 한도 모니터링, 그리고 운영 단계의 Cost Explorer / 태그 전략까지 정리하겠습니다.