Taking a Policy JSON Apart Line by Line
한국어 원문으로 표시합니다.
한 줄 요약
정책은 결국 네 가지를 적는 문서입니다 — 무엇을(Action) 어디에(Resource) 허용/거부(Effect) 하며, 어떤 조건에서(Condition).
왜 이게 필요했나
정책은 문법상 유효해도 의도보다 넓게 열릴 수 있습니다. 허용 효과만 확인하고 자원 범위와 조건을 읽지 않으면 리뷰를 통과한 정책이 곧 권한 상승 경로가 됩니다. 그래서 정책을 구성 요소별로 분해하고 위험한 조합을 일정한 순서로 읽어야 합니다.
어떻게 동작하나
최소 형태
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadReportsOnly",
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::acme-reports",
"arn:aws:s3:::acme-reports/*"
]
}
]
}
Version 은 날짜처럼 보이지만 정책 언어의 버전입니다. 2012-10-17 을
그대로 씁니다. 바꾸면 변수 치환 같은 기능이 사라집니다.
Resource 가 두 줄인 이유
이게 초보자가 가장 많이 틀리는 자리입니다.
arn:aws:s3:::acme-reports— 버킷 자체.ListBucket이 여기에 필요합니다.arn:aws:s3:::acme-reports/*— 버킷 안의 객체.GetObject가 여기에 필요합니다.
둘은 다른 자원입니다. 하나만 적으면 "목록은 보이는데 파일이 안 열린다" 또는 그 반대가 됩니다.
ARN 의 구조
arn:aws:s3:::acme-reports/reports/2026/*
│ │ │ │ │ └ 자원 경로
│ │ │ │ └ 계정 ID (S3 는 비움)
│ │ │ └ 리전 (S3 는 전역이라 비움)
│ │ └ 서비스
│ └ 파티션 (aws / aws-cn / aws-us-gov)
└ 고정
빈 칸이 있는 게 오타가 아니라 그 서비스가 전역이라는 뜻입니다.
와일드카드 — 위험은 자리에 따라 다르다
| 표현 | 의미 | 위험도 |
|---|---|---|
"Action": "s3:Get*" |
읽기 계열 전부 | 낮음 |
"Action": "s3:*" |
S3 의 모든 동작 (삭제 포함) | 높음 |
"Action": "*" |
모든 서비스의 모든 동작 | 관리자 |
"Resource": "*" |
모든 자원 | 문맥에 따라 |
"Action": "*" 와 "Resource": "*" 가 한 문장에 같이 있으면 그건 관리자
권한입니다. 정책 리뷰에서 가장 먼저 찾아야 할 조합입니다.
Condition — 진짜 좁혀지는 자리
권한을 좁히는 가장 강력한 수단인데 가장 덜 쓰입니다.
"Condition": {
"IpAddress": { "aws:SourceIp": ["203.0.113.0/24"] },
"Bool": { "aws:SecureTransport": "true" },
"StringEquals": { "aws:PrincipalTag/team": "platform" },
"DateLessThan": { "aws:CurrentTime": "2026-12-31T00:00:00Z" }
}
- 사무실 IP 에서만
- HTTPS 로만 (이거 하나로 평문 접근이 막힙니다)
- 특정 팀 태그를 가진 주체만
- 만료일까지만 — 임시 접근에 특히 유용합니다
한 Condition 블록 안의 여러 키는 AND 로 묶이고, 한 키에 값이 여러 개면
OR 입니다. 이 규칙을 헷갈리면 의도와 정반대의 정책이 나옵니다.
NotAction 은 함정이다
{ "Effect": "Allow", "NotAction": "iam:*", "Resource": "*" }
"IAM 빼고 전부 허용" 으로 읽히지만, 실제로는 앞으로 생길 모든 신규 서비스도 자동 허용됩니다. 화이트리스트가 아니라 블랙리스트라서 그렇습니다. 권한은 항상 허용 목록으로 적습니다.
읽는 순서
리뷰할 때 이 순서로 보면 빠릅니다.
Effect: Deny문장부터 — 무엇이 절대 막혀 있나Action에*이 있나Resource에*이 있나Condition이 있나 — 없으면 그 권한은 어디서든 통한다NotAction/NotResource가 있나 — 있으면 의심한다
현장에서 만나는 모습
- 목록은 보이는데 다운로드가 안 됨 →
Resource에/*이 빠졌다. - 정책은 맞는데 막힘 → 상위 조직 정책의 Deny 또는 권한 경계.
s3:*로 붙여 놓고 잊음 → 삭제 권한까지 열려 있다.
다음에 볼 것
장기 키를 나눠 주지 않고도 권한을 주는 방법 — 역할과 임시 자격증명입니다.