웹사이트와 애플리케이션의 성능을 전 세계적으로 향상시키는 두 가지 핵심 서비스
:1. CloudFront는 콘텐츠를 엣지 로케이션에 캐싱하고 2. Global Accelerator는 AWS 글로벌 네트워크를 통해 트래픽을 최적화한다
CloudFront
CloudFront는 AWS의 CDN(Content Delivery Network) 서비스로, 전 세계 450개 이상의 엣지 로케이션에서 콘텐츠를 제공
사용자 (서울) ↓ 요청 엣지 로케이션 (서울) ↓ 캐시 미스 오리진 (버지니아) ↓ 콘텐츠 반환 엣지 로케이션 (캐싱) ↓ 빠른 응답 사용자 두 번째 요청: 사용자 → 엣지 (캐시 히트) → 즉시 반환
주요 장점
1. 성능 향상
- 지연 시간 감소 (평균 50-90% 감소)
- 엣지 로케이션에서 즉시 제공
- 오리진 서버 부하 감소
2. 글로벌 배포
- 450+ 엣지 로케이션
- 자동 라우팅
- 지역별 최적화
3. 보안
- DDoS 보호 (AWS Shield Standard 포함)
- HTTPS 지원
- 지리적 제한
- AWS WAF 통합
4. 비용 효율
- 데이터 전송 비용 절감
- 오리진 부하 감소
- 프리 티어: 월 50GB 데이터 전송
CloudFront vs 직접 배포
직접 S3 배포:
서울 사용자 → 버지니아 S3
- 지연시간: 200-300ms
- 비용: 높음 (리전 간 전송)
CloudFront:
서울 사용자 → 서울 엣지 → (캐시 히트) 즉시 반환
- 지연시간: 10-20ms (95% 감소)
- 비용: 낮음 (엣지에서 처리)
비용 최적화
CloudFront 비용 구조
데이터 전송 (가장 큰 비용):
리전별 가격 (per GB):
- 북미, 유럽: $0.085
- 아시아 (일본 제외): $0.140
- 남미: $0.250
- 오스트레일리아: $0.170
프리 티어:
- 월 50GB 데이터 전송
- 월 2백만 HTTP/HTTPS 요청
요청:
HTTP/HTTPS:
- $0.0075 ~ $0.0100 / 10,000 요청
HTTPS 요청 (추가):
- $0.0100 / 10,000 요청
Invalidation:
- 처음 1,000개/월: 무료
- 이후: $0.005/개
절감 전략
1. Price Class 조정
# 서비스 지역이 북미/유럽이면
aws cloudfront update-distribution \
--id E1234567890ABC \
--price-class PriceClass_100
# 절감: 약 20-30%
2. Compression 활성화
# Gzip/Brotli 압축 활성화
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config '{
"DefaultCacheBehavior": {
"Compress": true
}
}'
# 효과: 데이터 전송량 70-90% 감소
예시:
압축 전:
- app.js: 500KB × 1,000,000 요청 = 500GB
- 비용: 500GB × $0.085 = $42.50
압축 후:
- app.js: 100KB (80% 압축) × 1,000,000 = 100GB
- 비용: 100GB × $0.085 = $8.50
- 절감: $34.00 (80%)
3. 캐시 최적화
캐시 히트율 향상:
60% → 90%
효과:
- 오리진 요청: 40% → 10% (75% 감소)
- 오리진 비용: $100 → $25
- 지연시간: 100ms → 10ms
4. Lambda@Edge 대신 CloudFront Functions
Lambda@Edge:
- $0.60 / 백만 요청
- $0.00001667 / GB-초
CloudFront Functions:
- $0.10 / 백만 요청
- 추가 컴퓨팅 비용 없음
절감: 83%
5. Origin Shield
중간 캐싱 레이어를 추가하여 오리진 부하를 줄인다.
Origin Shield 없음:
450+ 엣지 → 오리진 (많은 요청)
Origin Shield 사용:
450+ 엣지 → Origin Shield (1곳) → 오리진
└─ 오리진 요청 90% 감소
비용:
Origin Shield: $0.005 / 10,000 요청
오리진 비용 절감: $0.020 / 10,000 요청
순 절감: $0.015 / 10,000 요청
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config '{
"Origins": {
"Items": [{
"Id": "S3-my-bucket",
"DomainName": "my-bucket.s3.amazonaws.com",
"OriginShield": {
"Enabled": true,
"OriginShieldRegion": "us-east-1"
}
}]
}
}'
보안 모범 사례
1. HTTPS 강제
// CloudFront Function
function handler(event) {
var request = event.request;
if (request.headers['cloudfront-forwarded-proto']
&& request.headers['cloudfront-forwarded-proto'].value === 'http') {
return {
statusCode: 301,
statusDescription: 'Moved Permanently',
headers: {
'location': {
value: 'https://' + request.headers.host.value + request.uri
}
}
};
}
return request;
}
2. 보안 헤더 추가
function handler(event) {
var response = event.response;
var headers = response.headers;
// Security headers
headers['strict-transport-security'] = {
value: 'max-age=63072000; includeSubdomains; preload'
};
headers['content-security-policy'] = {
value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
};
headers['x-content-type-options'] = {
value: 'nosniff'
};
headers['x-frame-options'] = {
value: 'DENY'
};
headers['x-xss-protection'] = {
value: '1; mode=block'
};
headers['referrer-policy'] = {
value: 'strict-origin-when-cross-origin'
};
headers['permissions-policy'] = {
value: 'geolocation=(), microphone=(), camera=()'
};
return response;
}
3. AWS WAF 통합
# WAF WebACL 생성
aws wafv2 create-web-acl \
--name my-waf-acl \
--scope CLOUDFRONT \
--default-action Allow={} \
--rules file://waf-rules.json
# CloudFront에 연결
aws cloudfront update-distribution \
--id E1234567890ABC \
--web-acl-id arn:aws:wafv2:us-east-1:account-id:global/webacl/my-waf-acl/id
WAF 규칙 예시:
{
"Rules": [
{
"Name": "RateLimitRule",
"Priority": 1,
"Statement": {
"RateBasedStatement": {
"Limit": 2000,
"AggregateKeyType": "IP"
}
},
"Action": {
"Block": {}
}
},
{
"Name": "SQLInjectionRule",
"Priority": 2,
"Statement": {
"SqliMatchStatement": {
"FieldToMatch": {
"QueryString": {}
},
"TextTransformations": [{
"Priority": 0,
"Type": "URL_DECODE"
}]
}
},
"Action": {
"Block": {}
}
},
{
"Name": "GeoBlockRule",
"Priority": 3,
"Statement": {
"GeoMatchStatement": {
"CountryCodes": ["CN", "RU"]
}
},
"Action": {
"Block": {}
}
}
]
}
4. Signed URLs/Cookies (프리미엄 콘텐츠)
Signed URL 생성:
import boto3
from datetime import datetime, timedelta
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from botocore.signers import CloudFrontSigner
import base64
def rsa_signer(message):
with open('private_key.pem', 'rb') as key_file:
private_key = serialization.load_pem_private_key(
key_file.read(),
password=None
)
return private_key.sign(message, padding.PKCS1v15(), hashes.SHA1())
# CloudFront Signer 생성
cf_signer = CloudFrontSigner('APKAEIBAERJR2EXAMPLE', rsa_signer)
# Signed URL 생성
url = 'https://d111111abcdef8.cloudfront.net/premium-video.mp4'
expire_date = datetime.now() + timedelta(hours=1)
signed_url = cf_signer.generate_presigned_url(
url,
date_less_than=expire_date
)
print(signed_url)
Signed Cookie 생성:
policy = {
"Statement": [{
"Resource": "https://d111111abcdef8.cloudfront.net/premium/*",
"Condition": {
"DateLessThan": {
"AWS:EpochTime": int((datetime.now() + timedelta(hours=24)).timestamp())
}
}
}]
}
signed_cookies = cf_signer.generate_presigned_cookie(
url,
date_less_than=expire_date
)
# 쿠키 설정
# CloudFront-Policy=...
# CloudFront-Signature=...
# CloudFront-Key-Pair-Id=...
트러블슈팅
문제 1: 504 Gateway Timeout
원인:
- 오리진 응답 느림 (>30초)
- 오리진 서버 다운
해결:
# 1. 오리진 타임아웃 확인
aws cloudfront get-distribution-config --id E1234567890ABC \
| jq '.DistributionConfig.Origins.Items[0].CustomOriginConfig.OriginReadTimeout'
# 2. 타임아웃 증가 (최대 60초)
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config '{
"Origins": {
"Items": [{
"CustomOriginConfig": {
"OriginReadTimeout": 60
}
}]
}
}'
# 3. 오리진 헬스 체크
curl -I https://origin-server.example.com/health
문제 2: 캐시가 업데이트되지 않음
원인:
- 긴 TTL
- 잘못된 Cache-Control 헤더
해결:
# 1. 즉시 무효화
aws cloudfront create-invalidation \
--distribution-id E1234567890ABC \
--paths "/*"
# 2. 오리진 헤더 확인
curl -I https://d111111abcdef8.cloudfront.net/index.html
# 3. Cache-Control 헤더 수정
aws s3api copy-object \
--bucket my-bucket \
--key index.html \
--copy-source my-bucket/index.html \
--metadata-directive REPLACE \
--cache-control "max-age=3600" \
--content-type "text/html"
문제 3: CORS 에러
원인:
- 오리진에 CORS 헤더 없음
- CloudFront가 CORS 헤더를 캐시하지 않음
해결:
# 1. Origin Request Policy 생성
aws cloudfront create-origin-request-policy \
--origin-request-policy-config '{
"Name": "CORS-Policy",
"HeadersConfig": {
"HeaderBehavior": "whitelist",
"Headers": {
"Items": ["Origin", "Access-Control-Request-Headers", "Access-Control-Request-Method"]
}
}
}'
# 2. Response Headers Policy 생성
aws cloudfront create-response-headers-policy \
--response-headers-policy-config '{
"Name": "CORS-Headers",
"CorsConfig": {
"AccessControlAllowOrigins": {
"Items": ["https://example.com"]
},
"AccessControlAllowHeaders": {
"Items": ["*"]
},
"AccessControlAllowMethods": {
"Items": ["GET", "POST", "OPTIONS"]
},
"AccessControlAllowCredentials": false,
"OriginOverride": true
}
}'
문제 4: 높은 비용
원인:
- 불필요한 엣지 로케이션
- 낮은 캐시 히트율
- 압축 미사용
해결:
# 1. 캐시 히트율 확인
aws cloudwatch get-metric-statistics \
--namespace AWS/CloudFront \
--metric-name CacheHitRate \
--dimensions Name=DistributionId,Value=E1234567890ABC \
--start-time 2024-11-01T00:00:00Z \
--end-time 2024-11-19T23:59:59Z \
--period 86400 \
--statistics Average
# 2. Price Class 변경
aws cloudfront update-distribution \
--id E1234567890ABC \
--price-class PriceClass_100
# 3. Compression 활성화
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config '{"DefaultCacheBehavior": {"Compress": true}}'
# 4. Origin Shield 활성화
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config '{
"Origins": {
"Items": [{
"OriginShield": {
"Enabled": true,
"OriginShieldRegion": "us-east-1"
}
}]
}
}'
실전 프로젝트: 완전한 정적 웹사이트 배포
1단계: S3 버킷 및 콘텐츠 준비
# 버킷 생성
aws s3 mb s3://my-website-bucket
# 웹사이트 파일 업로드
aws s3 sync ./build/ s3://my-website-bucket/ \
--cache-control "max-age=31536000" \
--exclude "*.html" \
--exclude "service-worker.js"
# HTML 파일 (짧은 캐시)
aws s3 sync ./build/ s3://my-website-bucket/ \
--cache-control "max-age=3600" \
--exclude "*" \
--include "*.html"
2단계: CloudFront 배포 생성
aws cloudfront create-distribution \ --origin-domain-name my-website-bucket.s3.amazonaws.com \ --default-root-object index.html \ --distribution-config file://distribution-config.json
distribution-config.json:
{
"CallerReference": "my-website-2024",
"Origins": {
"Quantity": 1,
"Items": [{
"Id": "S3-my-website",
"DomainName": "my-website-bucket.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
},
"OriginShield": {
"Enabled": true,
"OriginShieldRegion": "us-east-1"
}
}]
},
"DefaultCacheBehavior": {
"TargetOriginId": "S3-my-website",
"ViewerProtocolPolicy": "redirect-to-https",
"Compress": true,
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6"
},
"CustomErrorResponses": {
"Quantity": 1,
"Items": [{
"ErrorCode": 404,
"ResponsePagePath": "/index.html",
"ResponseCode": "200",
"ErrorCachingMinTTL": 300
}]
},
"Comment": "My Website CDN",
"Enabled": true
}
3단계: Route 53 도메인 연결
# ACM 인증서 요청 (us-east-1에서!)
aws acm request-certificate \
--domain-name example.com \
--subject-alternative-names www.example.com \
--validation-method DNS \
--region us-east-1
# CloudFront에 도메인 및 인증서 추가
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config file://distribution-with-domain.json
# Route 53 레코드 생성
aws route53 change-resource-record-sets \
--hosted-zone-id Z1234567890ABC \
--change-batch file://dns-records.json
dns-records.json:
{
"Changes": [
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net",
"EvaluateTargetHealth": false
}
}
},
{
"Action": "CREATE",
"ResourceRecordSet": {
"Name": "www.example.com",
"Type": "A",
"AliasTarget": {
"HostedZoneId": "Z2FDTNDATAQYW2",
"DNSName": "d111111abcdef8.cloudfront.net",
"EvaluateTargetHealth": false
}
}
}
]
}
4단계: 보안 강화
// CloudFront Function: 보안 헤더
function handler(event) {
var response = event.response;
var headers = response.headers;
headers['strict-transport-security'] = {
value: 'max-age=63072000; includeSubdomains; preload'
};
headers['content-security-policy'] = {
value: "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.example.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:; connect-src 'self' https://api.example.com"
};
headers['x-content-type-options'] = { value: 'nosniff' };
headers['x-frame-options'] = { value: 'DENY' };
headers['x-xss-protection'] = { value: '1; mode=block' };
headers['referrer-policy'] = { value: 'strict-origin-when-cross-origin' };
return response;
}
5단계: CI/CD 파이프라인
# GitHub Actions
name: Deploy to CloudFront
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build
run: |
npm install
npm run build
- name: Deploy to S3
run: |
aws s3 sync build/ s3://my-website-bucket/ \
--delete \
--cache-control "max-age=31536000" \
--exclude "*.html"
aws s3 sync build/ s3://my-website-bucket/ \
--cache-control "max-age=3600" \
--exclude "*" \
--include "*.html"
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: us-east-1
- name: Invalidate CloudFront
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
--paths "/*"
마치며
CloudFront와 Global Accelerator는 글로벌 애플리케이션의 성능과 가용성을 극대화하는 강력한 도구
핵심 요약:
CloudFront:
- 정적/동적 콘텐츠 캐싱 및 배포
- 450+ 엣지 로케이션
- S3, ALB, 커스텀 오리진 지원
- Lambda@Edge/CloudFront Functions로 엣지 컴퓨팅
- 보안: HTTPS, Signed URLs, WAF, Geo Restriction
- 비용 최적화: Compression, Origin Shield, Price Class
Global Accelerator:
- TCP/UDP 트래픽 가속화
- 고정 Anycast IP
- AWS 백본 네트워크 사용
- 게임, IoT, VoIP에 최적
- Health Check 및 자동 장애 조치
선택 가이드:
- HTTP/HTTPS 콘텐츠 → CloudFront
- TCP/UDP 애플리케이션 → Global Accelerator
- 정적 웹사이트 → CloudFront + S3
- 동적 웹앱 → CloudFront + ALB
- 실시간 게임 → Global Accelerator + NLB
다음 단계로 AWS WAF, Shield, GuardDuty 등 보안 서비스를 학습하여 더욱 안전한 인프라를 구축해보세요! 🚀CloudFront와 S3 통합
기본 설정
1. S3 버킷 생성 및 콘텐츠 업로드
# 버킷 생성
aws s3 mb s3://my-static-website
# 웹사이트 파일 업로드
aws s3 sync ./website/ s3://my-static-website/
2. CloudFront 배포 생성
aws cloudfront create-distribution \ --origin-domain-name my-static-website.s3.amazonaws.com \ --default-root-object index.html
콘솔 설정:
Origin Settings:
- Origin Domain: my-static-website.s3.amazonaws.com
- Origin Path: / (선택)
- Origin Access: Origin Access Control (OAC) - 권장
Default Cache Behavior:
- Viewer Protocol Policy: Redirect HTTP to HTTPS
- Allowed HTTP Methods: GET, HEAD
- Cache Policy: CachingOptimized
Distribution Settings:
- Price Class: Use All Edge Locations
- Alternate Domain Names (CNAMEs): www.example.com
- SSL Certificate: Custom SSL certificate (ACM)
- Default Root Object: index.html
3. Origin Access Control (OAC) 설정
OAC 생성:
aws cloudfront create-origin-access-control \
--origin-access-control-config '{
"Name": "my-oac",
"Description": "OAC for S3 origin",
"SigningProtocol": "sigv4",
"SigningBehavior": "always",
"OriginAccessControlOriginType": "s3"
}'
S3 버킷 정책 업데이트:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-static-website/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1234567890ABC"
}
}
}
]
}
보안 비교:
❌ Public S3 (권장하지 않음):
인터넷 → S3 (누구나 접근 가능)
✅ OAC (권장):
인터넷 → CloudFront → S3
└─ S3는 CloudFront만 접근 허용
CloudFront 고급 기능
1. 지리적 제한 (Geo Restriction)
특정 국가에서의 접근을 허용하거나 차단
aws cloudfront update-distribution \
--id E1234567890ABC \
--distribution-config '{
"Restrictions": {
"GeoRestriction": {
"RestrictionType": "whitelist",
"Quantity": 2,
"Items": ["US", "KR"]
}
}
}'
사용 사례:
- 라이선스 제한 (예: 한국에서만 서비스)
- 저작권 보호
- 규제 준수
Whitelist (허용 목록):
- US, KR만 허용
- 기타 국가: 403 Forbidden
Blacklist (차단 목록):
- CN, RU 차단
- 기타 국가: 허용
2. Price Classes (요금 클래스)
사용할 엣지 로케이션을 제한하여 비용을 절감
옵션:
Price Class All (기본)
- 모든 엣지 로케이션 (450+)
- 최상의 성능
- 가장 비쌈
Price Class 200
- 북미, 유럽, 아시아, 중동, 아프리카
- 남미 제외
- 중간 가격
Price Class 100
- 북미, 유럽만
- 가장 저렴
- 제한된 커버리지
aws cloudfront update-distribution \
--id E1234567890ABC \
--price-class PriceClass_200
비용 비교:
Price Class All: $0.085/GB (아시아-태평양)
Price Class 200: $0.085/GB (동일)
Price Class 100: $0.085/GB → 사용 불가 (미국/유럽만)
3. Cache Invalidation (캐시 무효화)
배포된 콘텐츠를 즉시 업데이트합니다.
# 단일 파일 무효화
aws cloudfront create-invalidation \
--distribution-id E1234567890ABC \
--paths /index.html
# 폴더 전체 무효화
aws cloudfront create-invalidation \
--distribution-id E1234567890ABC \
--paths /images/*
# 모든 파일 무효화
aws cloudfront create-invalidation \
--distribution-id E1234567890ABC \
--paths /*
비용:
- 월 1,000개 무료
- 이후: $0.005/개
모범 사례:
❌ 나쁜 예: 자주 무효화
- 콘텐츠 변경할 때마다 무효화
- 비용 증가
✅ 좋은 예: 버전 관리
- 파일 이름에 버전 포함
- style.css → style.v2.css
- 무효화 불필요
즉시 업데이트 전략:
# 버전 기반 배포
import boto3
import hashlib
import time
s3 = boto3.client('s3')
def upload_with_version(file_path, bucket, key_prefix):
# 파일 해시로 버전 생성
with open(file_path, 'rb') as f:
content = f.read()
version = hashlib.md5(content).hexdigest()[:8]
# 버전이 포함된 키
versioned_key = f"{key_prefix}.{version}.js"
# 업로드
s3.put_object(
Bucket=bucket,
Key=versioned_key,
Body=content,
CacheControl='max-age=31536000' # 1년
)
return versioned_key
# 사용
new_script = upload_with_version('app.js', 'my-bucket', 'js/app')
print(f"New version: {new_script}")
# → js/app.a3b5c7d9.js
CloudFront와 ALB 통합
아키텍처
사용자
↓
[CloudFront]
├─ 정적 콘텐츠 (S3 Origin)
│ └─ /assets/* → S3
└─ 동적 콘텐츠 (ALB Origin)
└─ /api/* → ALB → EC2
설정
1. ALB를 오리진으로 추가
aws cloudfront create-distribution \
--distribution-config '{
"Origins": {
"Items": [
{
"Id": "S3-my-bucket",
"DomainName": "my-bucket.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
}
},
{
"Id": "ALB-my-app",
"DomainName": "my-alb-123456789.us-east-1.elb.amazonaws.com",
"CustomOriginConfig": {
"HTTPPort": 80,
"HTTPSPort": 443,
"OriginProtocolPolicy": "https-only"
}
}
]
},
"CacheBehaviors": {
"Items": [
{
"PathPattern": "/api/*",
"TargetOriginId": "ALB-my-app",
"ViewerProtocolPolicy": "redirect-to-https",
"CachePolicyId": "4135ea2d-6df8-44a3-9df3-4b5a84be39ad"
}
]
}
}'
2. 캐시 동작 (Cache Behavior) 설정
기본 동작 (Default):
- Origin: S3
- Path: /*
- Cache: Enabled (긴 TTL)
추가 동작 #1:
- Origin: ALB
- Path: /api/*
- Cache: Disabled (동적 콘텐츠)
추가 동작 #2:
- Origin: S3
- Path: /images/*
- Cache: Enabled (매우 긴 TTL)
캐시 정책
CachingOptimized (정적 콘텐츠)
TTL:
- Minimum: 1초
- Maximum: 31,536,000초 (1년)
- Default: 86,400초 (1일)
캐시 키:
- Query strings: None
- Headers: None
- Cookies: None
CachingDisabled (동적 콘텐츠)
TTL: 0 (캐싱 안 함)
모든 요청을 오리진으로 전달
커스텀 캐시 정책
{
"Name": "CustomCachePolicy",
"MinTTL": 0,
"MaxTTL": 31536000,
"DefaultTTL": 86400,
"ParametersInCacheKeyAndForwardedToOrigin": {
"EnableAcceptEncodingGzip": true,
"EnableAcceptEncodingBrotli": true,
"QueryStringsConfig": {
"QueryStringBehavior": "whitelist",
"QueryStrings": {
"Items": ["page", "sort"]
}
},
"HeadersConfig": {
"HeaderBehavior": "whitelist",
"Headers": {
"Items": ["Accept-Language", "CloudFront-Viewer-Country"]
}
},
"CookiesConfig": {
"CookieBehavior": "none"
}
}
}
CloudFront Functions vs Lambda@Edge
비교
특성 | CloudFront Functions | Lambda@Edge |
실행 위치 | 엣지 로케이션 (모든 PoP) | 리전별 엣지 로케이션 |
지연 시간 | 1ms 미만 | 5-10ms |
최대 실행 시간 | 1ms | 5초 (viewer), 30초 (origin) |
메모리 | 2MB | 128MB ~ 10GB |
패키지 크기 | 10KB | 50MB |
가격 | 매우 저렴 ($0.10/100만 요청) | 비쌈 ($0.60/100만 요청) |
네트워크 액세스 | 불가 | 가능 |
파일 시스템 | 불가 | 불가 |
사용 사례 | 간단한 변환 | 복잡한 로직 |
CloudFront Functions 예시
1. 헤더 추가
function handler(event) {
var response = event.response;
var headers = response.headers;
// 보안 헤더 추가
headers['strict-transport-security'] = {
value: 'max-age=63072000'
};
headers['x-content-type-options'] = {
value: 'nosniff'
};
headers['x-frame-options'] = {
value: 'DENY'
};
headers['x-xss-protection'] = {
value: '1; mode=block'
};
return response;
}
2. URL 리다이렉트
function handler(event) {
var request = event.request;
var uri = request.uri;
// 디렉토리 접근 시 index.html 추가
if (uri.endsWith('/')) {
request.uri += 'index.html';
}
// 확장자 없는 경우 .html 추가
else if (!uri.includes('.')) {
request.uri += '.html';
}
return request;
}
3. A/B 테스트
function handler(event) {
var request = event.request;
var headers = request.headers;
var cookies = request.cookies;
// 쿠키 확인
var testGroup = cookies['ab-test'] ? cookies['ab-test'].value : null;
if (!testGroup) {
// 랜덤 할당
testGroup = Math.random() < 0.5 ? 'A' : 'B';
}
// URI 변경
if (testGroup === 'B') {
request.uri = '/beta' + request.uri;
}
// 쿠키 설정
request.headers['set-cookie'] = {
value: `ab-test=${testGroup}; Max-Age=86400; Path=/`
};
return request;
}
Lambda@Edge 예시
1. 이미지 리사이징
const AWS = require('aws-sdk');
const sharp = require('sharp');
const S3 = new AWS.S3();
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
const response = event.Records[0].cf.response;
// 리사이즈 파라미터 파싱
const params = new URLSearchParams(request.querystring);
const width = parseInt(params.get('w')) || 800;
// 원본 이미지 가져오기
const s3Object = await S3.getObject({
Bucket: 'my-images',
Key: request.uri.substring(1)
}).promise();
// 리사이징
const resized = await sharp(s3Object.Body)
.resize(width)
.toBuffer();
// 응답 생성
return {
status: '200',
headers: {
'content-type': [{ value: 'image/jpeg' }],
'cache-control': [{ value: 'max-age=31536000' }]
},
body: resized.toString('base64'),
bodyEncoding: 'base64'
};
};
2. 인증 확인
const jwt = require('jsonwebtoken');
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
// Authorization 헤더 확인
const authHeader = headers.authorization && headers.authorization[0].value;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return {
status: '401',
statusDescription: 'Unauthorized',
headers: {
'www-authenticate': [{ value: 'Bearer' }]
}
};
}
const token = authHeader.substring(7);
try {
// JWT 검증
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// 사용자 정보를 커스텀 헤더로 전달
request.headers['x-user-id'] = [{ value: decoded.userId }];
request.headers['x-user-role'] = [{ value: decoded.role }];
return request;
} catch (err) {
return {
status: '403',
statusDescription: 'Forbidden',
body: 'Invalid token'
};
}
};
3. 동적 콘텐츠 생성
exports.handler = async (event) => {
const request = event.Records[0].cf.request;
// 국가 정보
const country = request.headers['cloudfront-viewer-country'][0].value;
// 동적 HTML 생성
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
</head>
<body>
<h1>Welcome from ${country}!</h1>
<p>Your local time is: ${new Date().toLocaleString()}</p>
</body>
</html>
`;
return {
status: '200',
headers: {
'content-type': [{ value: 'text/html; charset=utf-8' }],
'cache-control': [{ value: 'no-cache' }]
},
body: html
};
};
AWS Global Accelerator
AWS의 글로벌 네트워크를 사용하여 애플리케이션의 가용성과 성능을 향상시킨다
CloudFront (캐싱):
사용자 → 엣지 (캐시 히트) → 즉시 반환
Global Accelerator (프록시):
사용자 → 엣지 → AWS 백본 → 애플리케이션
└─ 캐싱 없음, 모든 요청 전달
CloudFront vs Global Accelerator
특성 | CloudFront | Global Accelerator |
목적 | 콘텐츠 캐싱 및 배포 | 네트워크 성능 향상 |
프로토콜 | HTTP/HTTPS | TCP/UDP |
캐싱 | 있음 | 없음 |
IP | 동적 | 고정 (Anycast) |
사용 사례 | 정적/동적 웹 콘텐츠 | 게임, IoT, VoIP |
가격 | 저렴 | 비쌈 |
Global Accelerator 구성
[Global Accelerator]
├─ Static IP: 1.2.3.4, 5.6.7.8 (Anycast)
├─ Endpoint Group (ap-northeast-2)
│ ├─ ALB-1 (가중치: 70)
│ └─ EC2-1 (가중치: 30)
└─ Endpoint Group (us-east-1)
├─ ALB-2 (가중치: 100)
└─ NLB-1 (가중치: 0)
설정
# Accelerator 생성
aws globalaccelerator create-accelerator \
--name my-accelerator \
--ip-address-type IPV4 \
--enabled
# Listener 생성
aws globalaccelerator create-listener \
--accelerator-arn arn:aws:globalaccelerator::123456789012:accelerator/a1234567-89ab-cdef-0123-456789abcdef \
--port-ranges FromPort=80,ToPort=80 FromPort=443,ToPort=443 \
--protocol TCP
# Endpoint Group 생성
aws globalaccelerator create-endpoint-group \
--listener-arn arn:aws:globalaccelerator::123456789012:listener/l1234567/89abcdef \
--endpoint-group-region ap-northeast-2 \
--endpoint-configurations \
EndpointId=arn:aws:elasticloadbalancing:ap-northeast-2:123456789012:loadbalancer/app/my-alb/50dc6c495c0c9188,Weight=100
주요 기능
1. Health Check
aws globalaccelerator update-endpoint-group \ --endpoint-group-arn arn:aws:globalaccelerator::account:accelerator/id/listener/id/endpoint-group/id \ --health-check-protocol HTTP \ --health-check-path /health \ --health-check-interval-seconds 30 \ --threshold-count 3
2. Traffic Dial (트래픽 다이얼)
엔드포인트 그룹으로 전송되는 트래픽 비율을 제어
# 트래픽 50%만 전송 (블루-그린 배포)
aws globalaccelerator update-endpoint-group \
--endpoint-group-arn arn:... \
--traffic-dial-percentage 50
사용 예시:
배포 전: Traffic Dial 100% (구버전)
배포 중: Traffic Dial 50% (신버전 테스트)
확인 후: Traffic Dial 100% (신버전)
3. Client Affinity (클라이언트 선호도)
# 소스 IP 기반 라우팅
aws globalaccelerator update-endpoint-group \
--endpoint-group-arn arn:... \
--client-affinity SOURCE_IP
동작:
Client Affinity: None
- 요청마다 다른 엔드포인트 가능
Client Affinity: SOURCE_IP
- 동일 IP는 항상 같은 엔드포인트
- 세션 유지 필요한 애플리케이션
실전 사용 사례
사례 1: 글로벌 정적 웹사이트
아키텍처:
[S3 Static Website]
↓ Origin
[CloudFront]
├─ 450+ 엣지 로케이션
├─ HTTPS (ACM 인증서)
├─ Geo Restriction (필요시)
└─ Lambda@Edge (헤더 추가)
↓
[Route 53]
└─ www.example.com → CloudFront
성능:
- 서울 사용자: 10-20ms (엣지에서)
- 뉴욕 사용자: 10-20ms (엣지에서)
- 오리진 부하: 99% 감소 (캐시 히트율)
비용:
- S3: $0.023/GB (저장)
- CloudFront: $0.085/GB (전송)
- 월 1TB 전송: ~$85 (직접 대비 60% 절감)
사례 2: 동적 웹 애플리케이션
[ALB]
├─ [EC2] AZ-A
└─ [EC2] AZ-C
↓ Origin
[CloudFront]
├─ /api/* → Cache: Disabled
├─ /assets/* → Cache: Enabled (1년)
└─ /* → Cache: Enabled (1일)
설정:
- Cache Policy: CachingDisabled (/api/*)
- Origin Request Policy: AllViewer (/api/*)
- Response Headers Policy: SecurityHeadersPolicy
보안:
- AWS WAF (SQL Injection, XSS 차단)
- AWS Shield (DDoS 보호)
- Rate Limiting (1000 req/min)
사례 3: 게임 서버 (Global Accelerator)
이유: CloudFront 사용 불가
- TCP/UDP 프로토콜
- 실시간 통신 (캐싱 불가)
- 낮은 지연시간 필수
아키텍처:
[Global Accelerator]
├─ Static IP: 1.2.3.4, 5.6.7.8
├─ 서울 리전
│ └─ NLB → EC2 (게임 서버)
└─ 도쿄 리전
└─ NLB → EC2 (게임 서버)
성능 개선:
- 공인 인터넷: 200ms 지연
- Global Accelerator: 50ms 지연 (75% 개선)
- AWS 백본 사용으로 안정성 향상
사례 4: 하이브리드 (CloudFront + Global Accelerator)
[CloudFront] ← 정적 콘텐츠 (HTML, CSS, JS, 이미지)
└─ S3 Origin
[Global Accelerator] ← API 및 WebSocket
├─ ALB (REST API)
└─ NLB (WebSocket)
클라이언트:
- 페이지 로드: CloudFront에서
- API 호출: Global Accelerator로
- 실시간 통신: Global Accelerator (WebSocket)
모니터링 및 최적화
CloudWatch 지표
# 캐시 히트율 조회
aws cloudwatch get-metric-statistics \
--namespace AWS/CloudFront \
--metric-name CacheHitRate \
--dimensions Name=DistributionId,Value=E1234567890ABC \
--start-time 2024-11-19T00:00:00Z \
--end-time 2024-11-19T23:59:59Z \
--period 3600 \
--statistics Average
주요 지표:
- CacheHitRate: 캐시 히트율 (목표: 80% 이상)
- Requests: 총 요청 수
- BytesDownloaded: 다운로드된 바이트
- 4xxErrorRate: 클라이언트 에러율
- 5xxErrorRate: 서버 에러율
캐시 최적화
낮은 캐시 히트율 원인:
1. Query String 변동 (?timestamp=123456)
2. Cookie 변동
3. 짧은 TTL
4. Vary 헤더
해결책:
1. Query String 화이트리스트
2. Cookie 화이트리스트
3. 적절한 TTL 설정
4. Cache-Control 헤더 최적화
Cache-Control 헤더:
정적 콘텐츠 (CSS, JS, 이미지):
Cache-Control: public, max-age=31536000, immutable
동적 콘텐츠 (HTML):
Cache-Control: public, max-age=3600, must-revalidate
API 응답:
Cache-Control: no-cache, no-store, must-revalidate
Share article