R2 3D Tiles 보안 — 선택 가이드 및 구현 체크리스트
상황별 보안 방식 선택 기준과 구현 시 반드시 확인해야 할 체크리스트를 정리한다.
업데이트: 2026-04-06
핵심 요약
구분 내용 📖 정의 R2 3D Tiles 보안 방식의 상황별 선택 가이드 및 구현 체크리스트 💡 핵심 Decision Tree로 상황에 맞는 방식을 선택하고, 레벨별 체크리스트로 안전하게 구현한다 🎯 대상 보안 방식을 결정하고 실제 구현에 착수하려는 개발자 ⚠️ 주의 무료 플랜 한도(Worker 10만/일, Access 50명)를 초과하면 서비스가 중단될 수 있다
목차
상황별 선택 기준 (Decision Tree)
권장 구성 레벨별 정리
구현 체크리스트
비용 시뮬레이션
CDN 캐싱 전략
보안 강화 체크리스트
구현 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 커스텀 도메인으로 공개 WAF Referer 체크 1개 규칙 Rate Limiting IP당 200req/10초 DDoS 자동 포함 (무료) 월 비용 $0
표준 (Standard) — 권장 구성
대상 : 인증이 필요한 일반적인 서비스
구성 요소 설정 Worker JWT 검증 + R2 Binding R2 완전 비공개 Cache API TTL 1시간 CORS 특정 도메인만 허용 WAF Rate Limiting 추가 월 비용 0 5
고급 (Advanced) — 엔터프라이즈 구성
대상 : 다중 프로젝트, 세밀한 권한, 높은 트래픽
구성 요소 설정 Worker JWT + projectId 경로 권한 분리 R2 완전 비공개 Cache API 프로젝트별 TTL JWT 서버 RS256 비대칭 키, 토큰 갱신 WAF Custom Rules + Rate Limiting + Bot Management 모니터링 Worker Analytics + R2 사용량 추적 월 비용 5 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 기준, 월간)
시나리오 규모 Workers R2 합계 소규모 5명, 1,000 타일, 100 씬/일 $0 (무료 내) $0 (무료 내) $0 중규모 50명, 5,000 타일, 1,000 씬/일 0 50 20 7대규모 500명, 10,000 타일, 10,000 씬/일 $5 + 초과분 5 2010 30
CDN 캐싱 효과
[ 캐싱 미적용 ]
100명 × 500 타일 = 50,000 R2 GetObject → $0.018/씬 전환
[ 캐싱 적용 (히트율 99%) ]
첫 1명 → 500 R2 GetObject
나머지 99명 → CDN 캐시에서 직접 제공
→ R2 비용 99% 절감
무료 플랜 한도 주의
서비스 무료 한도 초과 시 Workers 100,000 요청/일 서비스 중단 R2 Class B 10,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" 추가
문서 탐색
참고 자료