docs: update CLAUDE.md with security hardening and admin SSH key

- Add middleware directory to architecture diagram
- Document Admin SSH Key for server recovery
- Update Security Features section (origin validation, timeouts, etc.)
- Add TIMEOUTS and TECH_CATEGORY_WEIGHTS to config section
- Update secrets list with SSH key variables
- Add latest changes section for security hardening

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-29 11:39:26 +09:00
parent 5319bf3e4c
commit f62712af37

123
CLAUDE.md
View File

@@ -33,24 +33,32 @@ npx wrangler tail
```
src/
├── index.ts # Main router, CORS, Queue consumer
├── config.ts # Configuration constants
├── config.ts # Configuration constants (LIMITS, TIMEOUTS, i18n)
├── types.ts # TypeScript type definitions
├── region-utils.ts # Region matching utilities
├── utils.ts # Re-exports from utils/ (backward compatibility)
├── utils/ # Modular utilities
│ ├── index.ts # Central export point
│ ├── http.ts # HTTP responses, CORS, escapeHtml
│ ├── validation.ts # Input validation, type guards
│ ├── validation.ts # Input validation, type guards, escapeLikePattern
│ ├── bandwidth.ts # Bandwidth estimation & cost calculation
│ ├── cache.ts # Caching, rate limiting
│ ├── cache.ts # Caching, rate limiting (with time-based cleanup)
│ ├── ai.ts # AI prompt sanitization
│ └── exchange-rate.ts # Currency conversion
├── middleware/ # Request middleware
│ ├── index.ts # Central export point
│ ├── auth.ts # API key authentication
│ ├── origin.ts # Origin validation (restricts to .kappa-d8e.workers.dev)
│ ├── rate-limit.ts # Rate limiting middleware
│ ├── request-id.ts # Request ID generation
│ ├── security.ts # Security headers (CSP, HSTS, etc.)
│ └── user-id.ts # User ID extraction
├── repositories/
│ ├── AnvilServerRepository.ts # DB queries for Anvil servers
│ └── ProvisioningRepository.ts # Users, deposits, orders (telegram-conversations)
├── services/
│ ├── ai-service.ts # AI recommendations & fallback logic
│ ├── provisioning-service.ts # Server provisioning workflow
│ ├── provisioning-service.ts # Server provisioning workflow + SSH key injection
│ ├── vps-provider.ts # VPS provider abstract base class
│ ├── linode-provider.ts # Linode API implementation
│ └── vultr-provider.ts # Vultr API implementation
@@ -58,7 +66,7 @@ src/
│ ├── health.ts # GET /api/health
│ ├── servers.ts # GET /api/servers
│ ├── recommend.ts # POST /api/recommend
│ ├── report.ts # GET /api/recommend/report
│ ├── report.ts # GET /api/recommend/report (CSP: style-src 'unsafe-inline')
│ ├── provision.ts # POST/GET/DELETE /api/provision/*
│ └── queue.ts # Queue consumer for async provisioning
└── __tests__/
@@ -253,12 +261,16 @@ window.open(reportUrl); // Opens printable HTML
- **XSS prevention**: `escapeHtml()` applied to all user data in HTML reports
- **Input validation**: Comprehensive checks with length limits (tech_stack ≤20, use_case ≤500, region_preference ≤10 items)
- **Cache integrity**: Validates cached JSON structure before returning
- **Rate limiting**: 60 req/min per IP with in-memory fallback when KV unavailable
- **SQL injection prevention**: All queries use parameterized statements via Repository pattern
- **Rate limiting**: 60 req/min per IP with in-memory fallback (time-based sorting for cleanup)
- **SQL injection prevention**: All queries use parameterized statements + `escapeLikePattern()` for LIKE queries
- **Security headers**: CSP, HSTS, X-Frame-Options, X-Content-Type-Options
- **Origin validation**: Restricts browser requests to `.kappa-d8e.workers.dev` domain only
- **API key protection**: Keys never logged, sanitized from error messages
- **Prompt injection protection**: `sanitizeForAIPrompt()` filters malicious patterns
- **Password generation**: Rejection sampling for unbiased random character selection
- **Type safety**: No `any` types - uses `unknown` + type guards
- **Request size limits**: Base64 data parameter max 100KB for report endpoint
- **Timeout protection**: AbortController with configurable timeouts for all external APIs
### AI Fallback System (`services/ai-service.ts`)
@@ -324,17 +336,67 @@ On failure: Refund balance + status: failed
- Linode (`linode-provider.ts`)
- Vultr (`vultr-provider.ts`)
### Admin SSH Key for Server Recovery
Admin SSH key is automatically added to all provisioned servers for emergency recovery access.
**Environment Variables** (set via `wrangler secret put`):
```
ADMIN_SSH_PUBLIC_KEY # Linode: public key string (ssh-rsa AAAA... or ssh-ed25519 AAAA...)
ADMIN_SSH_KEY_ID_VULTR # Vultr: pre-registered SSH key ID (from Vultr dashboard/API)
```
**Provider Differences**:
| Provider | Parameter | Value Type | How to Set |
|----------|-----------|------------|------------|
| Linode | `authorized_keys` | Public key string | Direct: `ssh-ed25519 AAAA...` |
| Vultr | `sshkey_id` | Key ID | Register via dashboard/API first |
**Vultr SSH Key Registration** (one-time setup):
```bash
# Register key via Vultr API
curl -X POST "https://api.vultr.com/v2/ssh-keys" \
-H "Authorization: Bearer $VULTR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"anvil-admin","ssh_key":"ssh-ed25519 AAAA..."}'
# Response: {"ssh_key":{"id":"cb676a46-66fd-4dfb-..."}}
# Use this ID for ADMIN_SSH_KEY_ID_VULTR
```
**Password Recovery Options**:
| Provider | API Reset | Console Access |
|----------|-----------|----------------|
| Linode | ✅ `POST /linode/instances/{id}/password` | ✅ Lish via dashboard |
| Vultr | ❌ Not available | ✅ View Console in dashboard |
### Configuration (`config.ts`)
Centralized limits and constants:
```typescript
LIMITS = {
MAX_REQUEST_BODY_BYTES: 10240, // 10KB
CACHE_TTL_SECONDS: 300, // 5 minutes
RATE_LIMIT_MAX_REQUESTS: 60, // per minute
MAX_AI_CANDIDATES: 15, // reduce API cost
CACHE_TTL_SECONDS: 300, // 5 minutes
RATE_LIMIT_MAX_REQUESTS: 60, // per minute
MAX_AI_CANDIDATES: 15, // reduce API cost
MAX_TECH_STACK: 20,
MAX_USE_CASE_LENGTH: 500,
MAX_REGION_PREFERENCE: 10,
MAX_REGION_LENGTH: 50,
MAX_BASE64_DATA_LENGTH: 100000, // ~75KB decoded
}
TIMEOUTS = {
AI_REQUEST_MS: 30000, // 30 seconds for OpenAI
VPS_PROVIDER_API_MS: 60000, // 60 seconds for Linode/Vultr
TELEGRAM_API_MS: 10000, // 10 seconds for Telegram notifications
}
TECH_CATEGORY_WEIGHTS = {
heavy_db: 0.3, // analytics, log server, reporting
medium_heavy_db: 0.5, // e-commerce, ERP, CRM
medium_db: 0.7, // API, SaaS, app backend
light_db: 1.0, // blog, portfolio, wiki
}
```
@@ -366,7 +428,13 @@ max_retries = 3
dead_letter_queue = "provision-queue-dlq"
# Secrets (via wrangler secret put)
# OPENAI_API_KEY, LINODE_API_KEY, VULTR_API_KEY, PROVISION_API_KEY
# OPENAI_API_KEY - OpenAI API key for GPT-4o-mini
# LINODE_API_KEY - Linode API token
# VULTR_API_KEY - Vultr API key
# PROVISION_API_KEY - API key for /api/provision/* endpoints
# BOT_TOKEN - Telegram bot token for notifications (optional)
# ADMIN_SSH_PUBLIC_KEY - Admin SSH public key for Linode (optional)
# ADMIN_SSH_KEY_ID_VULTR - Admin SSH key ID for Vultr (optional)
```
## Testing
@@ -429,7 +497,38 @@ curl -s -X DELETE "https://cloud-orchestrator.kappa-d8e.workers.dev/api/provisio
## Recent Changes
### CDN Cache Hit Rate (Latest)
### Security Hardening & Admin SSH Key (Latest)
**Security Improvements**:
- CSP headers for HTML reports (`style-src 'unsafe-inline'`)
- Origin validation restricts to `.kappa-d8e.workers.dev` domain
- Base64 size limit (100KB) for report data parameter
- Rejection sampling for unbiased password generation
- SQL LIKE pattern escaping via `escapeLikePattern()`
- Rate limiter cleanup with time-based sorting
**Performance Improvements**:
- Telegram API timeout (10s) with AbortController
- Centralized TIMEOUTS config for all external APIs
- VPS provider timeout configurable (default 60s)
**New Features**:
- Admin SSH key support for server recovery
- `ADMIN_SSH_PUBLIC_KEY` for Linode (public key string)
- `ADMIN_SSH_KEY_ID_VULTR` for Vultr (pre-registered key ID)
- Middleware layer: auth, origin, rate-limit, request-id, security, user-id
- Idempotency key for order deduplication
**Code Quality**:
- 404 status when no servers found (was 200 with empty array)
- Consolidated error logging to single JSON.stringify
- Import TECH_CATEGORY_WEIGHTS from config.ts
**Files Added**:
- `src/middleware/{auth,origin,rate-limit,request-id,security,user-id}.ts`
- `migrations/004_add_idempotency_key.sql`
### CDN Cache Hit Rate
**New Feature**: CDN 캐시 히트율 기반 원본 서버 트래픽 및 비용 계산