CloudFront CDN 실전 가이드 3편: 사설 콘텐츠·엣지 로직·보안·모니터링

CloudFront CDN 실전 가이드 3편: 사설 콘텐츠·엣지 로직·보안·모니터링


서론

1편에서 개념을, 2편에서 Spring Boot + Kotlin 오리진을 CloudFront로 올리는 실습을 했다. 기본 동작은 갖췄으니, 이번 3편은 실제 운영에 필요한 네 가지를 다룬다.

다룰 주제: ① 사설 콘텐츠(Signed URL/쿠키), ② 엣지 로직(Functions vs Lambda@Edge), ③ 보안(커스텀 도메인·OAC·WAF), ④ 모니터링·비용.


TL;DR

  • 비공개 콘텐츠는 서명으로 보호한다 — 서명된 URL(파일 1개)이나 서명된 쿠키(여러 파일)로, 권한 있는 사용자만 일정 시간 동안 접근하게 한다.
  • 엣지에서 가벼운 로직을 돌린다 — 단순 헤더 조작·리다이렉트는 초경량 CloudFront Functions, 네트워크 호출·복잡한 로직은 Lambda@Edge.
  • 둘의 분기 기준은 무게 — Functions는 1ms·뷰어 단계만·매우 저렴, Lambda@Edge는 더 무겁고 4개 트리거에 네트워크 가능.
  • 보안은 세 겹 — TLS 인증서로 커스텀 도메인(HTTPS), S3는 오리진 접근 제어(OAC)로 직접 접근 차단, 웹 방화벽(WAF)·지역 차단으로 트래픽 필터.
  • 운영은 적중률로 본다 — 캐시 적중률·에러율·전송량을 지표로 보고, 가격 등급·압축·적중률로 비용을 줄인다.

기본 CloudFront 배포는 누구나 URL만 알면 접근할 수 있다. 유료 동영상, 회원 전용 파일처럼 권한 있는 사용자만 접근시키려면 서명(signing)이 필요하다.

방식적합한 경우특징
Signed URL파일 하나 (특정 동영상·다운로드 링크)URL에 서명·만료시각 포함. URL이 길어짐
Signed Cookie여러 파일·경로 전체 (회원 전용 섹션)쿠키로 권한 부여, URL은 그대로. 다수 자산에 적합

동작 원리: 백엔드(신뢰 서버)가 개인 키로 정책(만료시각·허용 경로)에 서명하고, CloudFront는 등록된 공개 키로 검증한다. 서명이 유효하고 안 만료됐을 때만 콘텐츠를 내려준다.

flowchart LR
    app["백엔드<br/>(개인 키로 서명)"] -->|"서명된 URL/쿠키 발급"| client["클라이언트"]
    client -->|"요청 + 서명"| cf["CloudFront<br/>(공개 키로 검증)"]
    cf -->|"유효하면 전달"| origin["오리진"]

Terraform으로 공개 키와 키 그룹을 등록하고, Behavior에 연결한다.

resource "aws_cloudfront_public_key" "app" {
  name        = "app-public-key"
  encoded_key = file("public_key.pem")   # RSA 공개 키 (PEM)
}

resource "aws_cloudfront_key_group" "app" {
  name  = "app-key-group"
  items = [aws_cloudfront_public_key.app.id]
}

# 보호할 Behavior에 추가:
#   trusted_key_groups = [aws_cloudfront_key_group.app.id]

trusted_key_groups가 걸린 Behavior는 유효한 서명 없이는 403을 반환한다. 서명 생성은 백엔드(예: AWS SDK의 CloudFront signer)에서 개인 키로 수행한다.


2. 엣지 로직 — CloudFront Functions vs Lambda@Edge

엣지에서 요청·응답을 가로채 로직을 실행할 수 있다. 두 가지 수단이 있고, “무게”로 나뉜다.

기준CloudFront FunctionsLambda@Edge
언어JavaScript (경량 런타임)Node.js / Python
실행 위치모든 엣지 로케이션리저널 엣지 캐시(+뷰어)
트리거viewer-request, viewer-responseviewer/origin × request/response (4종)
실행 시간1ms 미만최대 수~수십 초
네트워크 호출불가가능 (외부 API·DB)
비용매우 저렴더 비쌈
용도헤더 조작, 리다이렉트, URL 재작성, 토큰 형식 검사오리진 분기, 외부 인증, 이미지 변환 등 무거운 로직

고르는 법: “헤더 손보기·간단 리다이렉트·URL 정규화”면 거의 항상 CloudFront Functions(싸고 빠르다). “외부 호출·복잡한 분기·오리진 응답 가공”이 필요할 때만 Lambda@Edge.

예시 — viewer-request에서 보안 헤더 검사 (CloudFront Functions)

// auth.js — Authorization 헤더 없으면 401
function handler(event) {
  var request = event.request;
  if (!request.headers['authorization']) {
    return {
      statusCode: 401,
      statusDescription: 'Unauthorized',
    };
  }
  return request; // 통과
}
resource "aws_cloudfront_function" "auth" {
  name    = "viewer-auth"
  runtime = "cloudfront-js-2.0"
  publish = true
  code    = file("auth.js")
}

# Behavior에 연결:
#   function_association {
#     event_type   = "viewer-request"
#     function_arn = aws_cloudfront_function.auth.arn
#   }

3. 보안 — 커스텀 도메인, OAC, WAF

3.1 커스텀 도메인 + TLS 인증서 (ACM)

d123.cloudfront.net 대신 cdn.example.com을 쓰려면 ACM 인증서가 필요하다. CloudFront용 인증서는 반드시 us-east-1 리전에 있어야 한다(글로벌 서비스라 버지니아 북부에서 관리).

# CloudFront용 인증서는 us-east-1 고정
resource "aws_acm_certificate" "cdn" {
  provider          = aws.us_east_1
  domain_name       = "cdn.example.com"
  validation_method = "DNS"
}

# 배포에 추가:
#   aliases = ["cdn.example.com"]
#   viewer_certificate {
#     acm_certificate_arn      = aws_acm_certificate.cdn.arn
#     ssl_support_method       = "sni-only"
#     minimum_protocol_version = "TLSv1.2_2021"
#   }

이후 Route53(또는 DNS 제공자)에서 cdn.example.com을 배포 도메인으로 CNAME/별칭 연결한다.

3.2 S3 오리진 — OAC로 직접 접근 차단

정적 자산을 S3에 둔다면(2편 1절의 옵션), 버킷을 공개하면 안 된다. OAC(Origin Access Control)로 “CloudFront만 S3에 접근”하게 하고 버킷은 비공개로 둔다. (구형 OAI는 더 이상 권장되지 않는다.)

resource "aws_cloudfront_origin_access_control" "s3" {
  name                              = "s3-oac"
  origin_access_control_origin_type = "s3"
  signing_behavior                  = "always"
  signing_protocol                  = "sigv4"
}

# S3 오리진에 origin_access_control_id 연결 + 버킷 정책에서
# cloudfront.amazonaws.com 서비스 주체에 AWS:SourceArn(배포 ARN) 조건으로만 허용
flowchart LR
    user["사용자"] --> cf["CloudFront (OAC 서명)"]
    cf -->|sigv4 서명 요청만| s3["S3 (비공개 버킷)"]
    direct["직접 접근 시도"] -.차단(403).-> s3

3.3 WAF·지역 차단

웹 방화벽(WAF)으로 SQL 인젝션·악성 봇·요청 폭주(rate limit)를 엣지에서 거른다. CloudFront용 WAF는 scope = "CLOUDFRONT"로 만들고 us-east-1에 둔다.

resource "aws_wafv2_web_acl" "cdn" {
  provider = aws.us_east_1
  name     = "cdn-waf"
  scope    = "CLOUDFRONT"
  # ... 관리형 규칙 그룹(AWSManagedRulesCommonRuleSet 등) + rate-based 규칙 ...
}

# 배포에 추가: web_acl_id = aws_wafv2_web_acl.cdn.arn

특정 국가만 허용/차단하려면 배포의 geo_restriction을 쓴다.

restrictions {
  geo_restriction {
    restriction_type = "whitelist"
    locations        = ["KR", "US", "JP"]
  }
}

4. 모니터링·비용

4.1 무엇을 보나

CloudFront는 CloudWatch로 핵심 지표를 노출한다.

지표의미본다는 것은
캐시 적중률(Cache Hit Rate)hit / 전체 비율낮으면 오리진 부하·비용↑ → 캐시 키·TTL 점검
4xx / 5xx 에러율오류 응답 비율5xx 급증 = 오리진 장애, 4xx = 권한·경로 문제
BytesDownloaded전송량비용·트래픽 추세
OriginLatency오리진 응답 지연높으면 오리진 병목

참고: 적중률 같은 상세 지표는 배포의 추가 지표(additional metrics)를 켜야 CloudWatch에 올라온다. 기본 지표만으로는 적중률을 정확히 못 본다.

로그는 두 가지다 — S3로 떨구는 표준 로그(사후 분석용)와, 초 단위로 흘려보내는 실시간 로그(Kinesis 등으로). 캐시 miss가 잦은 경로를 찾을 때 로그가 결정적이다.

4.2 비용 줄이기

CloudFront 비용은 크게 전송량 + 요청 수 + (무효화·Lambda@Edge)다.

  • 적중률을 올린다: 캐시 키를 최소화하고(쿠키 제거), 정적은 길게 캐시. 적중률이 곧 비용이다.
  • 압축을 켠다: compress = true로 전송량을 줄인다.
  • 가격 등급(Price Class): 전 세계 엣지가 필요 없으면 PriceClass_100(북미·유럽) 등으로 제한해 비용을 낮춘다.
  • Origin Shield: 오리진 앞에 한 겹 더 두면 오리진 적중을 줄여 부하·전송을 절감(트래픽 큰 경우).

정리

여기까지 CloudFront를 개념부터 운영까지 다뤘다.

Part주제핵심
1편개념엣지 캐시·캐시 키·Cache-Control/TTL·무효화 vs 버저닝
2편실습Spring Boot+Kotlin 오리진 + Behavior 분리 + Terraform + X-Cache 검증
3편운영사설 콘텐츠·엣지 로직·보안(도메인·OAC·WAF)·모니터링

CDN 설계의 본질은 한 문장이다 — “무엇을, 누구에게, 얼마나 오래 캐시할지”를 경로별로 분리하고, 그 의도를 오리진 헤더와 CloudFront Behavior에 일관되게 박는 것. 여기에 서명·엣지 로직·보안·모니터링을 얹으면 프로덕션 CDN이 완성된다.

마지막 4편에서는 미디어를 다룬다. 사용자가 올린 이미지를 온디맨드로 리사이징해 캐싱하고(Lambda@Edge), 영상은 MediaConvert로 트랜스코딩해 HLS/DASH로 CloudFront에서 전송하는 — 정적·동적을 넘어선 미디어 서빙을 정리한다.


부록

A. 의사결정 치트시트

상황선택
비공개 파일 1개Signed URL
비공개 경로 전체Signed Cookie
헤더 조작·리다이렉트CloudFront Functions
외부 호출·복잡 로직Lambda@Edge
커스텀 도메인 HTTPSACM 인증서(us-east-1) + sni-only
S3 정적 비공개OAC + 비공개 버킷 정책
봇·인젝션·폭주 방어WAF (scope=CLOUDFRONT)
비용 절감적중률↑ + 압축 + Price Class + Origin Shield

B. 용어집

용어설명
Signed URL/Cookie서명·만료로 권한 있는 사용자만 접근시키는 비공개 콘텐츠 방식
CloudFront Functions모든 엣지에서 도는 초경량 JS (헤더·리다이렉트)
Lambda@Edge리저널 엣지에서 도는 Node/Python (네트워크·복잡 로직)
ACMAWS Certificate Manager. TLS 인증서 관리 (CloudFront는 us-east-1)
OACOrigin Access Control. CloudFront만 S3에 접근하게 하는 제어
WAF웹 애플리케이션 방화벽. 엣지에서 악성 트래픽 필터
Origin Shield오리진 앞 추가 캐시 계층. 오리진 적중·부하 절감
Price Class사용할 엣지 지역 범위. 좁히면 비용↓

C. 참고 자료

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.