AWS에서 권한 문제가 생기면 가장 먼저 열어 보는 것이 IAM 정책입니다. 콘솔에서 AdministratorAccess 같은 관리형 정책을 붙이면 당장은 편합니다. 하지만 정책 문서가 실제로 무엇을 허용하는지 읽지 못하면 필요 이상으로 넓은 권한을 주게 되고, 반대로 요청이 왜 거부되는지 원인을 찾지 못해 시간을 허비하게 됩니다.
IAM 정책은 JSON 형식의 문서이고, 구조는 생각보다 단순합니다. 정해진 몇 개의 요소가 같은 의미로 반복될 뿐이라, 요소별 역할과 평가 순서만 이해하면 처음 보는 정책도 한 줄씩 해석할 수 있습니다.
이 글에서는 정책 문서의 기본 구조, Effect·Action·Resource·Condition 각 요소의 의미, 여러 정책이 겹칠 때 최종 허용 여부가 정해지는 순서, 그리고 최소 권한 원칙에 맞게 정책을 좁혀 가는 방법을 차례로 정리합니다.
결론부터 말씀드리면 AWS는 명시적으로 허용되지 않은 요청을 모두 거부하고, 어느 정책에서든 명시적 거부(Deny)가 있으면 다른 곳의 허용보다 우선합니다. 그래서 정책을 읽을 때는 어떤 작업을, 어떤 리소스에, 어떤 조건에서 허용하거나 거부하는지를 차례로 확인하면 됩니다.

정책 문서는 Version과 Statement로 이루어집니다
IAM 정책 문서의 가장 바깥에는 Version과 Statement 두 요소가 있습니다. Version은 정책 언어의 버전을 나타내며, 현재 쓰는 값은 2012-10-17입니다. 이 날짜는 정책을 작성한 날이 아니라 정책 문법의 버전 이름이므로 오늘 날짜로 바꾸면 안 됩니다. 이전 버전인 2008-10-17을 쓰면 정책 변수 같은 일부 기능이 동작하지 않습니다.
Statement는 권한 규칙을 담는 배열입니다. 규칙 하나하나를 문(statement)이라고 부르며, 각 문에는 Sid(선택 사항인 식별 이름), Effect, Action, Resource, Condition 같은 요소가 들어갑니다. 한 정책 안에 여러 문을 넣을 수 있고, 각 문은 독립적으로 평가됩니다.
아래는 특정 S3 버킷의 목록 조회와 파일 읽기만 허용하는 정책 예시입니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListReportBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::kimstips-report"
},
{
"Sid": "ReadReportObjects",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::kimstips-report/*"
}
]
}
문이 두 개로 나뉜 이유가 중요합니다. s3:ListBucket은 버킷 자체에 대한 작업이라 버킷 ARN을 대상으로 하고, s3:GetObject는 버킷 안의 객체에 대한 작업이라 버킷 이름 뒤에 /*가 붙은 객체 ARN을 대상으로 합니다. 두 작업을 한 문에 넣고 버킷 ARN만 적으면 목록은 보이는데 파일은 열리지 않는 문제가 생깁니다.
정책은 Version과 Statement 배열로 구성되고, Version은 2012-10-17을 그대로 쓰며, 작업마다 대상 리소스의 형태가 다르면 문을 나눠 적는 것이 정확합니다.
Effect, Action, Resource가 권한의 뼈대입니다
Effect는 Allow 또는 Deny 둘 중 하나입니다. Action은 서비스 접두사와 작업 이름을 콜론으로 이은 형태로 적습니다. s3:GetObject, ec2:StartInstances, iam:CreateUser처럼 읽으면 어느 서비스의 어떤 API인지 바로 알 수 있습니다. s3:Get*처럼 별표를 쓰면 Get으로 시작하는 모든 작업을 뜻합니다.
Resource는 작업 대상을 ARN(Amazon Resource Name)으로 지정합니다. ARN은 arn:파티션:서비스:리전:계정ID:리소스 순서로 구성됩니다. 다만 S3 버킷처럼 이름이 전 세계에서 고유한 리소스는 리전과 계정 ID 칸이 비어 있습니다. 또 ec2:DescribeInstances처럼 특정 리소스를 지정할 수 없는 작업은 Resource에 별표(*)를 써야 동작합니다.
| 요소 | 의미 | 예시 | 읽을 때 주의점 |
|---|---|---|---|
| Effect | 허용 또는 거부 | Allow, Deny | Deny는 다른 모든 Allow보다 우선 |
| Action | 허용·거부할 API 작업 | s3:GetObject, ec2:* | 별표가 들어가면 범위가 급격히 넓어짐 |
| Resource | 작업 대상 ARN | arn:aws:s3:::bucket/* | 버킷과 객체 ARN을 구분해야 함 |
| Condition | 추가 조건 | aws:SourceIp, aws:RequestedRegion | 여러 조건은 모두 만족해야 적용 |
| Principal | 권한을 받는 주체 | 다른 계정, 서비스 | 버킷 정책 같은 리소스 기반 정책에서만 사용 |
Principal은 사용자나 역할에 붙이는 자격 증명 기반 정책에는 쓰지 않습니다. 정책이 붙은 대상이 곧 주체이기 때문입니다. 반면 S3 버킷 정책처럼 리소스에 붙이는 리소스 기반 정책에서는 누구에게 허용할지를 Principal로 반드시 지정해야 합니다.
Action과 Resource에 동시에 별표가 들어간 문은 사실상 전체 관리자 권한이므로, 정책을 검토할 때 가장 먼저 찾아서 범위를 좁혀야 합니다.
Condition으로 허용 범위를 한 번 더 좁힙니다
Condition은 요청이 특정 조건을 만족할 때만 문을 적용하게 만드는 요소입니다. 조건 연산자와 조건 키, 값으로 구성됩니다. 조건 연산자에는 문자열을 비교하는 StringEquals와 StringLike, IP 대역을 비교하는 IpAddress, 참·거짓을 보는 Bool 등이 있습니다.
조건 키는 모든 서비스에 공통인 전역 키와 서비스별 키로 나뉩니다. 자주 쓰는 전역 키로는 요청을 보낸 IP를 뜻하는 aws:SourceIp, 요청 대상 리전을 뜻하는 aws:RequestedRegion, MFA 인증 여부를 뜻하는 aws:MultiFactorAuthPresent가 있습니다.
조건이 여러 개일 때의 규칙도 알아두어야 합니다. 한 Condition 블록 안에 서로 다른 조건 연산자나 조건 키가 여러 개 있으면 모두 만족해야 합니다(AND). 반면 하나의 조건 키에 값을 여러 개 적으면 그중 하나만 맞아도 됩니다(OR).
예를 들어 서울 리전 이외의 작업을 막으려고 aws:RequestedRegion이 ap-northeast-2가 아니면 거부하는 문을 만들 수 있습니다. 이때 IAM이나 CloudFront, Route 53처럼 특정 리전에 속하지 않는 글로벌 서비스는 요청이 서울 리전으로 들어오지 않습니다. 그래서 이런 서비스를 예외로 빼지 않으면 필요한 작업까지 함께 막히게 됩니다.
Condition은 서로 다른 조건끼리는 AND, 한 키의 여러 값끼리는 OR로 평가되며, 리전 제한 조건은 글로벌 서비스를 예외로 두어야 의도대로 동작합니다.
여러 정책이 겹칠 때 허용 여부가 정해지는 순서
실제 계정에서는 한 사용자나 역할에 여러 정책이 동시에 적용됩니다. 사용자에게 직접 붙은 정책, 그룹 정책, 버킷 정책, 조직의 서비스 제어 정책(SCP)이 한꺼번에 평가되는 식입니다. AWS는 이 정책들을 모두 모아 아래 원칙으로 최종 결과를 정합니다.

첫째, 기본값은 거부입니다. 어떤 정책도 허용하지 않은 요청은 거부되며, 이를 암묵적 거부라고 합니다. 둘째, 적용되는 정책 중 하나라도 명시적 Deny가 있으면 다른 곳에 Allow가 있어도 최종 결과는 거부입니다. 셋째, 같은 계정 안에서는 자격 증명 기반 정책과 리소스 기반 정책 중 어느 한쪽에서만 허용해도 요청이 허용됩니다.
여기에 상한선 역할을 하는 정책이 더해집니다. 권한 경계(permissions boundary)와 조직의 SCP는 권한을 새로 부여하지 않고, 허용될 수 있는 최대 범위만 정합니다. 그래서 자격 증명 기반 정책이 허용하더라도 권한 경계나 SCP 범위 밖의 작업은 거부됩니다. 결과적으로는 두 정책이 모두 허용하는 교집합만 쓸 수 있습니다.
| 정책 종류 | 붙는 곳 | 역할 |
|---|---|---|
| 자격 증명 기반 정책 | 사용자, 그룹, 역할 | 권한 부여 |
| 리소스 기반 정책 | S3 버킷, KMS 키 등 | 권한 부여(다른 계정 허용 포함) |
| 권한 경계 | 사용자, 역할 | 최대 범위 제한 |
| 서비스 제어 정책(SCP) | 조직의 계정, 조직 단위 | 계정 전체의 최대 범위 제한 |
| 세션 정책 | 역할 전환 시 임시 세션 | 해당 세션의 최대 범위 제한 |
허용은 부여 정책 어딘가에 Allow가 있고, 상한선 정책의 범위 안이며, 어디에도 Deny가 없을 때만 성립합니다.
최소 권한으로 정책을 좁혀 가는 방법
최소 권한 원칙은 작업에 꼭 필요한 권한만 주는 것입니다. 처음부터 완벽한 정책을 쓰기는 어렵기 때문에, AWS도 관리형 정책으로 시작한 뒤 실제 사용 기록을 보면서 직접 관리하는 고객 관리형 정책으로 좁혀 가는 방식을 권장합니다.
| 단계 | 도구 | 확인할 내용 |
|---|---|---|
| 1. 작성 직후 검사 | IAM Access Analyzer 정책 검증 | 문법 오류, 보안 경고, 권장 사항 |
| 2. 사용 기록 기반 생성 | Access Analyzer 정책 생성 | CloudTrail 기록에 실제로 나온 작업만 추린 초안 |
| 3. 쓰지 않는 권한 정리 | 마지막 액세스 정보 | 오랫동안 호출하지 않은 서비스와 작업 |
| 4. 거부 원인 확인 | IAM 정책 시뮬레이터 | 특정 작업이 허용되는지, 어느 문 때문인지 |
고객 관리형 정책은 여러 사용자와 역할에 재사용할 수 있고, 버전이 최대 다섯 개까지 보관되어 이전 버전으로 되돌리기도 쉽습니다. 한 사용자에게만 필요한 예외적인 권한이 아니라면 인라인 정책보다 관리형 정책으로 관리하는 편이 추적하기 좋습니다.
사람보다 프로그램이 쓰는 권한을 먼저 점검하는 것도 효과적입니다. 서버나 배포 도구에 장기 액세스 키를 넣어 두기보다는 EC2 인스턴스 프로파일이나 역할을 사용해 임시 자격 증명을 쓰게 하면, 키 유출 위험 자체를 줄일 수 있습니다.
최소 권한은 한 번에 완성하는 것이 아니라 검증, 사용 기록 기반 생성, 미사용 권한 정리를 반복하면서 좁혀 가는 과정입니다.
정책 읽기 핵심 정리
IAM 정책은 Version과 Statement로 구성되며, 각 문은 Effect, Action, Resource, Condition으로 어떤 작업을 어떤 대상에 어떤 조건에서 허용하거나 거부할지 정합니다. 기본값은 거부이고, 명시적 Deny는 모든 Allow보다 우선하며, 권한 경계와 SCP는 권한을 주지 않고 최대 범위만 제한합니다. 관리형 정책으로 시작하되 Access Analyzer와 마지막 액세스 정보를 활용해 실제로 쓰는 권한만 남기는 것이 안전합니다.
자주 묻는 질문
Version 값을 최신 날짜로 바꿔야 하나요?
바꾸지 않습니다. 2012-10-17은 정책 언어의 버전 이름이고, 현재 사용하는 최신 버전입니다. 정책을 새로 쓸 때도 이 값을 그대로 적습니다.
정책을 수정하면 바로 반영되나요?
IAM은 여러 지역에 복제되는 서비스라 변경 사항이 반영되기까지 짧은 지연이 생길 수 있습니다. 수정 직후 테스트 결과가 이전과 같다면 잠시 뒤 다시 확인해 보세요.
AccessDenied 오류의 원인은 어떻게 찾나요?
오류 메시지에 거부된 작업 이름과 대상 리소스가 표시되는 경우가 많습니다. 그 작업과 리소스를 IAM 정책 시뮬레이터에 넣어 보면 어떤 정책의 어느 문 때문에 거부되는지 확인할 수 있습니다. 조직에 속한 계정이라면 SCP도 함께 확인해야 합니다.
그룹 정책과 사용자 정책이 서로 다르면 어떻게 되나요?
둘 다 자격 증명 기반 정책으로 함께 평가됩니다. 어느 한쪽에서 허용하면 허용되지만, 어느 한쪽에 명시적 Deny가 있으면 거부됩니다.
정책 문서는 처음에는 기호가 많아 어려워 보이지만, 읽는 순서만 익히면 권한 문제를 추측이 아니라 근거로 해결할 수 있게 됩니다.
지금 사용 중인 IAM 사용자나 역할 하나를 골라 붙어 있는 정책을 열어 보세요. Action과 Resource에 별표가 함께 들어간 문이 있는지, 마지막 액세스 정보에서 몇 달째 쓰지 않은 서비스가 있는지부터 확인해 보시길 권해드립니다.
함께 읽으면 좋은 글: AWS 루트 계정 MFA 설정과 IAM 권한 분리 / 클라우드 공동 책임 모델
참고 자료: IAM JSON 정책 요소 참조, IAM 정책 평가 로직, IAM 보안 모범 사례
※ 본 글은 2026년 9월 기준 AWS IAM 사용 설명서의 정책 요소, 정책 평가 로직, 보안 모범 사례 문서를 참고해 작성했으며, 기능과 콘솔 화면은 변경될 수 있으니 최신 내용은 AWS 공식 문서에서 확인해 주세요.
'IT 클라우드 정보' 카테고리의 다른 글
| 클라우드 비용 할당 태그 전략과 Cost Explorer로 서비스별 요금 분석하는 방법 (0) | 2026.09.27 |
|---|---|
| AWS 퍼블릭 IPv4 주소 요금과 미사용 탄력적 IP EBS 볼륨 정리로 숨은 비용 찾는 법 (0) | 2026.09.26 |
| 클라우드 데이터 전송 비용 egress가 비싼 이유와 CDN으로 줄이는 방법 (0) | 2026.09.25 |
| Docker 컨테이너와 쿠버네티스 차이 클라우드 관리형 서비스 EKS GKE AKS 비교 (0) | 2026.09.24 |
| 서버리스 AWS Lambda 개념과 콜드 스타트 원인 그리고 적합한 사용 사례 (0) | 2026.09.23 |