R2 3D Tiles 보안 — 선택 가이드 및 구현 체크리스트

상황별 보안 방식 선택 기준과 구현 시 반드시 확인해야 할 체크리스트를 정리한다. 업데이트: 2026-04-06


핵심 요약

구분내용
📖 정의R2 3D Tiles 보안 방식의 상황별 선택 가이드 및 구현 체크리스트
💡 핵심Decision Tree로 상황에 맞는 방식을 선택하고, 레벨별 체크리스트로 안전하게 구현한다
🎯 대상보안 방식을 결정하고 실제 구현에 착수하려는 개발자
⚠️ 주의무료 플랜 한도(Worker 10만/일, Access 50명)를 초과하면 서비스가 중단될 수 있다

목차

  1. 상황별 선택 기준 (Decision Tree)
  2. 권장 구성 레벨별 정리
  3. 구현 체크리스트
  4. 비용 시뮬레이션
  5. CDN 캐싱 전략
  6. 보안 강화 체크리스트
  7. 구현 Quick Start

1. 상황별 선택 기준 (Decision Tree)

flowchart TD
    START["R2 3D Tiles 보안 방식 선택"] --> Q1{"외부 사용자에게<br/>서빙하는가?"}
    
    Q1 -- "아니오<br/>(내부만)" --> F["방식 F: Tunnel + WARP<br/>내부 개발자만 접근"]
    
    Q1 -- "예" --> Q2{"강력한 인증이<br/>필요한가?"}
    
    Q2 -- "아니오<br/>기본 보호만" --> E["방식 E: Public + WAF<br/>보조 레이어로만 사용"]
    
    Q2 -- "예" --> Q3{"Worker 코드<br/>개발 가능한가?"}
    
    Q3 -- "예" --> A["방식 A: Worker JWT<br/>강력 추천"]
    
    Q3 -- "아니오<br/>코드리스 원함" --> Q4{"사용자 50명<br/>이하인가?"}
    
    Q4 -- "예" --> B["방식 B: Access Free<br/>Service Token 연동"]
    
    Q4 -- "아니오" --> Q5{"예산이<br/>있는가?"}
    
    Q5 -- "예" --> B2["방식 B: Access 유료<br/>7달러/사용자/월"]
    
    Q5 -- "아니오" --> A
    
    A --> PLUS["방식 E WAF Rate Limiting<br/>보조 레이어 추가 권장"]
    
    style A fill:#2d6a4f,color:#fff
    style PLUS fill:#1b4332,color:#fff

조건별 빠른 선택

조건권장 방식
B2B SaaS, 다중 프로젝트, 세밀한 권한 제어 필요A (Worker JWT)
소규모 팀 (≤50명), 코드 없이 빠르게 설정B (Access Free)
iframe, <img> 등 HTTP 헤더 설정 불가 환경D (HMAC Signed URL)
공개 데이터이나 남용 방지만 필요E (WAF + Rate Limiting)
개발/스테이징 환경, 내부 전용F (Tunnel + WARP)
Presigned URL로 단일 파일 다운로드만 필요C (Presigned URL)

2. 권장 구성 레벨별 정리

기본 (Basic) — 최소 보호

대상: 공개 데이터, 남용 방지만 필요한 경우

구성 요소설정
R2커스텀 도메인으로 공개
WAFReferer 체크 1개 규칙
Rate LimitingIP당 200req/10초
DDoS자동 포함 (무료)
월 비용$0

표준 (Standard) — 권장 구성

대상: 인증이 필요한 일반적인 서비스

구성 요소설정
WorkerJWT 검증 + R2 Binding
R2완전 비공개
Cache APITTL 1시간
CORS특정 도메인만 허용
WAFRate Limiting 추가
월 비용5

고급 (Advanced) — 엔터프라이즈 구성

대상: 다중 프로젝트, 세밀한 권한, 높은 트래픽

구성 요소설정
WorkerJWT + projectId 경로 권한 분리
R2완전 비공개
Cache API프로젝트별 TTL
JWT 서버RS256 비대칭 키, 토큰 갱신
WAFCustom Rules + Rate Limiting + Bot Management
모니터링Worker Analytics + R2 사용량 추적
월 비용25

3. 구현 체크리스트

방식 A (Worker + R2 Binding + JWT) 구현 체크리스트

인프라 준비

항목확인 방법통과 기준
Cloudflare 계정 생성대시보드 접근로그인 가능
Wrangler CLI 설치wrangler --versionv3 이상
R2 버킷 생성R2 대시보드 확인버킷 존재
R2 public access 비활성화버킷 설정 → Public access”Not allowed” 상태
r2.dev URL 비활성화버킷 설정 → r2.dev subdomain비활성화 상태

Worker 개발

항목확인 방법통과 기준
wrangler.toml 작성파일 존재 확인r2_buckets binding 포함
JWT_SECRET 등록wrangler secret listJWT_SECRET 존재
Worker 코드 작성wrangler dev 로컬 테스트JWT 검증 동작
CORS 처리OPTIONS 요청 테스트204 응답 + CORS 헤더
에러 처리잘못된 JWT 전송401/403 응답
Cache API 연동동일 URL 2회 요청2번째 요청이 캐시 히트
Worker 배포wrangler deploy배포 성공

클라이언트 연동

항목확인 방법통과 기준
JWT 발급 서버 구현토큰 발급 API 테스트JWT 정상 발급
Cesium.Resource 헤더 설정tileset.json 로드200 응답
자식 타일 헤더 전파 확인네트워크 탭에서 .b3dm 요청 확인Authorization 헤더 포함
토큰 만료 처리만료된 JWT로 요청retryCallback 동작

보안 검증

항목확인 방법통과 기준
토큰 없이 접근curl 헤더 없이 요청401 Unauthorized
만료 토큰 접근과거 exp의 JWT로 요청403 Forbidden
다른 프로젝트 경로 접근projectId 불일치 경로 요청403 Forbidden
R2 직접 접근 불가R2 URL 직접 호출접근 불가 (403 또는 없음)

4. 비용 시뮬레이션

시나리오별 예상 비용 (방식 A 기준, 월간)

시나리오규모WorkersR2합계
소규모5명, 1,000 타일, 100 씬/일$0 (무료 내)$0 (무료 내)$0
중규모50명, 5,000 타일, 1,000 씬/일527
대규모500명, 10,000 타일, 10,000 씬/일$5 + 초과분2030

CDN 캐싱 효과

[ 캐싱 미적용 ]
100명 × 500 타일 = 50,000 R2 GetObject → $0.018/씬 전환

[ 캐싱 적용 (히트율 99%) ]
첫 1명 → 500 R2 GetObject
나머지 99명 → CDN 캐시에서 직접 제공
→ R2 비용 99% 절감

무료 플랜 한도 주의

서비스무료 한도초과 시
Workers100,000 요청/일서비스 중단
R2 Class B10,000,000건/월$0.36/100만 건
R2 스토리지10 GB$0.015/GB

⚠️ Workers 무료 플랜은 초과 시 서비스가 중단된다. 대규모 서비스에서는 반드시 Standard($5/월) 플랜으로 전환해야 한다.


5. CDN 캐싱 전략

Cache-Control 설정 가이드

파일 유형Cache-Control이유
tileset.jsonpublic, max-age=300 (5분)타일셋 구조 변경 시 빠른 갱신 필요
.b3dm, .i3dmpublic, max-age=86400 (1일)타일 데이터는 변경 빈도 낮음
.glb, .gltfpublic, max-age=86400 (1일)모델 데이터 변경 빈도 낮음
.json (자식)public, max-age=3600 (1시간)메타데이터 갱신 고려

Worker에서 파일 유형별 캐싱 적용

function getCacheTTL(objectKey) {
  if (objectKey.endsWith('tileset.json')) return 300;
  if (objectKey.endsWith('.b3dm') || objectKey.endsWith('.i3dm')) return 86400;
  if (objectKey.endsWith('.glb') || objectKey.endsWith('.gltf')) return 86400;
  if (objectKey.endsWith('.json')) return 3600;
  return 3600; // 기본값
}
 
// Worker 내 사용
responseHeaders.set('Cache-Control', `public, max-age=${getCacheTTL(objectKey)}`);

캐시 퍼지 (Purge)

데이터가 업데이트되었을 때 CDN 캐시를 무효화하는 방법이다.

# 단일 URL 퍼지
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
  -H "Authorization: Bearer {api_token}" \
  -H "Content-Type: application/json" \
  --data '{"files":["https://worker.mydomain.com/tilesets/proj-a/tileset.json"]}'
 
# 전체 퍼지 (주의: 전체 CDN 캐시 삭제)
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone_id}/purge_cache" \
  -H "Authorization: Bearer {api_token}" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything":true}'

6. 보안 강화 체크리스트

필수 (Must Have)

항목설명
R2 public access 비활성화Worker Binding으로만 접근하도록 제한
r2.dev URL 비활성화Access 우회 방지
JWT_SECRET을 wrangler secret으로 관리코드/git에 하드코딩 금지
CORS origin 제한* 대신 특정 도메인만 허용
JWT 만료 시간 설정1시간 이내 권장

권장 (Should Have)

항목설명
Rate Limiting 설정IP당 요청 수 제한
projectId 경로 권한 분리JWT payload에 projectId 포함, 경로와 매핑
JWT 알고리즘 명시 (algorithms: ['HS256'])Algorithm Confusion 공격 방지
JWT issuer 검증다른 서비스의 JWT 혼용 방지
Worker 에러 메시지 최소화내부 정보 누출 방지

선택 (Nice to Have)

항목설명
RS256 (비대칭 키) 전환비밀 키를 Worker에 저장하지 않아도 됨
JWT 블랙리스트 (KV 활용)유출된 토큰 즉시 무효화
Worker Analytics 모니터링비정상 트래픽 패턴 감지
WAF Bot Management자동화된 스크래핑 차단

7. 구현 Quick Start

방식 A (Worker + R2 Binding + JWT)를 최소한으로 구현하는 단계이다.

Step 1. 프로젝트 초기화

# Wrangler CLI 설치
npm install -g wrangler
 
# 프로젝트 생성
mkdir r2-tileset-proxy && cd r2-tileset-proxy
npm init -y
npm install jose
 
# Wrangler 로그인
wrangler login

Step 2. wrangler.toml 작성

name = "r2-tileset-auth-proxy"
main = "src/index.mjs"
compatibility_date = "2024-09-23"
 
[[r2_buckets]]
binding = "TILE_BUCKET"
bucket_name = "my-3dtiles-bucket"
 
[vars]
ALLOWED_ORIGIN = "https://my-viewer-app.com"
JWT_ISSUER = "https://my-auth-server.com"

Step 3. Secret 등록

# JWT 검증용 비밀 키 등록
wrangler secret put JWT_SECRET
# 프롬프트에서 비밀 키 입력

Step 4. Worker 코드 작성

src/index.mjs방식별 상세 비교 문서의 Worker 코드를 작성한다.

Step 5. 로컬 테스트

# 로컬 개발 서버 실행
wrangler dev
 
# 테스트 (다른 터미널에서)
# 토큰 없이 접근 → 401
curl http://localhost:8787/tilesets/proj-a/tileset.json
 
# JWT 포함 접근 → 200
curl -H "Authorization: Bearer {test-jwt}" \
  http://localhost:8787/tilesets/proj-a/tileset.json

Step 6. 배포

# 프로덕션 배포
wrangler deploy
 
# 배포 확인
curl -H "Authorization: Bearer {jwt}" \
  https://r2-tileset-auth-proxy.{account}.workers.dev/tilesets/proj-a/tileset.json

Step 7. 커스텀 도메인 연결 (선택)

Cloudflare 대시보드 → Workers & Pages → r2-tileset-auth-proxy
→ Settings → Triggers → Custom Domains
→ "tiles.mydomain.com" 추가

문서 탐색


참고 자료