데이터 유출 사고 뉴스에 빠지지 않고 등장하는 단어가 "공개로 설정된 S3 버킷"입니다. 대부분 해킹이 아니라 권한 설정 실수입니다. S3 접근 권한은 여러 층이 겹쳐 평가되기 때문에, 각 층이 무슨 역할을 하는지 모르면 자기도 모르게 버킷을 열어두게 됩니다.
S3 권한을 결정하는 층
| 층 | 적용 범위 | 용도 |
|---|---|---|
| IAM 정책 | 사용자·역할 단위 | "이 사용자가 어떤 버킷에 뭘 할 수 있나" |
| 버킷 정책 | 버킷 단위 | "이 버킷에 누가 접근 가능한가" |
| ACL | 버킷·객체 단위(레거시) | 객체별 세밀 권한, 가급적 비활성 권장 |
| 퍼블릭 액세스 차단 | 계정·버킷 단위 | 위 설정과 무관하게 공개를 강제 차단 |
핵심은 명시적 거부가 항상 우선한다는 점입니다. 그래서 "퍼블릭 액세스 차단"을 켜두면 버킷 정책에 실수로 공개 규칙을 넣어도 외부 공개가 막힙니다.
버킷이 공개되는 흔한 경로
Principal: "*"버킷 정책 — "누구나"에게s3:GetObject를 허용. 정적 사이트 호스팅하다 그대로 두는 경우가 많습니다.- 레거시 ACL의
AllUsers— 콘솔 클릭 한 번으로 객체가 전체 공개됩니다. - 계정 단위 퍼블릭 차단 해제 — 한 버킷 때문에 계정 전체 차단을 끄면 다른 버킷까지 노출됩니다.
JSON
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-bucket/*"
}
위 정책은 버킷 전체를 누구나 읽을 수 있게 만듭니다. 정말 공개가 필요한 정적 자산만 별도 버킷에 분리하고, 나머지는 절대 이 패턴을 쓰지 않습니다.
안전하게 설정하는 순서
- 퍼블릭 액세스 차단을 계정·버킷 모두 ON으로 두고 시작합니다.
- ACL은 비활성(버킷 소유자 강제)으로 두고 권한은 정책으로만 관리합니다.
- 내부 접근은 IAM 역할로 부여하고, 최소 권한(필요한 액션·버킷만)을 적용합니다.
- 외부에 파일을 잠깐 줘야 하면 공개 대신 **사전 서명 URL(presigned URL)**로 만료 시간을 둡니다.
- 정기적으로 공개 여부를 점검합니다(
aws s3api get-bucket-policy-status).
요점 정리
- S3 권한은 IAM·버킷 정책·ACL·퍼블릭 차단이 겹쳐 평가되고, 거부가 우선.
- "퍼블릭 액세스 차단"을 기본 ON으로 두는 것이 사고 예방의 핵심.
- 외부 공유는 공개 대신 사전 서명 URL, 내부는 최소 권한 IAM 역할.
IAM 정책과 버킷 권한을 직접 만들어 보고 공개 여부를 점검하는 실습은 클라우드 트랙에서 회원가입 없이 무료로 할 수 있습니다.