S3 퍼블릭 액세스 차단(Block Public Access)이 객체 공개 설정을 무력화하는 이유

S3에 이미지를 업로드하고 객체 ACL을 'public-read'로 설정했는데도 URL로 접근하면 'Access Denied'가 반환되는 상황은 AWS를 처음 다루는 엔지니어뿐 아니라 경험 있는 팀에서도 자주 마주치는 문제다. 원인은 대부분 하나다 — 버킷 수준의 'Block Public Access' 설정이 객체 ACL보다 상위에서 동작하기 때문이다.

TL;DR — S3 퍼블릭 액세스 차단 문제 요약

확인 항목예상 상태실제 차단 원인
객체 ACLpublic-read 설정됨Block Public Access가 ACL을 무시함
버킷 Block Public Access기본값: 모두 활성화4가지 설정 중 하나라도 켜져 있으면 퍼블릭 접근 차단
버킷 정책없거나 Allow 없음ACL 없이 정책만으로 퍼블릭 접근 허용 가능
계정 수준 Block Public Access기본값: 모두 활성화버킷 설정보다 상위에서 적용됨

S3 퍼블릭 액세스 제어 계층 구조 이해

S3의 접근 제어는 단일 설정이 아니라 여러 계층이 순서대로 평가되는 구조다. 객체 ACL을 'public-read'로 바꾸는 것은 가장 하위 계층을 건드리는 것이고, 그 위에 버킷 정책, 버킷 Block Public Access, 계정 수준 Block Public Access가 차례로 쌓여 있다. 상위 계층이 'Deny'를 내리면 하위 계층의 'Allow'는 효력이 없다.

AWS는 2018년 이후 신규 버킷 생성 시 Block Public Access 4가지 옵션을 모두 활성화한다. 이 기본값은 의도치 않은 데이터 노출을 막기 위한 것이지만, 퍼블릭 접근이 필요한 정적 웹사이트 호스팅이나 공개 이미지 서빙 시나리오에서는 직접 해제해야 한다.

graph TD A["클라이언트 GET 요청"] --> B["계정 수준 Block Public Access"] B -- "차단 설정 true" --> Z1["403 Access Denied"] B -- "차단 설정 false" --> C["버킷 수준 Block Public Access"] C -- "IgnorePublicAcls=true 또는 RestrictPublicBuckets=true" --> Z2["403 Access Denied"] C -- "모두 false" --> D["버킷 정책 평가"] D -- "Explicit Deny" --> Z3["403 Access Denied"] D -- "Allow 존재" --> Y1["200 OK"] D -- "Allow 없음" --> E["객체 ACL 평가"] E -- "public-read" --> Y2["200 OK"] E -- "ACL 없음" --> Z4["403 Access Denied"]
  1. 요청 진입: 클라이언트가 S3 객체 URL로 GET 요청을 보낸다.
  2. 계정 수준 Block Public Access 평가: AWS Organizations 또는 계정 설정에서 퍼블릭 접근이 차단되어 있으면 즉시 Access Denied 반환. 버킷 설정을 볼 필요도 없다.
  3. 버킷 수준 Block Public Access 평가: 4가지 설정 중 관련 항목이 활성화되어 있으면 버킷 정책과 ACL을 무시하고 차단.
  4. 버킷 정책 평가: Explicit Deny가 있으면 차단. Allow가 있으면 허용.
  5. 객체 ACL 평가: 버킷 정책에 Allow가 없을 때 ACL이 평가된다. public-read ACL이 있으면 허용.

Block Public Access 4가지 설정의 정확한 의미

이 4가지를 구분하지 않으면 '일부만 해제'했을 때 왜 여전히 차단되는지 이해할 수 없다.

설정 이름차단 대상
BlockPublicAcls퍼블릭 ACL을 부여하는 PUT 요청 자체를 차단. 기존 ACL은 유지되지만 새로 설정 불가.
IgnorePublicAcls기존 퍼블릭 ACL을 무시. ACL이 public-read여도 퍼블릭 접근 불허.
BlockPublicPolicy퍼블릭 접근을 허용하는 버킷 정책 PUT 요청을 차단.
RestrictPublicBuckets퍼블릭 버킷 정책이 있어도 AWS 서비스 주체와 인증된 사용자 외 접근 차단.

객체 ACL을 public-read로 설정했는데 접근이 안 된다면 IgnorePublicAcls가 활성화되어 있을 가능성이 높다. 이 설정은 ACL 자체를 무효화하기 때문에 ACL 값이 무엇이든 퍼블릭 접근이 불가능하다.

Block Public Access는 방화벽 앞단의 ACL 같은 개념이다. 방화벽이 포트를 막아두면 서버 내부에서 포트를 열어도 외부에서 접근할 수 없다. 객체 ACL을 바꾸는 것은 서버 내부 설정을 바꾸는 것이고, Block Public Access는 그 앞의 방화벽이다.

S3 퍼블릭 액세스 차단 문제 진단 — 단계별 CLI

Step 1. 계정 수준 Block Public Access 확인

버킷 설정을 보기 전에 계정 수준 설정을 먼저 확인해야 한다. 계정 수준에서 차단이 걸려 있으면 버킷 설정을 아무리 바꿔도 소용없다 — 이 계층을 건너뛰고 버킷만 수정하다가 시간을 낭비하는 경우가 많다.

aws s3control get-public-access-block \
  --account-id 123456789012

응답에서 BlockPublicAcls, IgnorePublicAcls, BlockPublicPolicy, RestrictPublicBuckets 중 하나라도 true이면 계정 수준에서 차단 중이다.

Step 2. 버킷 수준 Block Public Access 확인

계정 수준이 문제없다면 버킷 수준을 확인한다. 버킷 수준 설정은 계정 설정을 상속하거나 독립적으로 구성할 수 있다.

aws s3api get-public-access-block \
  --bucket your-bucket-name

4가지 항목 중 어떤 것이 활성화되어 있는지 정확히 파악한 뒤 해제 여부를 결정한다.

Step 3. 버킷 수준 Block Public Access 해제 (필요한 경우)

퍼블릭 접근이 실제로 필요한 버킷이라면 4가지를 모두 false로 설정한다. 운영 환경에서는 이 변경이 보안 정책에 부합하는지 반드시 검토해야 한다.

aws s3api put-public-access-block \
  --bucket your-bucket-name \
  --public-access-block-configuration \
    'BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false'

Step 4. 객체 ACL 또는 버킷 정책으로 퍼블릭 접근 허용

Block Public Access를 해제한 뒤에도 실제 접근 허용 설정이 없으면 여전히 차단된다. ACL 방식과 버킷 정책 방식 중 하나를 선택한다.

방법 A: 객체 ACL로 퍼블릭 접근 허용

aws s3api put-object-acl \
  --bucket your-bucket-name \
  --key your-image.jpg \
  --acl public-read

방법 B: 버킷 정책으로 퍼블릭 접근 허용 (권장)

버킷 정책 방식은 객체마다 ACL을 설정할 필요 없이 버킷 전체 또는 특정 경로에 대해 퍼블릭 접근을 허용할 수 있어 관리가 편하다.

🔽 버킷 정책 JSON 및 CLI 명령 (클릭하여 펼치기)
# policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PublicReadGetObject",
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::your-bucket-name/*"
    }
  ]
}

# 정책 적용
aws s3api put-bucket-policy \
  --bucket your-bucket-name \
  --policy file://policy.json

Step 5. 객체 URL로 직접 접근 테스트

설정 변경 후 실제 URL로 접근이 되는지 확인한다. curl을 사용하면 HTTP 상태 코드와 응답 헤더를 함께 볼 수 있어 디버깅에 유리하다.

curl -I https://your-bucket-name.s3.amazonaws.com/your-image.jpg

HTTP/1.1 200 OK가 반환되면 정상이다. 여전히 403이 반환된다면 Step 1부터 다시 확인한다.

실제 운영에서 마주친 패턴 — 잘못된 진단과 실제 원인

콘솔에서 객체를 선택하고 'Make public'을 클릭했는데 '이 버킷의 퍼블릭 액세스 차단 설정으로 인해 이 작업이 차단될 수 있습니다'라는 경고가 표시된 채로 진행한 경우가 있다. 작업은 성공한 것처럼 보이지만 실제로 ACL은 설정되지 않는다 — BlockPublicAcls=true이면 PUT Object ACL 요청 자체가 거부되기 때문이다.

처음에는 IAM 권한 문제로 오해하기 쉽다. s3:PutObjectAcl 권한이 있는데도 403이 반환되니 권한 설정을 반복해서 확인하게 된다. 하지만 실제 원인은 Block Public Access가 IAM 권한보다 먼저 요청을 차단하는 것이다.

이 상황에서 CloudTrail을 보면 PutObjectAcl 이벤트의 errorCodeAccessDenied이고 errorMessage에 'bucket settings'가 언급된다. IAM 정책 시뮬레이터로는 이 차단을 재현할 수 없다 — Block Public Access는 IAM 평가 엔진 밖에서 동작하기 때문이다.

Block Public Access는 IAM Allow를 우회하는 별도의 제어 평면이다.

보안 고려사항 — 퍼블릭 버킷이 정말 필요한가

Block Public Access를 해제하기 전에 실제로 퍼블릭 접근이 필요한 시나리오인지 검토해야 한다. 많은 경우 아래 대안이 더 적합하다.

시나리오권장 방식
인증된 사용자만 접근Presigned URL 사용 — 버킷은 비공개 유지
CDN을 통한 공개 콘텐츠 서빙CloudFront + OAC(Origin Access Control) — 버킷은 비공개 유지
정적 웹사이트 호스팅퍼블릭 버킷 정책 또는 CloudFront + OAC
임시 파일 공유Presigned URL — 만료 시간 설정 가능

CloudFront + OAC 구성은 버킷을 완전히 비공개로 유지하면서 CDN을 통해 콘텐츠를 서빙할 수 있어 보안과 성능을 동시에 확보할 수 있다.

S3 퍼블릭 액세스 차단 설정 전체 흐름 정리

graph LR A["Step 1 계정 Block Public Access get-public-access-block"] --> B["Step 2 버킷 Block Public Access get-public-access-block"] B --> C["Step 3 IgnorePublicAcls 확인 객체 ACL 유효 여부"] C --> D["Step 4 버킷 정책 또는 ACL로 명시적 Allow 설정"] D --> E["Step 5 curl -I 로 200 OK 확인"]
  1. 계정 Block Public Access 확인: 가장 먼저 확인. true이면 모든 하위 설정이 무의미하다.
  2. 버킷 Block Public Access 확인: 계정 수준이 false여도 버킷 수준이 true이면 차단된다.
  3. IgnorePublicAcls 확인: 이 설정이 true이면 객체 ACL public-read는 효력이 없다.
  4. 버킷 정책 또는 ACL로 접근 허용: Block Public Access 해제 후 명시적 Allow가 있어야 접근된다.

마무리 및 다음 단계

S3 퍼블릭 액세스 차단 문제는 계층 구조를 이해하면 빠르게 해결할 수 있다. 핵심은 객체 ACL 변경 전에 계정 및 버킷 수준의 Block Public Access 설정을 먼저 확인하는 것이다. 운영 환경에서는 버킷을 퍼블릭으로 열기보다 CloudFront + OAC 또는 Presigned URL을 검토하는 것이 보안 관점에서 더 적합하다.

용어 정리 (Glossary)

용어설명
Block Public AccessS3 버킷 및 계정 수준에서 퍼블릭 접근을 차단하는 4가지 설정의 집합. ACL 및 버킷 정책보다 상위에서 동작한다.
ACL (Access Control List)S3 객체 또는 버킷에 부여하는 접근 제어 목록. public-read는 모든 사용자에게 읽기 권한을 부여한다.
IgnorePublicAclsBlock Public Access 설정 중 하나. 활성화 시 퍼블릭 ACL이 설정되어 있어도 퍼블릭 접근을 허용하지 않는다.
Presigned URL특정 S3 객체에 대해 시간 제한이 있는 임시 접근 URL. 버킷을 퍼블릭으로 열지 않고 인증된 접근을 제공할 수 있다.
OAC (Origin Access Control)CloudFront에서 S3 버킷에 접근할 때 사용하는 인증 메커니즘. 버킷을 비공개로 유지하면서 CDN 서빙이 가능하다.

댓글

이 블로그의 인기 게시물

EC2 SSH 연결 시간 초과: 확인해야 할 보안 그룹(Security Group) 규칙

EC2 SSH 연결 타임아웃 완전 해결 가이드: Security Group 인바운드 규칙부터 라우팅까지

IAM User vs IAM Role 차이점 완전 정리 — EC2에서 S3 접근 시 무엇을 써야 하는가