개발자나 분석가에게 S3 접근 권한을 줄 때 가장 흔한 실수는 AmazonS3FullAccess를 통째로 붙이는 것입니다. 이 글에서는 버킷 하나의 목록 조회와 객체 읽기만 허용하는 정책을 JSON으로 직접 만들고, 정책 시뮬레이터로 무엇이 허용되고 무엇이 거부되는지 확인합니다. 시뮬레이터를 처음 읽는 분은 IAM 정책 시뮬레이터 글을 먼저 보면 화면이 익숙해집니다.
준비물
| 항목 | 내용 |
|---|---|
| AWS 계정 | 실습용 IAM 사용자. 정책 생성, 조회, 삭제와 정책 시뮬레이터 사용 권한이 필요합니다(필요한 세부 작업 이름은 이 실습에서 확인하지 않았습니다) |
| 정책 이름 | cr-demo-s3-one-bucket-read |
| 대상 버킷 이름 | cr-demo-reports (정책 안의 이름일 뿐, 이 실습에서는 버킷을 만들지 않습니다) |
| 예상 소요 시간 | 약 25분 |
| 변경 사항 | 고객 관리형 정책 1개를 만들고 마지막에 삭제합니다. 어떤 사용자나 역할에도 연결하지 않습니다 |
화면의 계정 정보는 가렸습니다.
1. 정책 편집기에서 JSON 탭 열기
IAM 콘솔에서 정책, 정책 생성을 차례로 누르고 정책 편집기의 JSON 탭을 엽니다. 아래 정책을 편집기에 붙여 넣습니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::cr-demo-reports"
},
{
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::cr-demo-reports/*"
}
]
}
두 문장으로 나눈 이유는 대상이 다르기 때문입니다. s3:ListBucket은 버킷 자체에 대한 작업이라 Resource에 버킷 ARN을 쓰고, s3:GetObject는 버킷 안의 객체에 대한 작업이라 /*를 붙인 객체 ARN을 씁니다.

이 실습에서는 Sid 없이 한 줄로 입력한 JSON을 작업 메뉴의 가독성을 위한 최적화로 펼쳤고, 그러자 Sid 값이 VisualEditor0, VisualEditor1로 채워졌습니다. 위 JSON을 그대로 붙여 넣으면 화면의 줄 구성이나 Sid 표시는 다를 수 있으며 어느 쪽이든 정책 내용은 같습니다.
편집기 아래로 내리면 검사 결과가 보입니다.

보안, 오류, 경고, 추천이 모두 0이면 다음으로 넘어갑니다. 오류가 있으면 이 칸에 줄 번호와 함께 표시됩니다.
2. 이름을 붙이고 요약 확인하기
2단계 검토 및 생성에서 정책 이름과 설명을 입력합니다.
| 화면 | 입력칸 | 입력값 |
|---|---|---|
| 정책 세부 정보 | 정책 이름 | cr-demo-s3-one-bucket-read |
| 정책 세부 정보 | 설명 | Read only access to the cr-demo-reports bucket |

권한 요약에는 S3, 액세스 수준 제한적: 나열, 읽기, 리소스 Multiple이 표시됩니다. 쓰기 수준 작업이 없다는 것을 이 요약에서 한 번 더 볼 수 있습니다. 맨 아래의 정책 생성을 누릅니다.

정책이 만들어지면 정책 이름이 위쪽에 표시되고 연결된 엔터티 탭에서 연결 현황을 볼 수 있습니다. ARN에는 계정 ID가 들어 있어 이미지에서는 가렸습니다.
3. 시뮬레이터에서 허용과 거부 확인하기
정책을 만들었다고 끝내지 않고, 의도한 대로만 허용되는지 시뮬레이터로 확인합니다. IAM 콘솔 왼쪽 메뉴의 정책 시뮬레이터를 열면 별도 페이지가 열립니다. 이 실습 시점에는 영문 화면이었고 위쪽에 새 시뮬레이터 안내가 있었습니다. 사용자에게 연결하지 않고도 시험할 수 있도록 위쪽 Mode를 New Policy로 바꾸고, 왼쪽의 Create New Policy를 눌러 같은 JSON을 한 줄로 붙여 넣은 뒤 Apply를 눌렀습니다(정책 이름은 화면이 임시로 붙인 값이 들어갑니다). 새 시뮬레이터에서 같은 방식이 되는지는 확인하지 않았습니다.
서비스 목록에서 Amazon S3를 고르고, 작업 목록에서 다음 다섯 작업을 선택했습니다.
| 작업 | 시험 목적 | Resource로 지정한 값 |
|---|---|---|
GetObject |
허용되어야 함 | arn:aws:s3:::cr-demo-reports/report.csv |
ListBucket |
허용되어야 함 | arn:aws:s3:::cr-demo-reports |
PutObject |
거부되어야 함 | arn:aws:s3:::cr-demo-reports/report.csv |
DeleteObject |
거부되어야 함 | arn:aws:s3:::cr-demo-reports/report.csv |
ListAllMyBuckets |
거부되어야 함 | 지정하지 않음(기본값 *) |
작업 행을 펼쳐 Add Resource로 ARN을 입력합니다. 시험할 대상을 특정 객체로 정하기 위해 행마다 입력했고, 이 칸을 비워 둔 채 실행하는 시험은 하지 않았습니다. 각 행에 있는 Include Resource Policy 상자는 기본값(선택됨) 그대로 두었습니다. 대상 버킷이 실제로 없으므로 버킷 정책은 적용되지 않았을 것이나, 시뮬레이터가 없는 버킷을 어떻게 처리하는지는 확인하지 않았습니다.

Run Simulation을 누르면 결과가 나옵니다.

허용과 거부가 갈린 이유가 작업 종류 때문이라는 점을 먼저 짚어 둡니다. 이 시험은 쓰기, 삭제, 버킷 목록 작업이 허용되지 않는 것은 보여 주지만 cr-demo-reports가 아닌 다른 버킷이 거부되는지는 보여 주지 않습니다. 그 시험은 하지 않았습니다.
결과는 허용 2건, 거부 3건이었습니다. GetObject와 ListBucket은 일치하는 문 1개로 허용되었고, PutObject, DeleteObject, ListAllMyBuckets는 일치하는 문이 없어 암묵적 거부로 표시되었습니다. 정책에 Deny 문을 쓰지 않았는데도 거부되는 이유는 IAM이 명시적으로 허용하지 않은 작업을 기본적으로 거부하기 때문입니다.
한 가지 짚어 둡니다. 결과 표의 Simulation Resource 열은 이 실습에서 계속 *로 보였습니다. 행을 펼쳐 입력한 ARN은 그 열이 아니라 펼친 행 안에서 확인합니다.
4. 정리: 정책 삭제
정책 목록에서 이름으로 cr-demo를 검색하면 방금 만든 정책 1건만 나옵니다. 그 항목을 선택하고 삭제를 누르면 확인 대화상자가 열립니다.

대화상자 제목과 본문의 이름이 만든 정책 하나와 같은지 확인한 뒤 정책 이름을 입력하고 삭제를 누릅니다.

삭제 전 7번 이미지의 정책 수는 1587개였고 삭제 뒤에는 1586개로 줄었으며 cr-demo 검색 결과는 0건이었습니다.
자주 막히는 곳
- 버킷 ARN과 객체 ARN을 하나로 합치기: S3 작업은 버킷 대상과 객체 대상이 나뉘어 있습니다. 목록 조회는 버킷 ARN, 객체 읽기는
/*가 붙은 ARN으로 나누어 씁니다. 하나로 합쳤을 때의 결과는 이 실습에서 시험하지 않았으니 시뮬레이터로 직접 확인해 보세요. - 시뮬레이터에서 예상과 다르게 거부로 나오는 경우: 시험하지 않았지만 확인해 볼 만한 점은 두 가지입니다. 작업 행마다 시험할 ARN을 입력했는지, 정책의
Resource와 시험 대상 ARN의 버킷 이름과 경로가 같은지입니다. - 이름이 길어 입력칸 오류: 정책 이름은 128자까지, 영문자와 숫자,
+=,.@-_만 쓸 수 있습니다. s3:GetObject만 있고s3:ListBucket이 없는 경우: 객체 이름을 정확히 아는 경우에만 읽을 수 있고 목록은 볼 수 없는 것으로 알려져 있습니다. 이 실습에서 직접 시험한 것은 아닙니다.- 이 정책만으로 부족할 수 있는 경우: S3 콘솔에서 버킷 목록을 열려면
s3:ListAllMyBuckets가 필요하며 이 정책에는 없습니다. KMS 키로 암호화한 객체는kms:Decrypt권한이, 버전 관리를 켠 버킷의 특정 버전은s3:GetObjectVersion권한이 따로 필요합니다. 이 내용은 AWS 문서를 근거로 한 설명이며 이 실습에서 시험하지 않았습니다.
이어서 해 볼 것
- 같은 정책에
Condition을 더해 특정 IP 대역이나 MFA 사용 여부로 한 번 더 좁혀 보기 - 정책을 IAM 사용자 그룹에 연결한 뒤 시뮬레이터의
Existing Policies모드로 같은 결과가 나오는지 비교하기. 같은 시험에 다른 버킷의 객체를 추가해 거부되는지도 확인해 보시기 바랍니다 - S3 버킷 보안 기본값 글의 버킷에 이 정책을 적용해 실제 접근을 시험하기
확인한 범위와 확인하지 않은 것
- 확인한 것: JSON 탭에 정책 붙이기, 검사 결과, 정책 생성과 삭제, 시뮬레이터의 새 정책 모드에서 다섯 작업의 허용과 거부 결과.
- 확인하지 않은 것: 정책을 실제 사용자나 역할에 연결해 S3를 호출하는 것.
cr-demo-reports버킷은 만들지 않았고 실제 객체를 읽거나 쓰는 시험도 하지 않았습니다. 시뮬레이터 결과는 정책 계산이며 버킷 정책이나 조직 정책 같은 다른 요소는 포함하지 않았습니다. - 시뮬레이터 화면은 영문 구버전이었고 상단에 새 시뮬레이터 안내가 표시됩니다. 시점에 따라 화면이 달라질 수 있습니다.
이 글의 다음 단계
- AWS CloudTrail 이벤트 기록에서 누가 언제 무엇을 했는지 읽기CloudTrail 이벤트 기록 화면에서 최근 변경 이벤트를 보고, 리소스 이름으로 걸러 한 보안 그룹의 생성부터 삭제까지를 추적합니다. 이벤트 상세와 JSON 레코드에서 사용자, 시각, 호출 내용, MFA 여부를 읽는 방법을 정리합니다.
- AWS 콘솔에서 EC2에 IAM 역할을 연결해 액세스 키 없이 S3 읽기 권한 주기IAM 콘솔에서 EC2용 역할 cr-demo-ec2-s3-read-role을 만들고 AmazonS3ReadOnlyAccess를 붙인 뒤, EC2 시작 화면의 고급 세부 정보에서 인스턴스에 연결합니다. 신뢰 정책과 권한 정책의 역할을 읽고, 인스턴스와 역할을 삭제해 정리합니다.