반응형
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가지 정책의 역할

7. Best Practices 요약
정적 자산 + CORS 필요 시
- Cache Policy: Managed-CachingOptimized 유지 (캐시 효율)
- Origin Request Policy: Managed-CORS-S3Origin 추가 (S3 CORS 백업)
- Response Headers Policy: 커스텀 생성 + origin_override=true (핵심)
동적 콘텐츠/API
- Cache Policy: Managed-CachingDisabled (캐시 안함)
- Origin Request Policy: Managed-AllViewer (모든 헤더 전달)
- Response Headers Policy: 필요 시 추가
CORS Origin 관리
- 적은 Origin 수: Response Headers Policy에 명시
- 많은/동적 Origin: S3 CORS + 커스텀 캐시 정책 (Origin 캐시 키 포함)
- 모든 Origin 허용: Response Headers Policy에 사용 (보안 주의)
참고 자료
반응형
'CLOUD > AWS' 카테고리의 다른 글
| AWS CloudFront 요금 정액제 출시 (2025. 11 업데이트) (0) | 2025.12.23 |
|---|---|
| ASG + 스팟 인스턴스 + 사설 DNS 자동등록 잘 안쓰이는이유 (2) | 2025.09.24 |
| Spot 인스턴스를 안정적으로 쓰는 방법: ASG + Capacity-Optimized + Capacity Rebalancing 2편(단점, 무중단, 장점) (0) | 2025.09.22 |
| Spot 인스턴스 안정성 확보: ASG + Capacity-Optimized + Capacity Rebalancing 활용하기 (0) | 2025.09.22 |
| EKS kubectl 연결 오류 해결기: NAT 교체 이후 발생한 함정 (0) | 2025.09.22 |
댓글