S3는 HTTPS와 HTTP 둘 다로 요청을 받을 수 있고, 버킷 정책에 aws:SecureTransport 조건을 넣으면 HTTPS가 아닌 요청을 거부할 수 있습니다(AWS 문서 기준, 아래 확인 범위에 링크). 이 글은 정책을 저장하는 데까지만 다루며 HTTP 요청이 실제로 거부되는지는 시험하지 않았습니다. 이 글에서는 빈 버킷을 하나 만들어 그 정책을 직접 입력하고 저장한 뒤, 콘솔에 표시되는 모습까지 확인합니다. 버킷의 다른 보안 기본값은 S3 버킷 보안 기본값 글에서 다룹니다.
준비물
| 항목 | 내용 |
|---|---|
| AWS 계정 | 실습용 IAM 사용자. 버킷 생성, 버킷 정책 편집, 삭제 권한 필요 |
| 리전 | 아시아 태평양(서울) ap-northeast-2 |
| 버킷 이름 | cr-demo-policy-1018. 이름이 이미 쓰이고 있으면 끝의 숫자를 바꿉니다 |
| 예상 소요 시간 | 약 20분 |
| 변경 사항 | 버킷 1개 생성과 버킷 정책 저장. 마지막에 버킷을 삭제합니다 |
화면의 계정 정보는 가렸습니다.
1. 버킷 만들기
S3 콘솔 위쪽에서 리전을 아시아 태평양(서울)로 바꾼 뒤 버킷 만들기를 누르고 이름에 cr-demo-policy-1018을 입력한 뒤 나머지는 기본값으로 만듭니다.

2. 비어 있는 버킷 정책 확인하기
버킷을 열고 권한 탭을 아래로 내려 버킷 정책 칸을 봅니다.

새 버킷에는 정책이 없습니다. 위쪽 파란 상자는 이 버킷의 퍼블릭 액세스 차단 설정이 켜져 있다는 안내입니다. 이 설정과 방금 만들 정책은 서로 다른 장치입니다. 퍼블릭 액세스 차단은 외부 공개를 막고, 이 글의 정책은 전송 방식(HTTP인지 HTTPS인지)을 조건으로 거부합니다. 편집을 누릅니다.

편집 화면 위쪽에 버킷 ARN이 표시됩니다. 정책 안의 Resource에 이 ARN을 그대로 씁니다. 오른쪽 위에는 외부 링크 모양의 정책 예제 단추가 있습니다. 이 단추는 누르지 않았습니다.
3. 정책 입력하기
편집기의 내용을 모두 지우고 아래 정책을 붙여 넣습니다. 버킷 이름을 바꿨다면 Resource의 두 ARN도 같은 이름으로 고칩니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::cr-demo-policy-1018",
"arn:aws:s3:::cr-demo-policy-1018/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
| 항목 | 값 | 의미 |
|---|---|---|
| Effect | Deny |
조건에 맞으면 거부합니다 |
| Principal | * |
모든 요청자가 대상입니다 |
| Action | s3:* |
이 버킷에 대한 모든 S3 작업이 대상입니다 |
| Resource | 버킷 ARN과 /* |
버킷 자체와 안의 객체 모두입니다 |
| Condition | aws:SecureTransport가 false |
HTTPS가 아닌 요청일 때만 위 거부가 적용됩니다 |
이 실습에서는 같은 내용을 한 줄로 입력했습니다. 입력한 뒤 편집기 아래쪽의 검사 칸을 확인합니다. 아래 화면은 편집기를 아래로 스크롤한 상태라 입력한 글자는 보이지 않고, 입력한 정책은 5번 화면에서 볼 수 있습니다.

보안, 오류, 경고, 추천이 모두 0이었습니다. 변경 사항 저장을 누릅니다.
4. 저장된 정책 읽기
저장하면 초록 알림 버킷 정책을 편집했습니다.가 나오고 권한 탭의 버킷 정책 칸에 정책이 표시됩니다.

한 줄로 입력한 정책이 콘솔에서는 줄 단위로 정리되어 표시되었습니다. 표시된 내용은 위에 적은 정책과 같습니다. 이 칸에서 편집으로 다시 고치거나 삭제로 정책을 지울 수 있습니다.
5. 정리: 버킷 삭제
버킷 목록에서 cr-demo-policy-1018만 선택하고 삭제를 누릅니다.

화면 제목의 버킷 이름이 지우려는 버킷과 같은지 확인한 뒤 이름을 입력하고 버킷 삭제를 누릅니다.

삭제 뒤 목록에는 이미 있던 버킷 1개가 남았고, 이름은 가렸습니다. 이 버킷은 이 실습에서 다루지 않았습니다.
자주 막히는 곳
- 정책이 저장되지 않는 경우: 이 실습에서는 오류 상황을 만들지 않았습니다. 편집기 아래 검사 칸의 오류 표시를 먼저 확인하고 따옴표와 쉼표를 점검합니다.
- Resource를 버킷 ARN 하나만 쓰는 경우: AWS 문서 기준으로
s3:ListBucket같은 버킷 대상 작업은 버킷 ARN에,s3:GetObject같은 객체 대상 작업은/*가 붙은 ARN에 일치합니다. 그래서 이 글의 정책은 두 ARN을 모두 썼습니다. 하나만 쓴 경우는 시험하지 않았습니다. - HTTP 요청이 정말 막히는지 궁금한 경우: 이 글에서는 시험하지 않았습니다. 아래 "이어서 해 볼 것"에 시험 방법을 적었습니다.
s3:*거부의 범위: AWS 문서 기준으로 명시적 거부는 허용보다 우선합니다. 조건에 맞는 요청은 요청자의 권한과 관계없이 거부되므로, HTTP로 접속하는 기존 도구가 있는지 먼저 확인한 뒤 적용합니다. 이 정책이 거부하는 것은 HTTP 요청뿐이라 HTTPS인 콘솔에서는 정책을 계속 고칠 수 있습니다(문서 기준).
이어서 해 볼 것
- 버킷에 객체 하나를 올리고 HTTPS와 HTTP로 각각 요청해 응답을 비교하기. 객체 공개가 꺼져 있으면 익명 요청은 둘 다 거부로 보일 수 있으니 서명된 요청으로 시험합니다. AWS CLI는 기본이 HTTPS이므로 HTTP를 시험하려면
--endpoint-url http://s3.ap-northeast-2.amazonaws.com처럼 주소를 직접 지정합니다. 이 방법은 이 글에서 실행하지 않았고, 기대 결과(HTTP는 AccessDenied)도 문서 기준입니다 - 같은 정책을 IAM 정책 시뮬레이터 글의 방식으로 시뮬레이터에 넣어
aws:SecureTransport값을 바꿔 가며 결과를 비교하기 - 버킷에 정책을 저장한 뒤 CloudTrail 이벤트 기록에서
PutBucketPolicy이벤트가 남았는지 확인하기. 이벤트가 나타나기까지 시간이 걸릴 수 있습니다(문서 기준). 읽는 방법은 CloudTrail 이벤트 기록 글에 있습니다
확인한 범위와 확인하지 않은 것
- 확인한 것: 버킷 생성, 빈 버킷 정책 화면, 정책 입력과 검사 결과, 저장 후 표시되는 정책, 버킷 삭제.
- 확인하지 않은 것: HTTP 요청이 실제로 거부되는지, 정책이 다른 문과 함께 있을 때의 동작,
Resource구성에 따른 차이. 정책 의미 설명(명시적 거부 우선, 조건 키의 의미, Resource 대응)은 AWS 문서에 근거한 것이며 이 실습에서 직접 시험하지 않았습니다. 근거 문서: 버킷 정책 예시(HTTPS 요청만 허용), S3 보안 모범 사례, 정책 평가 로직, S3 작업과 리소스 유형. 화면 문구는 이 실습 시점의 한국어 콘솔 기준입니다.
이 글의 다음 단계
- AWS CloudTrail 이벤트 기록에서 누가 언제 무엇을 했는지 읽기CloudTrail 이벤트 기록 화면에서 최근 변경 이벤트를 보고, 리소스 이름으로 걸러 한 보안 그룹의 생성부터 삭제까지를 추적합니다. 이벤트 상세와 JSON 레코드에서 사용자, 시각, 호출 내용, MFA 여부를 읽는 방법을 정리합니다.
- AWS 콘솔에서 EC2에 IAM 역할을 연결해 액세스 키 없이 S3 읽기 권한 주기IAM 콘솔에서 EC2용 역할 cr-demo-ec2-s3-read-role을 만들고 AmazonS3ReadOnlyAccess를 붙인 뒤, EC2 시작 화면의 고급 세부 정보에서 인스턴스에 연결합니다. 신뢰 정책과 권한 정책의 역할을 읽고, 인스턴스와 역할을 삭제해 정리합니다.