AWS 기술 블로그

AWS MediaTailor SSAI 환경에서 멀티 CDN 구성과 동적 전환 – Part1

이 블로그는 2부작 시리즈입니다.
– Part 1: 멀티 CDN 구성과 동적 전환 (본 글)
– Part 2: 멀티 CDN 환경의 보안 — 토큰 인증, Origin 보안, 서드파티 CDN 제약 대응

1. 도입

OTT 서비스를 운영하는 많은 기업들은 단일 CDN이 아닌 멀티 CDN 전략을 채택하고 있습니다. ISP별 네트워크 품질 차이, CDN 장애 대비, 비용 최적화 등의 이유로 Amazon CloudFront와 함께 서드파티 CDN을 병행 운영하는 것이 일반적입니다.

한편, 서버사이드 광고 삽입(SSAI)을 위해 AWS Elemental MediaTailor (이하 MediaTailor)를 도입하면 고민할 지점이 하나 늘어납니다. MediaTailor는 Origin에서 가져온 manifest에 광고 세그먼트 URL을 스티칭하여 personalized manifest를 생성하는데, 이때 콘텐츠 세그먼트와 광고 세그먼트가 각각 다른 CDN을 통해 전송될 수 있습니다. 멀티 CDN 환경에서 이 두 종류의 세그먼트를 어떻게 동적으로 라우팅할 것인지가 이 글의 주제입니다.

이 블로그에서는 MediaTailor의 CDN prefix 기능을 활용하여 콘텐츠/광고 세그먼트별로 동적으로 CDN을 적용하는 방법과 광고 트래킹이 유지되는 메커니즘을 다룹니다. 토큰 인증, Origin 보안 등 보안 심화 내용은 Part 2에서 다룹니다.

2. MediaTailor의 세그먼트 전송 구조

MediaTailor가 personalized manifest를 생성하는 과정을 이해하면 멀티 CDN 적용 방법이 명확해집니다.

Manifest 생성 흐름

  1. 플레이어가 MediaTailor에 manifest를 요청합니다.
  2. MediaTailor는 Content Origin(MediaPackage 등)에서 원본 manifest를 가져옵니다.
  3. 광고 브레이크 구간(SCTE-35 마커)을 감지하면 ADS(Ad Decision Server)에 광고를 요청합니다.
  4. 원본 manifest의 광고 브레이크 구간에 광고 세그먼트 URL을 스티칭합니다.
  5. 완성된 personalized manifest를 플레이어에 반환합니다.

두 가지 세그먼트 경로

플레이어가 받는 personalized manifest에는 두 종류의 세그먼트 URL이 포함됩니다:

  • 콘텐츠 세그먼트: Origin(MediaPackage) → CDN → 플레이어
  • 광고 세그먼트: MediaTailor(트래킹) → 301 Redirect → CDN → 플레이어

각 세그먼트 URL의 도메인(CDN)은 MediaTailor의 CDN prefix 설정에 의해 결정됩니다. 이 설정을 활용하면 콘텐츠와 광고 세그먼트를 서로 다른 CDN으로 라우팅할 수 있습니다.

> 전제: 이 글은 서버사이드 리포팅(server-side reporting) 기준으로 설명합니다. 플레이어가 GET <mediatailorURL>/v1/master/…로 세션을 시작하는 방식이며 MediaTailor 기본 동작입니다. 반면 플레이어가 POST /v1/session/…으로 세션을 초기화하면 리포팅 모드가 기본적으로 클라이언트사이드가 되어, 광고 세그먼트의 최종 URL이 manifest에 직접 들어가고 아래에서 설명하는 리다이렉트 홉이 생기지 않습니다 (body에 “reportingMode”: “server”를 넣으면 서버사이드로 유지됩니다). 두 방식의 차이는 5장(리포팅 모드에 따라 광고 세그먼트 URL이 달라집니다) 에서 다시 정리합니다.

3. CDN Prefix 설정: 콘텐츠 vs 광고 분리

MediaTailor의 PlaybackConfiguration에서는 두 가지 CDN prefix를 독립적으로 설정할 수 있습니다.

설정 항목

항목 설명 적용 대상
ContentSegmentUrlPrefix 콘텐츠 세그먼트 URL에 적용되는 CDN 도메인 원본 콘텐츠 (영상, 오디오)
AdSegmentUrlPrefix 광고 세그먼트 URL에 적용되는 CDN 도메인 광고 크리에이티브

콘솔 설정

MediaTailor 콘솔에서 PlaybackConfiguration을 생성할 때:

  1. Video content source URL: MediaPackage endpoint URL 입력
  2. Ad decision server URL: ADS URL 입력
  3. Content segment prefix: 콘텐츠 CDN 도메인 입력 (예: https://cdn-isp-a.example.com)
  4. Ad segment prefix: 광고 CDN 도메인 입력 (예: https://d1234567890.cloudfront.net)

4. 동적 CDN 전환: Configuration Aliases + Player Param

고정된 CDN prefix만으로는 ISP별 최적화나 런타임 CDN 전환이 어렵습니다. MediaTailor의 도메인 변수(domain variables) 기능을 활용하면 세션마다 다른 CDN을 동적으로 지정할 수 있습니다. CDN prefix에 [player_params.<변수명>] 형태의 변수를 넣고, Configuration Aliases에 변수별 alias key와 실제 도메인을 사전 등록합니다. 플레이어는 세션 초기화 시 각 변수에 사용할 alias key만 전달하면, MediaTailor가 이를 사전 등록된 도메인으로 치환합니다.

콘텐츠와 광고 세그먼트에 각각 별도의 변수를 두면, 두 세그먼트를 서로 다른 CDN으로 독립적으로 라우팅할 수 있습니다.

설정 방법

1단계: PlaybackConfiguration의 CDN prefix 항목에 변수를 포함한 값을 입력합니다.

{
  "CdnConfiguration": {
    "ContentSegmentUrlPrefix": "https://[player_params.content_cdn_domain]/out/v1/<endpoint-id>",
    "AdSegmentUrlPrefix": "https://[player_params.ad_cdn_domain]/ads/"
  }
}

2단계: ConfigurationAliases에 각 변수의 alias key와 실제 도메인을 매핑합니다. alias key는 변수마다 독립적으로 정의됩니다.

{
  "ConfigurationAliases": {
    "player_params.content_cdn_domain": {
      "cdn_a": "cdn-a.example.com",
      "cdn_b": "cdn-b.example.com",
      "cdn_cf": "d1234567890.cloudfront.net"
    },
    "player_params.ad_cdn_domain": {
      "cdn_cf": "d1234567890.cloudfront.net"
    }
  }
}

> 콘솔에서는 Configuration aliases 섹션에서 동일하게 등록할 수 있습니다. 콘텐츠 CDN은 ISP별로 여러 alias를, 광고 CDN은 CloudFront 하나로 고정하는 식의 구성이 가능합니다.

3단계: 플레이어에서 POST 세션 초기화 시 playerParams로 각 변수에 사용할 alias key를 전달합니다.

curl -X POST "https://cdn.example.com/v1/session/<hash>/<config>/index.m3u8" \
  -H "Content-Type: application/json" \
  -d '{
        "reportingMode": "server",
        "playerParams": {
          "content_cdn_domain": "cdn_a",
          "ad_cdn_domain": "cdn_cf"
        }
      }'

> reportingMode명시해야 합니다. POST /v1/session으로 세션을 초기화하면 리포팅 모드의 기본값이 client가 되어, 광고 세그먼트의 최종 URL이 manifest에 직접 들어가고 아래 4단계에서 설명하는 /v1/segment 리다이렉트 홉이 사라집니다. 이 글의 전제인 서버사이드 트래킹을 유지하면서 playerParams를 전달하려면 body에 “reportingMode”: “server”를 함께 넣어야 합니다. 자세한 비교는 5장의 리포팅 모드 표를 참고하세요.

4단계: 반환된 manifestUrl로 재생하면, 각 세그먼트 URL에 변수에 매핑된 CDN 도메인이 적용됩니다. 단, 두 prefix가 적용되는 위치는 다릅니다.

콘텐츠 세그먼트는 manifest에 CDN 도메인이 직접 치환되어 나타납니다 (content_cdn_domain=cdn_a):

광고 세그먼트는 manifest에는 MediaTailor의 트래킹 경로(/v1/segment)가 상대 URL로 나타나고:

#EXTINF:2.002,
../../../../segment/<hashed-account-id>/<config>/<session-id>/0/891622302

플레이어가 이 URL을 요청하면 MediaTailor가 트래킹을 기록한 후, ad_cdn_domain에 매핑된 CDN 도메인(cdn_cf)이 적용된 URL로 리다이렉트합니다:

HTTP/2 301
Location: https://d1234567890.cloudfront.net/tm/<hashed-account-id>/<asset-id>/asset_720_5_3_000000001.cmfv

즉, AdSegmentUrlPrefix는 manifest가 아닌 리다이렉트 응답의 Location에 반영됩니다. 이 리다이렉트 메커니즘과 트래킹의 관계는 5장에서 자세히 다룹니다.

> Location경로는 /tm/ 아래로 고정됩니다. AdSegmentUrlPrefix는 호스트(와 선택적 경로 prefix)만 치환하고 그 뒤 경로는 MediaTailor가 결정합니다. 따라서 광고 CDN에는 /tm/* 패턴의 behavior를 만들고 origin을 segments.mediatailor.<region>.amazonaws.com으로 지정해야 합니다.

content_cdn_domain을 cdn_cf로 바꿔 세션을 다시 초기화하면 동일 콘텐츠 세그먼트가 CloudFront 도메인으로 치환됩니다.

> 동적 변수는 CDN 도메인 외에도 ADS URL, Content Source URL, transcode profile 등 PlaybackConfiguration의 여러 필드에 적용할 수 있습니다. 전체 필드 목록과 예시는 Configuration alias 사용 예시를 참고하세요.

적용 패턴

alias key를 누가 결정하느냐에 따라 두 가지 패턴이 가능합니다.

항목 패턴 A (클라이언트 판단) 패턴 B (서버사이드 판단)
방식 플레이어가 ISP/네트워크 상태를 판단해 alias 설정 세션 발급 서버가 클라이언트 IP 기반으로 ISP 판별 후 alias 주입
장점 별도 서버 인프라 불필요, 디바이스가 실측한 네트워크 품질 반영 가능 판별 로직을 중앙에서 즉시 변경 가능, CDN 장애 시 서버 설정만으로 신규 세션 일괄 전환
단점 로직 변경 시 앱 업데이트 필요, 구버전 클라이언트 파편화 세션 발급 서버 필요, IP 기반 ISP 판별의 정확도 한계 (VPN, 통신사 NAT 등)

CDN 장애 대응까지 고려한다면 패턴 B가 유리합니다. 클라이언트 배포 없이 서버에서 alias 매핑만 바꾸면 이후 생성되는 모든 세션이 새 CDN을 사용하기 때문입니다.

> 참고: 두 패턴 모두 CDN 전환은 세션 단위로 결정됩니다. 재생 중 CDN을 바꾸려면 새 alias key로 세션을 다시 초기화해야 합니다.

5. 광고 세그먼트 트래킹: 리다이렉트 메커니즘

멀티 CDN 환경에서 자주 받는 질문: “세그먼트가 CDN으로 직접 전송되면 광고 트래킹은 어떻게 되는가?”

서버사이드 리포팅(server-side reporting) 모드에서 광고 세그먼트 요청은 CDN으로 직행하지 않습니다. manifest에 포함된 광고 세그먼트 URL은 MediaTailor의 /v1/segment 경로를 가리키며, 플레이어가 이 URL을 요청하면 MediaTailor가 impression/quartile 트래킹 비콘을 발화한 후 301 Redirect 응답으로 CDN의 실제 세그먼트 URL을 반환합니다. 플레이어는 이 응답을 따라 CDN에서 광고 세그먼트를 다운로드합니다. 트래킹은 manifest 파싱이나 프리로드 시점이 아니라 실제 세그먼트 요청 시점에 발생하므로, IAB 기준에 부합하는 impression 집계가 가능합니다.

트래킹은 항상 MediaTailor를 경유하므로, CDN바뀌어도 트래킹 정확도에 영향이 없습니다.

리포팅 모드에 따라 광고 세그먼트 URL이 달라집니다

같은 PlaybackConfiguration, 같은 광고 브레이크라도 플레이어가 세션을 어떻게 시작했는지에 따라 manifest에 들어가는 광고 세그먼트 URL의 형태가 다릅니다.

세션 초기화 리포팅 모드 manifest의 광고 세그먼트 URL 리다이렉트 홉
GET /v1/master/… 서버사이드 (기본) /v1/segment/<hash>/<config>/<session-id>/<variant>/<media-seq> 있음 (301)
POST /v1/session/… (body 없음) 클라이언트사이드 (POST 기본값) 광고 세그먼트 최종 URL 직접 없음
POST /v1/session/… + “reportingMode”: “server” 서버사이드 /v1/segment/… 있음 (301)

클라이언트사이드 리포팅에서는 비콘 발화 책임이 플레이어로 넘어갑니다. 플레이어가 세션 초기화 응답의 trackingUrl을 폴링해 광고 이벤트를 직접 보고하므로, MediaTailor가 세그먼트 요청을 가로챌 이유가 없어 리다이렉트 홉이 사라집니다. (trackingUrl 자체는 리포팅 모드와 무관하게 POST /v1/session 응답에 항상 포함됩니다. 이 값의 존재만으로 리포팅 모드를 판단할 수는 없습니다.) 즉 이 글에서 다루는 리다이렉트 기반 트래킹과 그에 따른 CORS 이슈는 서버사이드 리포팅에만 해당합니다.

주의할 점은 4장의 도메인 변수 기능이 playerParams 전달을 위해 POST /v1/session을 요구한다는 것입니다. POST의 리포팅 모드 기본값은 client이므로, 도메인 변수를 쓰면서 서버사이드 트래킹을 유지하려면 body에 “reportingMode”: “server”를 명시해야 합니다.

브라우저 개발자 도구로 디버깅할 때 이 차이가 혼란을 일으키기 쉽습니다. hls.js나 video.js는 기본적으로 master playlist를 GET하므로 서버사이드 리포팅 경로를 타지만, 자체 세션 발급 서버를 두고 POST /v1/session으로 초기화하는 구조라면 클라이언트사이드 리포팅이 되어 /v1/segment 요청이 아예 보이지 않습니다.

6. CORS 이슈와 해결 방안

위의 요청 흐름을 보면 두 구간에서 cross-origin 통신이 발생합니다. 첫 번째는 플레이어 도메인과 MediaTailor 도메인 간의 통신 구간입니다.

플레이어 (https://player.example.com) → MediaTailor (*.mediatailor.amazonaws.com)

MediaTailor 엔드포인트는 Origin 헤더가 포함된 요청에 대해 CORS 응답 헤더(Access-Control-Allow-Origin, Access-Control-Allow-Credentials: true)를 자체적으로 반환합니다. 따라서 플레이어에서 MediaTailor로의 cross-origin 요청(manifest, session init, /v1/segment 등)은 별도 설정 없이 동작합니다. 문제가 되는 것은 301 Redirect 이후 도메인이 변경되는 두 번째 구간입니다.

플레이어 (https://player.example.com) → 광고/콘텐츠 CDN (cdn.example.com)

브라우저 기반 플레이어(hls.js, video.js 등)에서는 이 도메인 변경으로 인해 CORS 에러가 발생할 수 있습니다. CORS 에러를 해소하기 위하여 광고 및 콘텐츠 세그먼트를 전송하는 CDN에 Access-Control-Allow-Origin 헤더 설정이 필요합니다.

보안을 위해서는 * 대신 허용할 도메인을 한정시켜 정의하는 것이 권장됩니다. 단 이 방식은 콘텐츠 세그먼트에만 적용할 수 있고, 리다이렉트 뒤에 오는 광고 세그먼트에는 쓸 수 없습니다. 이유는 뒤에서 설명합니다.

여기서 놓치기 쉬운 것이 하나 있습니다. Fetch 스펙상 CORS 요청은 리다이렉트 체인의 모든 응답이 CORS 검사를 통과해야 합니다. 즉 최종 CDN 응답만이 아니라 301 응답 자체에도 Access-Control-Allow-Origin있어야 합니다. MediaTailor 엔드포인트를 플레이어에 직접 노출하는 구성이라면 MediaTailor가 이 헤더를 알아서 붙이므로 신경 쓸 것이 없습니다. 반면 /v1/segment 요청을 CDN behavior로 감싼다면, 그 behavior가 Origin 요청 헤더를 MediaTailor까지 전달하도록 구성해야 합니다.

정리하면 CORS 헤더가 필요한 지점은 세 곳입니다.

지점 대상 필요한 이유 Access-Control-Allow-Origin
manifest MediaTailor 매니페스트 응답 플레이어가 XHR로 manifest를 읽음 MediaTailor가 요청한 도메인을 그대로 반환
리다이렉트 홉 /v1/segment 301 응답 리다이렉트 체인의 중간 응답도 CORS 검사 대상 MediaTailor가 요청한 도메인을 그대로 반환
광고 세그먼트 리다이렉트 대상 CDN 최종 리소스 읽기 *

앞의 두 지점은 MediaTailor가 처리하므로 별도 설정이 필요 없고, 마지막 광고 세그먼트만 *가 적용됩니다. 같은 재생 세션 안에서 CORS 정책이 두 종류로 갈리는 셈인데, 이는 리다이렉트 구조에서 비롯된 결과입니다.

CDN 설정 방법은 다음과 같습니다.

  • CloudFront: behavior를 manifest(/v1/master/* 등), 리다이렉트 홉(/v1/segment/*), 광고 세그먼트(/tm/*), 콘텐츠로 분리하고 각각에 Response Headers Policy로 Access-Control-Allow-Origin을 설정합니다. 이때 각 behavior에서 Origin Request PolicyOrigin 헤더를 오리진까지 전달해야 합니다. 오리진이 요청 도메인을 알아야 그에 맞는 CORS 응답을 만들 수 있기 때문입니다
  • 서드파티 CDN: 각 CDN 환경에서 위 경로별로 CORS 헤더를 설정합니다. CDN이 path별 CORS 설정을 지원하지 않으면 CloudFront를 Origin으로 구성하여 해결합니다
  • CloudFront Functions: 요청의 Origin 헤더 값을 기반으로 Access-Control-Allow-Origin 응답 헤더를 동적으로 설정하면, 서드파티 CDN은 별도의 CORS 처리 없이 단순 캐싱 역할만 유지 가능

관리형 CORS 정책은 Origin의 헤더를 덮어쓰지 않습니다

CloudFront 관리형 CORS 정책은 OriginOverride: false로 정의되어 있습니다. 오리진이 이미 Access-Control-Allow-Origin을 내려주면 정책 값을 적용하지 않는다는 뜻입니다. MediaTailor와 광고 세그먼트 CDN은 CORS 헤더를 스스로 반환하므로, 이 경로에 관리형 정책을 붙여도 CORS 값은 바뀌지 않고 보안 헤더만 추가됩니다. CORS 값을 직접 지정하려면 OriginOverride: true인 커스텀 정책이 필요합니다.

광고 세그먼트만 *를 써야 합니다

리다이렉트를 따라가는 요청은 Origin 헤더가 null이 됩니다. Fetch 스펙에 정의된 동작으로, MDN Origin 헤더 문서의 null 케이스 중 “Redirects across origins”에 해당합니다.

GET /v1/segment/...   Origin: https://player.example.com   → 301
GET /tm/...           Origin: null

*는 null과도 매칭되지만 허용 도메인 목록에는 null해당되지 않습니다. 허용 목록을 지정한 CDN은 이 요청에 Access-Control-Allow-Origin을 붙이지 않으므로 브라우저가 세그먼트를 차단합니다. 목록에 null을 등록하는 것도 불가능합니다. CloudFront는 유효한 URL이 아니라는 이유로 거부합니다.

따라서 광고 세그먼트는 *를 그대로 두어야 합니다. CloudFront Functions로 Access-Control-Allow-Origin: null을 직접 내리는 우회로가 있지만, sandboxed iframe이나 data: 문서도 null을 보내므로 *보다 오히려 넓게 열립니다. 광고 크리에이티브는 공개 자산이고 impression 집계는 /v1/segment에서 이뤄지므로, *를 좁혀서 얻는 보안 이점도 크지 않습니다.

> 허용 도메인 목록은 콘텐츠 세그먼트와 manifest적용하세요. 이 경로들은 리다이렉트를 거치지 않아 실제 도메인이 유지됩니다. 목록을 지정하려면 OriginOverride: true인 커스텀 Response Headers Policy를 사용합니다. 이 정책은 응답을 내보내는 시점에 요청별로 평가되므로, 캐시 히트에서도 요청 도메인에 맞는 값이 반환되어 7장의 오염 문제가 발생하지 않습니다.

CORS는 브라우저의 cross-origin 읽기를 제어하는 정책일 뿐 접근 제어 수단은 아닙니다. 콘텐츠 자체의 보호는 토큰 인증으로 처리해야 합니다(Part 2에서 다룹니다).

7. 캐싱 키 설정 및 Origin 전달 파라미터 정책

멀티 CDN 환경에서 캐싱 키와 Origin 전달 파라미터를 올바르게 설정하는 것이 중요합니다.

> 지금까지의 시나리오는 manifest를 CDN을 경유하지 않고 MediaTailor로 직접 요청하는 구성이므로 Manifest behavior 설정이 필요하지 않습니다. 아래 Manifest behavior 표는 manifest 요청도 CDN을 경유하는 구조일 때 참고하세요.

Manifest behavior:

설정 항목 권장 값 이유
Cache Key – Query Strings All 또는 필요한 파라미터만 MediaPackage 또는 서드파티 packager에 동적 파라미터 전달이 필요할 수 있으므로, timeshift(start, end), time_delay 등 기능별 파라미터를 포함
Cache Key – Headers None TTL 0으로 캐싱을 끄므로 캐시 키 구성은 의미가 없음. CORS 응답 헤더는 캐시가 아니라 응답 헤더 정책으로 처리
Origin Request – Query Strings All MediaTailor를 거쳐 Origin(MediaPackage)에 기능 파라미터 전달 필요
Origin Request – Headers Host 제외 전달 (AllViewerExceptHostHeader) MediaTailor의 디바이스 감지, geo 타겟팅, manifest 압축에 User-Agent, X-Forwarded-For, Accept-Encoding 전달이 필수 (필수 헤더 문서)
TTL 0초 (캐싱 비활성화) MediaTailor personalized manifest는 시청자별로 다르므로 캐싱하면 안 됨 (참고)

Segment behavior:

정 항목 권장 값 이유
Cache Key – Query Strings None 세그먼트는 URL path로 고유 식별, 캐시 효율 극대화
Cache Key – Headers None 세그먼트는 URL만으로 고유하게 식별되므로 헤더 구분이 불필요. 단 허용 도메인을 한정한 경로라면 Origin을 포함해야 함 (아래 참고)
TTL (콘텐츠) Origin Cache-Control 따름 MediaPackage는 세그먼트에 긴 Cache-Control을 내려주므로 그대로 따라가면 됨
TTL (광고) Default TTL 24시간 명시 광고 세그먼트 응답에는 Cache-Control 헤더가 없어 Origin 값을 따를 수 없음. CDN에서 Default TTL을 직접 지정해야 캐시가 동작

> 주의: 리다이렉트 홉(/v1/segment/*)은 세그먼트가 아니라 트래킹 지점입니다. 이 경로를 캐싱하면 비콘이 발화되지 않아 광고 집계가 누락되므로 TTL 0(캐싱 비활성)으로 두어야 합니다. 실제로 캐싱해야 하는 것은 리다이렉트 대상인 /tm/* 경로입니다.

> 주의: Origin Request Policy에서 All viewer headers(Host 포함)를 사용하면 플레이어가 보낸 Host 헤더(CDN 도메인)가 그대로 Origin으로 전달됩니다. MediaPackage를 Origin으로 하는 behavior에서는 자신의 endpoint 호스트네임이 아닌 Host를 거부하여 403 에러가 발생합니다. 헤더를 아예 전달하지 않으면 이 문제는 피할 수 있지만 위에서 언급한 필수 헤더까지 끊기므로, CloudFront 관리형 정책 AllViewerExceptHostHeader처럼 Host만 제외하고 전달하는 구성이 정답입니다.

> MediaTailor 전용 관리형 Origin Request Policy있습니다. AllViewerExceptHostHeader 대신 Managed-Elemental-MediaTailor-PersonalizedManifests를 쓰면 CORS와 디바이스 감지에 필요한 헤더(Origin, X-Forwarded-For, User-Agent 등)만 화이트리스트로 전달하고 query string은 전부 전달합니다. Host가 빠지므로 403 문제도 없습니다. 단 Accept-Encoding은 전달하지 않으므로 manifest 압축은 CloudFront의 Compress 옵션으로 처리해야 합니다.

Origin이 캐시 키에 없으면 CORS 응답이 오염됩니다

CORS 응답 헤더가 요청 도메인에 따라 달라지는 경로를 캐싱할 때는, 캐시 키에 Origin을 포함해야 합니다. 포함하지 않으면 서로 다른 도메인의 요청이 같은 캐시 항목을 공유하게 되고, 두 번째 요청은 첫 요청의 도메인이 담긴 응답을 그대로 받습니다.

요청 요청 도메인 응답 Access-Control-Allow-Origin 캐시
1 https://player-a.example.com https://player-a.example.com Miss
2 https://player-b.example.com https://player-a.example.com Hit

두 번째 요청은 자신의 도메인이 아닌 값을 받았으므로 브라우저가 응답을 차단합니다.

> Vary: Origin문제를 막아주지 않습니다. MediaTailor는 Vary: Origin을 함께 반환하지만, CloudFront는 캐시 키에 없는 헤더에 대한 Vary를 응답에서 제거합니다. 브라우저는 응답이 도메인별로 달라져야 한다는 사실조차 알 수 없게 됩니다. Vary에 의존하지 말고  직접 포함시켜야 합니다.

서드파티 CDN을 사용할 때는 헤더 기반 캐싱 키 지원 여부도 확인해야 합니다. 서드파티 CDN에서 CORS 구성을 할 수 없는 환경이라면, CORS 응답은 자체 오리진(혹은 오리진으로 바라보는 CloudFront)에서 구현되어야 합니다. 이를 위해서는 오리진 방향으로 Origin 헤더를 반드시 전달해야 하며, Origin 헤더를 캐시 키에 포함시켜 Origin별로 적절한 CORS 응답 헤더가 캐싱되도록 서드파티 CDN을 구성해야 합니다. CDN이 Origin을 캐싱 키에 포함하지 못하면 위와 같은 오염이 발생하므로, 이 경우 CloudFront를 Origin으로 두어 CORS 처리를 위임하는 것이 안전합니다.

이 내용은 manifest와 콘텐츠 세그먼트처럼 요청 도메인에 따라 CORS 응답이 달라지는 경로에 해당합니다. Access-Control-Allow-Origin: *를 반환하는 광고 세그먼트는 응답이 도메인별로 갈리지 않으므로 캐시 키에 Origin을 넣을 필요가 없습니다.

8. 결론

멀티 CDN 구성에서 가장 먼저 이해할 것은 두 CDN prefix가 적용되는 위치가 다르다는 점입니다. ContentSegmentUrlPrefix는 manifest에 직접 치환되고, AdSegmentUrlPrefix는 301 리다이렉트 응답의 Location에 반영됩니다. 광고 요청이 항상 MediaTailor를 경유하는 이 구조 덕분에, CDN을 어떻게 조합하고 전환하든 광고 트래킹 정확도는 유지됩니다.

동적 전환은 Configuration Aliases 하나로 충분합니다. CDN 조합별로 Config를 여러 개 만들 필요 없이, 세션 초기화 시 alias key만 바꾸면 됩니다. 장애 대응까지 고려한다면 alias 결정을 서버사이드에 두는 것을 권합니다.

실제로 문제가 생기는 지점은 기능 자체보다 CDN 설정 디테일입니다. Host 헤더 전달로 인한 MediaPackage 403, 리다이렉트 이후 도메인 변경으로 발생하는 CORS 에러, 리다이렉트 홉에 CORS 헤더가 빠져 체인 중간에서 차단되는 경우, personalized manifest가 캐싱되는 사고가 대표적입니다. 7장의 표를 배포 전 체크리스트로 활용하시기 바랍니다.

디버깅할 때는 리포팅 모드를 먼저 확인하세요. 서버사이드 리포팅이면 개발자 도구 네트워크 탭에 /v1/segment 요청과 301 응답이 보이고, 클라이언트사이드 리포팅이면 광고 세그먼트 요청이 CDN으로 바로 나갑니다. 같은 설정인데 동작이 다르게 보이는 경우가 대부분 여기서 갈립니다.

토큰 인증, MediaPackage Origin 보안, 서드파티 CDN 제약 대응 등 보안 심화 내용은 [Part 2]에서 다룹니다.

참고 자료

Yuntaek Lim

Yuntaek Lim

임윤택 솔루션즈 아키텍트는 미디어 및 엔터테인먼트 고객들이 원하는 비즈니스 결과를 달성할 수 있도록 최적의 아키텍처를 설계하는 역할을 맡고 있습니다. OTT 산업의 기술 배경지식을 바탕으로 미디어 산업에 기술적으로 기여하고자 노력하고 있습니다.

Gabin Lee

Gabin Lee

이갑인 솔루션즈 아키텍트는 다양한 AWS 엣지 서비스를 활용하여 확장 가능하고 탄력적이며 안전한 아키텍처를 구축하는 것에 열정적이며, 특히 CloudFront, Global Accelerator, WAF, Shield 등과 같은 AWS 엣지 서비스를 활용하고 있는 한국 고객들을 집중적으로 지원하고 있습니다.