Published on

CloudFront 403/504? OAC·S3 정책·CORS 점검

Authors

CloudFront를 S3 오리진 앞에 두고 정적 파일이나 SPA를 서빙하다 보면, 어느 날 갑자기 403 또는 504가 터지며 배포가 멈추는 경우가 있습니다. 특히 OAI에서 OAC로 전환하는 과정, S3 버킷 퍼블릭 차단 설정, CORS 헤더 구성, CloudFront의 오리진 연결 설정이 맞물리면 “겉으로는 설정이 맞아 보이는데 계속 실패”하는 상황이 자주 발생합니다.

이 글은 CloudFront 403504증상별로 분해하고, OAC·S3 정책·CORS·타임아웃을 재현 가능한 체크리스트로 정리합니다. 마지막에는 AWS CLI로 검증하는 방법과 정책 예시까지 포함합니다.

1) 먼저 구분: 403 vs 504가 의미하는 것

CloudFront 403의 대표 원인

  • CloudFront가 오리진(S3)에 접근했지만 권한이 없어 거절
  • Viewer 요청이 WAF, Geo restriction, Signed URL/쿠키 정책에 의해 차단됨
  • S3가 AccessDenied 또는 NoSuchKey를 반환했는데, CloudFront가 403으로 표면화함

CloudFront 504의 대표 원인

  • CloudFront가 오리진에 연결했지만 응답을 제때 못 받아 타임아웃
  • 오리진이 ALB, EC2, Lambda URL, API Gateway인 경우 백엔드 지연이 원인일 수 있음
  • S3는 보통 504의 주범이 아니지만, VPC 엔드포인트, 프라이빗 네트워크 경로, DNS 이슈 등이 끼면 간접적으로 발생할 수 있음

에러를 빠르게 분류하려면 CloudFront 표준 로그 또는 실시간 로그에서 x-edge-result-type, x-edge-response-result-type를 확인하세요.

2) OAC 기본 이해: OAI와 뭐가 달라졌나

OAC(Origin Access Control)는 CloudFront가 S3에 접근할 때 SigV4 서명 기반으로 인증하는 방식입니다. OAI보다 권장되는 최신 방식이며, 보안 정책도 더 명확하게 작성할 수 있습니다.

OAC를 쓰면 핵심은 아래 두 가지입니다.

  1. CloudFront 배포의 오리진에 OAC가 연결되어 있어야 함
  2. S3 버킷 정책에서 CloudFront 서비스 프린시플을 허용하고, AWS:SourceArn으로 배포 ARN을 제한해야 함

이 둘 중 하나라도 빠지면 CloudFront는 S3에서 AccessDenied를 받고, 결과적으로 403이 됩니다.

3) CloudFront 403: OAC·S3 정책 점검 체크리스트

3-1. S3 퍼블릭 접근 차단은 유지해도 된다

많은 팀이 “버킷이 퍼블릭 차단인데 CloudFront가 접근 가능한가”를 헷갈려 합니다. 결론은 가능합니다.

  • S3 Block Public Access는 “퍼블릭 정책/ACL”을 막는 기능
  • OAC는 퍼블릭이 아니라 CloudFront만 접근하도록 버킷 정책을 작성하는 방식

즉, 퍼블릭 차단은 켜두고, 버킷 정책으로 CloudFront만 허용하는 게 정석입니다.

3-2. OAC용 S3 버킷 정책 예시

아래 정책은 CloudFront 배포 1개만 S3 GetObject를 할 수 있도록 허용합니다. Resource는 반드시 객체 경로까지 포함해 /*로 끝나야 합니다.

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

자주 하는 실수:

  • Resourcearn:aws:s3:::bucket까지만 쓰고 /*를 빼서 객체 접근이 막힘
  • AWS:SourceArn에 배포 ID를 잘못 입력하거나, 다른 계정의 ARN을 넣음
  • OAC가 아니라 OAI 기준의 정책을 그대로 붙여서 Principal이 맞지 않음

3-3. CloudFront 배포의 오리진 설정 확인 포인트

CloudFront 콘솔에서 Distribution Origins 항목을 확인합니다.

  • Origin domain이 S3 REST 엔드포인트인지 확인
    • 예: my-bucket.s3.ap-northeast-2.amazonaws.com
  • OAC가 해당 오리진에 연결되어 있는지 확인
  • Origin path를 썼다면(예: /prod) S3 키 경로가 실제와 일치하는지 확인

SPA에서 index.html을 루트로 두고 있는데 Origin path가 붙어 있으면 NoSuchKey가 나고, CloudFront는 상황에 따라 403 또는 404로 보일 수 있습니다.

3-4. 기본 루트 객체와 403 커스텀 에러 응답

SPA에서 라우팅을 CloudFront로 처리하려면 다음을 함께 점검하세요.

  • Default root object가 index.html인지
  • Custom error response에서 403 또는 404index.html로 매핑했는지

단, “S3 권한 문제로 발생한 진짜 403”까지 index.html로 덮어버리면 장애가 숨겨집니다. 운영에서는 에러 매핑을 최소화하고, 배포 직후 또는 장애 시점에는 매핑을 잠시 끄고 원인을 확인하는 방식이 안전합니다.

4) CORS: 403이 아니라도 프론트에서는 실패로 보인다

CORS는 보통 CloudFront가 403을 내는 문제가 아니라, 브라우저가 응답을 차단하는 문제입니다. 그래서 DevTools에는 네트워크 응답이 200인데도 애플리케이션은 “요청 실패”처럼 보이기도 합니다.

4-1. S3 CORS 설정 예시

S3에 직접 CORS를 설정하는 경우(특히 이미지, 폰트, JSON을 S3에서 직접 가져오는 경우) 아래처럼 구성합니다.

[
  {
    "AllowedOrigins": ["https://app.example.com"],
    "AllowedMethods": ["GET", "HEAD"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]

체크포인트:

  • AllowedOrigins*를 쓰면 쿠키/인증 헤더가 포함된 요청은 실패할 수 있음
  • 폰트 로딩 문제는 Access-Control-Allow-Origin 누락으로 자주 발생

4-2. CloudFront에서 CORS 헤더를 주입하는 경우

CloudFront Response headers policy로 CORS를 넣는 방식도 흔합니다. 이 경우 S3 CORS와 CloudFront 헤더 정책이 충돌할 수 있습니다.

권장 접근:

  • “어디에서 CORS를 책임질지”를 하나로 정함
  • CloudFront에서 CORS를 넣는다면 S3는 최소화하고, CloudFront 정책을 표준화

또한 프리플라이트 요청(OPTIONS)을 쓰는 API 오리진이라면, CloudFront 캐시 정책에 Origin, Access-Control-Request-Method, Access-Control-Request-Headers가 포함되어야 예측 가능한 동작을 합니다.

5) CloudFront 504: 오리진 타임아웃과 네트워크 점검

504는 CloudFront가 오리진에서 응답을 받지 못했다는 뜻입니다. S3 정적 오리진이라면 드물지만, 다음 상황에서는 가능성이 있습니다.

5-1. 오리진이 S3가 아니라면 먼저 의심할 것

  • ALB 뒤 애플리케이션 지연
  • Lambda Function URL 또는 API Gateway 지연
  • 오리진의 헬스/스케일 문제

이 경우는 “백엔드가 느려서 CloudFront가 기다리다 포기”하는 형태가 많습니다. 비슷한 맥락의 장애 대응은 GCP Cloud Run 503·콜드스타트 5분 튜닝 가이드처럼, 지연 원인을 계층별로 쪼개는 방식이 도움이 됩니다.

5-2. CloudFront 오리진 타임아웃 설정

CloudFront에는 오리진에 대한 타임아웃 설정이 있습니다(콘솔에서 오리진 편집).

  • Origin response timeout
  • Origin keep-alive timeout

백엔드가 피크에 느려질 수 있다면, 타임아웃을 무작정 늘리기보다 백엔드 성능 개선캐시 전략 강화를 먼저 검토하세요. 타임아웃 증가는 장애를 “더 늦게 터지게” 할 뿐, 근본 해결이 아닐 때가 많습니다.

5-3. DNS 및 네트워크 경로

특정 리전 또는 특정 PoP에서만 504가 난다면 아래를 점검합니다.

  • 오리진 도메인의 DNS 응답이 일관적인지
  • 오리진이 프라이빗 네트워크에 있고, CloudFront가 접근 가능한 경로인지
  • 방화벽 또는 보안 그룹에서 CloudFront IP 대역을 잘못 차단하고 있지 않은지

6) 장애 재현과 검증: AWS CLI로 빠르게 확인하기

6-1. CloudFront를 거치지 않고 S3 오브젝트 접근 확인

S3 오브젝트 자체가 존재하는지부터 확인합니다.

aws s3api head-object --bucket my-static-bucket --key index.html

404가 나오면 CloudFront 문제가 아니라 배포 산출물 또는 경로 문제입니다.

6-2. CloudFront 경유 응답 헤더 확인

다음처럼 헤더를 확인하면 캐시 여부와 에지 결과 타입을 빠르게 볼 수 있습니다.

curl -I https://d111111abcdef8.cloudfront.net/index.html

확인할 헤더 예시:

  • x-cache: Hit from cloudfront 또는 Miss from cloudfront
  • via: CloudFront 경유 여부
  • age: 캐시된 응답의 나이

6-3. 캐시 무효화로 정책 변경 반영

정책이나 헤더 정책을 바꿨는데도 동일 증상이면 캐시 영향일 수 있습니다.

aws cloudfront create-invalidation \
  --distribution-id E1ABCDEFGHIJKL \
  --paths "/*"

CORS 헤더 변경은 캐시에 남아 있으면 계속 재현됩니다. 특히 OPTIONS 응답이 캐시된 경우가 까다롭습니다.

7) 실전 트러블슈팅 순서(추천)

운영에서 시간을 가장 아끼는 순서로 정리하면 다음과 같습니다.

  1. CloudFront 에러 코드 확인: 403인지 504인지, 특정 경로만인지
  2. curl -I로 CloudFront 응답 헤더 확인: 캐시 여부, 응답 코드
  3. S3 head-object로 파일 존재 여부 확인
  4. OAC 연결 여부 확인: 배포 오리진에 OAC가 붙었는지
  5. S3 버킷 정책 확인: Principal이 cloudfront.amazonaws.com인지, AWS:SourceArn이 정확한지
  6. CORS 책임 위치 결정: S3 또는 CloudFront 중 하나로 단일화
  7. 504면 오리진 타임아웃 및 백엔드 지연 분석

장애 분석은 “증상을 한 번에 고치려는 시도”보다, 계층별로 분해해 원인을 좁히는 게 훨씬 빠릅니다. 예를 들어 타임아웃 계열 문제는 gRPC에서도 동일한 접근이 유효합니다. 필요하면 Go gRPC DEADLINE_EXCEEDED 9가지 원인과 처방처럼, 타임아웃을 만드는 병목을 분류하는 사고방식을 참고할 수 있습니다.

8) 마무리: 403은 권한, 504는 지연이다

  • 403은 대부분 OAC와 S3 버킷 정책 불일치에서 시작합니다. OAC를 쓴다면 “CloudFront 서비스 프린시플 허용”과 AWS:SourceArn 제한이 핵심입니다.
  • 504는 오리진 지연 또는 네트워크 경로 문제입니다. 타임아웃을 늘리기 전에 백엔드 병목과 캐시 전략을 먼저 점검하세요.
  • CORS는 서버가 200을 줘도 브라우저가 막을 수 있으니, S3와 CloudFront 중 한 곳에서 일관되게 관리하세요.

위 체크리스트대로만 따라가도 CloudFront 403/504의 대부분은 30분 안에 원인 범위를 좁힐 수 있습니다.