보안 개선: - API 키 하드코딩 제거 (NAMECHEAP_API_KEY_INTERNAL) - CORS 정책: * → hosting.anvil.it.com 제한 - /health 엔드포인트 DB 정보 노출 방지 - Rate Limiting 인메모리 Map → Cloudflare KV 전환 - 분산 환경 일관성 보장 - 재시작 후에도 유지 - 자동 만료 (TTL) 문서: - CLAUDE.md Security 섹션 추가 - KV Namespace 설정 가이드 추가 - 배포/마이그레이션 가이드 추가 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
266 lines
6.6 KiB
Markdown
266 lines
6.6 KiB
Markdown
# Rate Limiting KV Migration - 배포 요약
|
|
|
|
## 변경 사항
|
|
|
|
### 1. Rate Limiting 시스템 마이그레이션
|
|
- **이전:** 인메모리 Map (Worker 인스턴스별 독립)
|
|
- **현재:** Cloudflare KV (분산 환경 공유)
|
|
|
|
### 2. 해결된 문제
|
|
✅ Workers 인스턴스 간 Rate Limit 데이터 공유
|
|
✅ Worker 재시작 시에도 Rate Limit 상태 유지
|
|
✅ 분산 환경에서 일관된 Rate Limiting 동작
|
|
✅ 자동 만료 (KV TTL) - 메모리 효율성
|
|
|
|
---
|
|
|
|
## 수정된 파일
|
|
|
|
### 1. `/Users/kaffa/telegram-bot-workers/wrangler.toml`
|
|
```toml
|
|
[[kv_namespaces]]
|
|
binding = "RATE_LIMIT_KV"
|
|
id = "YOUR_KV_NAMESPACE_ID" # 생성 후 실제 ID로 교체 필요
|
|
```
|
|
|
|
### 2. `/Users/kaffa/telegram-bot-workers/src/types.ts`
|
|
```typescript
|
|
export interface Env {
|
|
// ... 기존 필드들
|
|
RATE_LIMIT_KV: KVNamespace; // ✅ 추가
|
|
}
|
|
```
|
|
|
|
### 3. `/Users/kaffa/telegram-bot-workers/src/security.ts`
|
|
- 인메모리 Map 제거 (`rateLimitMap`)
|
|
- `cleanupRateLimits()` 함수 제거 (KV TTL로 자동 관리)
|
|
- `checkRateLimit()` 함수 시그니처 변경:
|
|
- 이전: `checkRateLimit(userId: string): boolean`
|
|
- 현재: `checkRateLimit(kv: KVNamespace, userId: string): Promise<boolean>`
|
|
|
|
### 4. `/Users/kaffa/telegram-bot-workers/src/index.ts`
|
|
```typescript
|
|
// 이전
|
|
if (!checkRateLimit(telegramUserId)) {
|
|
// ...
|
|
}
|
|
|
|
// 현재
|
|
if (!(await checkRateLimit(env.RATE_LIMIT_KV, telegramUserId))) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
### 5. `/Users/kaffa/telegram-bot-workers/CLAUDE.md`
|
|
- Rate Limiting 섹션 업데이트 (KV 기반 설명 추가)
|
|
- Configuration 섹션에 KV Namespaces 테이블 추가
|
|
- Commands 섹션에 KV Namespace 생성 명령 추가
|
|
|
|
---
|
|
|
|
## 배포 전 필수 작업
|
|
|
|
### Step 1: KV Namespace 생성
|
|
```bash
|
|
wrangler kv:namespace create RATE_LIMIT_KV
|
|
```
|
|
|
|
**출력 예시:**
|
|
```
|
|
⛅️ wrangler 3.x.x
|
|
-------------------
|
|
🌀 Creating namespace with title "telegram-summary-bot-RATE_LIMIT_KV"
|
|
✨ Success!
|
|
Add the following to your configuration file in your kv_namespaces array:
|
|
{ binding = "RATE_LIMIT_KV", id = "abc123..." }
|
|
```
|
|
|
|
### Step 2: wrangler.toml 수정
|
|
출력된 `id` 값을 복사하여 `wrangler.toml` 22번 줄 수정:
|
|
```toml
|
|
id = "abc123def456ghi789jkl012mno345pq" # ← 실제 ID로 변경
|
|
```
|
|
|
|
### Step 3: TypeScript 컴파일 확인
|
|
```bash
|
|
npx tsc --noEmit
|
|
```
|
|
|
|
### Step 4: 로컬 테스트
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
다른 터미널에서:
|
|
```bash
|
|
curl -X POST http://localhost:8787/webhook \
|
|
-H "Content-Type: application/json" \
|
|
-H "X-Telegram-Bot-Api-Secret-Token: test-secret" \
|
|
-d '{"update_id":1,"message":{"message_id":1,"from":{"id":123,"is_bot":false,"first_name":"Test"},"chat":{"id":123,"type":"private"},"date":1234567890,"text":"테스트"}}'
|
|
```
|
|
|
|
### Step 5: Production 배포
|
|
```bash
|
|
npm run deploy
|
|
```
|
|
|
|
### Step 6: 배포 확인
|
|
```bash
|
|
# Health Check
|
|
curl https://telegram-summary-bot.kappa-d8e.workers.dev/health
|
|
|
|
# 로그 스트리밍
|
|
npm run tail
|
|
```
|
|
|
|
---
|
|
|
|
## 기술 상세
|
|
|
|
### Rate Limiting 동작 방식
|
|
|
|
**Key 형식:** `ratelimit:{userId}`
|
|
|
|
**데이터 구조:**
|
|
```typescript
|
|
{
|
|
count: number, // 현재 윈도우 내 요청 수
|
|
resetAt: number // 윈도우 만료 시각 (Unix timestamp)
|
|
}
|
|
```
|
|
|
|
**알고리즘:**
|
|
1. KV에서 `ratelimit:{userId}` 조회
|
|
2. 데이터 없음 또는 윈도우 만료 (`now > resetAt`)
|
|
→ 새 윈도우 시작 (`count=1`, `resetAt=now+60000`)
|
|
3. `count >= 30` (기본값)
|
|
→ Rate Limit 초과, 요청 차단
|
|
4. `count < 30`
|
|
→ `count++` 후 KV 업데이트
|
|
|
|
**자동 만료:**
|
|
- KV의 `expirationTtl` 옵션 사용
|
|
- 윈도우 종료 시 자동 삭제 (메모리 효율)
|
|
|
|
**에러 처리:**
|
|
- KV 오류 발생 시: Rate Limit 통과 (서비스 가용성 우선)
|
|
- 로그 기록: `[RateLimit] KV 오류: ...`
|
|
|
|
---
|
|
|
|
## 모니터링
|
|
|
|
### KV Dashboard
|
|
https://dash.cloudflare.com → Workers & Pages → KV → telegram-summary-bot-RATE_LIMIT_KV
|
|
|
|
### KV CLI 명령어
|
|
```bash
|
|
# Namespace 목록
|
|
wrangler kv:namespace list
|
|
|
|
# 특정 키 조회
|
|
wrangler kv:key get "ratelimit:821596605" --namespace-id=YOUR_KV_ID
|
|
|
|
# 모든 키 목록
|
|
wrangler kv:key list --namespace-id=YOUR_KV_ID
|
|
|
|
# 키 삭제 (테스트용)
|
|
wrangler kv:key delete "ratelimit:821596605" --namespace-id=YOUR_KV_ID
|
|
```
|
|
|
|
### 로그 확인
|
|
```bash
|
|
# 실시간 로그
|
|
wrangler tail
|
|
|
|
# Rate Limit 관련 로그만 필터링
|
|
wrangler tail --format json | jq 'select(.message | contains("RateLimit"))'
|
|
```
|
|
|
|
---
|
|
|
|
## 성능 영향
|
|
|
|
### Before (인메모리 Map)
|
|
- 응답 시간: ~1ms (동기)
|
|
- 메모리: 인스턴스별 독립 (중복 저장)
|
|
- 일관성: ❌ 분산 환경에서 불일치
|
|
|
|
### After (KV)
|
|
- 응답 시간: ~20-50ms (KV read/write 포함)
|
|
- 메모리: 0 (KV로 오프로드)
|
|
- 일관성: ✅ 전역 일관성 보장
|
|
|
|
**영향 분석:**
|
|
- 약 20-50ms 지연 추가 (허용 가능한 수준)
|
|
- Telegram Webhook 응답은 200ms 이내 권장 (충분히 만족)
|
|
- 사용자 경험에 무시할 수 있는 영향
|
|
|
|
---
|
|
|
|
## 비용 분석
|
|
|
|
### Cloudflare Workers Free Plan
|
|
- **KV 읽기:** 100,000 reads/day (무료)
|
|
- **KV 쓰기:** 1,000 writes/day (무료)
|
|
|
|
### Rate Limiting 사용량
|
|
- 1 메시지 = 1 read + 1 write (최악의 경우)
|
|
- 일일 1,000 메시지까지 무료 (write limit 기준)
|
|
- 초과 시: $0.50 per million writes
|
|
|
|
**예상 사용량:**
|
|
- 현재 사용자 수: 소규모 (~10명)
|
|
- 일일 메시지 수: ~100개
|
|
- 예상 비용: $0 (무료 한도 내)
|
|
|
|
---
|
|
|
|
## 롤백 절차 (문제 발생 시)
|
|
|
|
### Option 1: Git Revert
|
|
```bash
|
|
git revert HEAD
|
|
npm run deploy
|
|
```
|
|
|
|
### Option 2: 수동 롤백
|
|
1. `wrangler.toml`에서 KV Namespace 제거
|
|
2. `src/types.ts`에서 `RATE_LIMIT_KV` 제거
|
|
3. `src/security.ts` 이전 버전으로 복원
|
|
4. `src/index.ts` 이전 버전으로 복원
|
|
5. `npm run deploy`
|
|
|
|
---
|
|
|
|
## 추가 리소스
|
|
|
|
- **상세 마이그레이션 가이드:** `/Users/kaffa/telegram-bot-workers/KV_MIGRATION_GUIDE.md`
|
|
- **Cloudflare KV Docs:** https://developers.cloudflare.com/kv/
|
|
- **Workers KV Limits:** https://developers.cloudflare.com/workers/platform/limits/#kv
|
|
|
|
---
|
|
|
|
## 체크리스트
|
|
|
|
배포 전:
|
|
- [ ] `wrangler kv:namespace create RATE_LIMIT_KV` 실행
|
|
- [ ] `wrangler.toml`에 실제 KV Namespace ID 입력
|
|
- [ ] `npx tsc --noEmit` 타입 에러 없음
|
|
- [ ] `npm run dev` 로컬 테스트 성공
|
|
- [ ] Rate Limit 테스트 (30회 연속 요청)
|
|
|
|
배포 후:
|
|
- [ ] `npm run deploy` 성공
|
|
- [ ] Health Check 정상 (`/health` 엔드포인트)
|
|
- [ ] 실제 Telegram 메시지 테스트 성공
|
|
- [ ] KV Dashboard에서 키 생성 확인
|
|
- [ ] `wrangler tail` 로그 확인
|
|
- [ ] 30회 연속 메시지로 Rate Limit 동작 확인
|
|
|
|
---
|
|
|
|
**작업 완료 시각:** 2026-01-19
|
|
**배포 담당자:** Claude Code (AI Assistant)
|
|
**상태:** ✅ 코드 변경 완료 / ⏳ KV Namespace 생성 대기 중
|