AWS S3 & CloudFront 403 Access Denied 에러 완벽 해결: OAC 보안 아키텍처

AWS S3 & CloudFront 403 Access Denied 에러 완벽 해결: OAC 보안 아키텍처

"React로 만든 멋진 웹사이트를 AWS S3에 올리고, CDN을 태우기 위해 CloudFront까지 완벽하게 연동했는데 도메인에 접속하면 403 ERROR - The request could not be satisfied라는 차가운 접근 거부 메시지만 나타납니다."

서버리스(Serverless) 정적 웹 호스팅을 구축하려는 데브옵스(DevOps) 엔지니어들이 가장 오랜 시간 삽질을 하는 마의 구간입니다. 이 에러를 마주하면 대부분 급한 마음에 S3 버킷의 '퍼블릭 액세스 차단'을 모조리 해제하고 버킷 정책(Bucket Policy)에 와일드카드(*)를 남발하여 대문을 활짝 열어버립니다.

하지만 이는 CloudFront라는 튼튼한 성벽을 세워둔 의미를 완전히 상실하게 만드는 치명적인 보안 사고입니다. 본 가이드에서는 S3 버킷을 외부 인터넷으로부터 완벽히 차단(Private)하면서도, 오직 CloudFront만이 안전하게 데이터를 가져갈 수 있도록 허락하는 최신 OAC(Origin Access Control) 아키텍처 설정법을 단호하게 제시합니다.

📌 이 글의 핵심 포인트

  • 403 Access Denied 에러의 근본적 원인 이해: CloudFront와 S3 간의 권한(Permission) 불일치
  • 레거시 OAI(Origin Access Identity) 방식의 한계와 최신 OAC(Origin Access Control) 도입의 필요성
  • 단 3단계로 끝내는 S3 버킷 정책(Bucket Policy) 자동 생성 및 무결점 보안 셋업

1단계: 핵심 원인 - 성문을 잠그고 열쇠를 주지 않은 실수

CloudFront(CDN)는 전 세계에 퍼져있는 엣지 서버입니다. 유저가 웹사이트에 접속하면 CloudFront가 원본 저장소인 S3에 다가가 "내가 유저 대신 파일 좀 가져갈게"라고 요청합니다.

그런데 S3 버킷은 기본적으로 세상의 모든 접근을 차단(Block Public Access)하도록 단단히 잠겨 있습니다. 아무리 CloudFront라 할지라도, S3 입장에서 보면 '초대장(버킷 정책) 없이 담을 넘으려는 외부인'일 뿐이므로 가차 없이 403 Forbidden(접근 거부) 에러를 던지며 쫓아내는 것입니다.

2단계: 최신 방어 체계 - OAC(Origin Access Control) 설정

과거에는 OAI(Origin Access Identity)라는 방식을 썼지만, 보안상의 헛점이 많아 AWS는 2022년부터 OAC라는 훨씬 강력하고 정교한 암호화 통신 방식을 표준으로 권장하고 있습니다. S3를 완벽한 Private 상태로 유지하면서 OAC를 뚫어주는 방법은 다음과 같습니다.

  1. AWS 콘솔에서 CloudFront 배포(Distribution) 설정으로 들어갑니다.
  2. [원본(Origins)] 탭을 클릭하고 현재 연결된 S3 원본을 선택 후 [편집]을 누릅니다.
  3. '원본 액세스(Origin access)' 항목에서 '원본 액세스 제어 설정(권장)'을 선택합니다.
  4. 드롭다운 메뉴 우측의 [제어 설정 생성] 버튼을 누르고 이름 확인 후 그대로 생성합니다.
  5. 화면 맨 아래의 [변경 사항 저장]을 누릅니다.

3단계: S3 버킷 정책(Bucket Policy) 자동 업데이트

CloudFront에서 OAC를 설정하고 저장 버튼을 누르면, 화면 상단에 "S3 버킷 정책을 업데이트해야 합니다"라는 노란색 경고 배너와 함께 [정책 복사] 버튼이 친절하게 나타납니다. 이 버튼이 핵심입니다.

복사된 정책은 대략 아래와 같은 구조를 갖습니다. (직접 타이핑하지 말고 반드시 AWS가 복사해 준 정책을 사용하세요)


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudFrontServicePrincipal",
            "Effect": "Allow",
            "Principal": {
                "Service": "cloudfront.amazonaws.com"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/*",
            "Condition": {
                "StringEquals": {
                    "AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1ABCDEFGHIJ"
                }
            }
        }
    ]
}

이 코드는 "오직 내 AWS 계정(123456789012)에 속한, 특정 CloudFront 배포(E1ABCDEFGHIJ)만이 이 버킷 안의 객체(s3:GetObject)를 읽어갈 수 있다"라는 아주 견고한 보안 규칙입니다.

  1. 복사한 정책을 들고 S3 콘솔로 이동합니다.
  2. 해당 버킷의 [권한(Permissions)] 탭으로 갑니다. (이때 '퍼블릭 액세스 차단'은 반드시 '모든 퍼블릭 액세스 차단(On)' 상태여야 합니다.)
  3. [버킷 정책(Bucket Policy)] 섹션의 [편집]을 누르고, 복사해 온 JSON 코드를 붙여넣기 한 뒤 저장합니다.

이제 도메인에 다시 접속해 보십시오. 차갑던 403 에러가 사라지고, CloudFront를 타고 날아온 React 웹사이트가 0.1초 만에 당신을 반겨줄 것입니다.

💡 아키텍트의 시선 (Insight)

클라우드 인프라 구축에서 '작동하는 것(Works)'과 '안전하게 작동하는 것(Works Securely)'은 하늘과 땅 차이입니다. 403 에러를 피하려고 S3를 퍼블릭(Public)으로 여는 것은, 도둑질을 막겠다고 아예 대문을 부숴버리는 것과 같습니다. CloudFront와 S3 OAC 아키텍처의 권한 분리 원칙을 완벽하게 이해하고 통제하는 순간, 당신은 어설픈 개발자를 넘어 신뢰받는 클라우드 아키텍트로 한 걸음 도약하게 될 것입니다.

댓글

이 블로그의 인기 게시물

Zapier & Make.com 자동화의 덫: 무한 루프(Infinite Loop) 에러 완벽 방어 아키텍처

엑셀 보고서의 종말: 구글 스프레드시트와 루커 스튜디오(Looker Studio)로 실시간 대시보드 구축하기

Docker OOMKilled (Exit Code 137) 에러의 진실: 컨테이너 메모 누수 방어 및 리소스 최적화 아키텍처