본문 바로가기
CLOUD/AWS

AWS CloudFront 캐시 정책과 CORS 에러

by Rainbound-IT 2026. 1. 2.
반응형

 

Cloudfront  캐시 정책 설정시 CORS 에러가 발생하여   

CloudFront 캐시 정책이 CORS 동작에 미치는 영향과 해결 방법을 상세히 정리합니다.

 

 

 

1. CloudFront 캐시 키(Cache Key) 이해

캐시 키란?

CloudFront가 캐시된 객체를 식별하는 고유 값입니다. 동일한 캐시 키를 가진 요청은 동일한 캐시 응답을 받습니다.

기본 캐시 키 구성요소

캐시 키 = URL + (선택적) 헤더 + (선택적) 쿠키 + (선택적) 쿼리스트링

캐시 키에 헤더 포함 시 영향

HeaderBehavior: "none" (헤더 미포함)
├── /fonts/Pretendard.woff2 → 캐시 키 1개
└── 모든 Origin에서 같은 캐시 응답

HeaderBehavior: "whitelist" + Origin 헤더 포함
├── /fonts/Pretendard.woff2 + Origin:<https://a.example.com> → 캐시 키 A
├── /fonts/Pretendard.woff2 + Origin:<https://b.example.com> → 캐시 키 B
└── Origin별로 다른 캐시 응답 (캐시 효율 ↓)


2. AWS Managed 캐시 정책 비교

주요 Managed 정책

정책명  TTL  Headers  Cookies  QueryStrings  용도
CachingOptimized 86400s (1일) none none none 정적 자산 (JS, CSS, 이미지)
CachingOptimizedForUncompressedObjects 86400s none none none 압축 불필요 자산
CachingDisabled 0 - - - 동적 콘텐츠, API
Elemental-MediaPackage 86400s whitelist none all 미디어 스트리밍

Managed-CachingOptimized 상세 설정

{
  "Name": "Managed-CachingOptimized",
  "DefaultTTL": 86400,      // 24시간
  "MaxTTL": 31536000,       // 1년
  "MinTTL": 1,
  "ParametersInCacheKeyAndForwardedToOrigin": {
    "EnableAcceptEncodingGzip": true,
    "EnableAcceptEncodingBrotli": true,
    "HeadersConfig": {
      "HeaderBehavior": "none"    // ⚠️ 헤더 캐시 키 미포함
    },
    "CookiesConfig": {
      "CookieBehavior": "none"
    },
    "QueryStringsConfig": {
      "QueryStringBehavior": "none"
    }
  }
}

왜 HeaderBehavior: "none"인가?

설계 의도: 캐시 효율 극대화

시나리오: 동일 파일을 3개 Origin에서 요청

HeaderBehavior: "whitelist" (Origin 포함)
├── Origin: <https://a.example.com> → S3 요청 → 캐시 A 저장
├── Origin: <https://b.example.com> → S3 요청 → 캐시 B 저장
├── Origin: <https://c.example.com> → S3 요청 → 캐시 C 저장
└── 결과: 3번의 Origin 요청, 3개의 캐시 복사본

HeaderBehavior: "none"
├── 첫 번째 요청 → S3 요청 → 캐시 저장
├── 두 번째 요청 → 캐시 히트
├── 세 번째 요청 → 캐시 히트
└── 결과: 1번의 Origin 요청, 1개의 캐시 복사본

결론: 정적 자산은 누가 요청해도 같은 내용이므로 Origin 구분이 불필요


3. CORS와 캐시의 충돌

CORS 동작 원리

브라우저 (<https://app.example.com>)
    ↓
    요청: GET /fonts/Pretendard.woff2
    헤더: Origin: <https://app.example.com>
    ↓
서버 (S3/CloudFront)
    ↓
    응답: 200 OK
    헤더: Access-Control-Allow-Origin: <https://app.example.com>
    ↓
브라우저
    Origin 헤더와 ACAO 헤더 비교
    ├── 일치 → 리소스 사용 허용
    └── 불일치/없음 → CORS 에러

문제 발생 시나리오

 

1단계

 

 

2단계

 

 

 

 

핵심 문제점

 

구성 요소 동작  문제
Cache Policy Origin 헤더 캐시 키 미포함 모든 Origin에 같은 캐시 응답
Origin Request Policy Origin 헤더 미전달 S3가 CORS 헤더 미반환
S3 CORS Origin 헤더 필요 헤더 없으면 CORS 응답 안함

 


4. 해결 방법 비교

 

 

방법 1: Origin 헤더를 캐시 키에 포함 (커스텀 캐시 정책)

resource "aws_cloudfront_cache_policy" "cors_aware_caching" {
  name    = "cors-aware-caching"
  comment = "Include Origin header in cache key for CORS"

  default_ttl = 86400
  max_ttl     = 31536000
  min_ttl     = 1

  parameters_in_cache_key_and_forwarded_to_origin {
    headers_config {
      header_behavior = "whitelist"
      headers {
        items = ["Origin"]  # Origin 헤더 캐시 키 포함
      }
    }
    cookies_config {
      cookie_behavior = "none"
    }
    query_strings_config {
      query_string_behavior = "none"
    }
  }
}

장점:

  • S3 CORS 응답을 Origin별로 정확히 캐시
  • S3 CORS 설정을 그대로 활용

단점:

  • 캐시 효율 감소 (Origin별로 별도 캐시)
  • 여러 Origin에서 접근 시 캐시 복사본 증가

방법 2: Response Headers Policy 사용 (권장)

resource "aws_cloudfront_response_headers_policy" "cors_static_assets" {
  name = "cors-static-assets"

  cors_config {
    access_control_allow_credentials = false

    access_control_allow_headers {
      items = ["*"]
    }

    access_control_allow_methods {
      items = ["GET", "HEAD", "OPTIONS"]
    }

    access_control_allow_origins {
      items = [
        "<https://app.example.com>",
        "<https://www.example.com>"
      ]
    }

    access_control_max_age_sec = 86400

    # ✅ 핵심: 캐시된 응답에도 CORS 헤더 강제 추가
    origin_override = true
  }
}

장점:

  • 캐시 효율 유지 (CachingOptimized 그대로 사용)
  • CloudFront 레벨에서 CORS 헤더 강제 추가
  • S3 CORS 설정과 독립적

단점:

  • CORS Origin 목록을 CloudFront에서 관리해야 함
  • 동적 Origin 허용이 어려움 (와일드카드 제한적)

방법 3: Origin Request Policy만 추가 (부분 해결)

data "aws_cloudfront_origin_request_policy" "cors_s3_origin" {
  name = "Managed-CORS-S3Origin"
}

# behavior에 적용
origin_request_policy_id = data.aws_cloudfront_origin_request_policy.cors_s3_origin.id

이것만으로는 불충분한 이유:

  • Origin 헤더를 S3로 전달하지만
  • CachingOptimized는 Origin을 캐시 키에 미포함
  • 첫 요청의 Origin으로 CORS 응답이 캐시됨
  • 다른 Origin에서 요청 시 잘못된 ACAO 헤더 반환

방법 비교 요약

 

방법  캐시 효율  구현 복잡도 CORS 정확성  권장도
커스텀 캐시 정책 낮음 중간 높음 ⭐⭐⭐
Response Headers Policy 높음 낮음 높음 ⭐⭐⭐⭐⭐
Origin Request Policy만 높음 낮음 낮음

5. 권장 해결책

최종 구성

ordered_cache_behavior {
  path_pattern = "/_static/assets/*"

  # 1. 캐시 효율 유지
  cache_policy_id = data.aws_cloudfront_cache_policy.caching_optimized.id

  # 2. S3 CORS 응답 활성화 (백업)
  origin_request_policy_id = data.aws_cloudfront_origin_request_policy.cors_s3_origin.id

  # 3. CloudFront 레벨 CORS 강제 (핵심)
  response_headers_policy_id = aws_cloudfront_response_headers_policy.cors_static_assets.id
}

동작 흐름

요청: GET /_static/assets/fonts/Pretendard.woff2
헤더: Origin: <https://app.example.com>

CloudFront Edge:
├── 캐시 확인 → 히트 또는 미스
│
├── [캐시 미스 시]
│   ├── Origin Request Policy → Origin 헤더를 S3로 전달
│   ├── S3 → CORS 헤더 포함 응답
│   └── 캐시 저장
│
├── [캐시 히트 시]
│   └── 저장된 응답 반환 (CORS 헤더 있을 수도/없을 수도)
│
└── Response Headers Policy (origin_override=true)
    └── 최종 응답에 CORS 헤더 강제 추가/덮어쓰기
        Access-Control-Allow-Origin: <https://app.example.com>

브라우저: CORS 검증 통과 ✅

6. 알아두면 좋은 추가 내용

origin_override 옵션

  동작
true Origin 응답의 CORS 헤더를 무시하고 CloudFront 설정으로 덮어씀
false Origin 응답에 CORS 헤더가 있으면 그대로 사용, 없으면 추가

권장: true - 일관된 CORS 동작 보장

Preflight (OPTIONS) 요청 처리

CORS preflight 요청도 캐시될 수 있습니다:

ordered_cache_behavior {
  allowed_methods = ["GET", "HEAD", "OPTIONS"]  # OPTIONS 허용
  cached_methods  = ["GET", "HEAD"]             # OPTIONS는 캐시 안함 (기본)
}

S3 CORS vs CloudFront Response Headers Policy

 

항목  S3 CORS CloudFront Response Headers Policy
설정 위치 S3 버킷 CloudFront Distribution
동적 Origin 지원 (AllowedOrigins 목록) 지원 (allow_origins 목록)
와일드카드 * 완전 지원 제한적 (*.example.com 형태)
캐시 영향 캐시 키/정책에 따라 다름 origin_override로 제어
권장 사용 직접 S3 접근 시 CloudFront 경유 시

트러블슈팅 체크리스트

# 1. 현재 CORS 헤더 확인 (Origin 헤더 포함)
curl -I -H "Origin: <https://app.example.com>" \\
  "<https://static.example.com/_static/assets/fonts/Pretendard-Bold.woff2>"

# 2. Origin 헤더 없이 요청
curl -I \\
  "<https://static.example.com/_static/assets/fonts/Pretendard-Bold.woff2>"

# 3. 캐시 무효화
aws cloudfront create-invalidation \\
  --distribution-id EXXXXXXXXXXXXX \\
  --paths "/_static/assets/*"

# 4. CloudFront 정책 확인
aws cloudfront get-cache-policy --id 
aws cloudfront get-origin-request-policy --id 
aws cloudfront get-response-headers-policy --id 

 

 

캐시키 정책

캐시키 정책

 

3가지 정책의 역할

3가지 정책의역할

 


7. Best Practices 요약

정적 자산 + CORS 필요 시

  1. Cache Policy: Managed-CachingOptimized 유지 (캐시 효율)
  2. Origin Request Policy: Managed-CORS-S3Origin 추가 (S3 CORS 백업)
  3. Response Headers Policy: 커스텀 생성 + origin_override=true (핵심)

동적 콘텐츠/API

  1. Cache Policy: Managed-CachingDisabled (캐시 안함)
  2. Origin Request Policy: Managed-AllViewer (모든 헤더 전달)
  3. Response Headers Policy: 필요 시 추가

CORS Origin 관리

  • 적은 Origin 수: Response Headers Policy에 명시
  • 많은/동적 Origin: S3 CORS + 커스텀 캐시 정책 (Origin 캐시 키 포함)
  • 모든 Origin 허용: Response Headers Policy에  사용 (보안 주의)

참고 자료

반응형

댓글