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:
123
CLAUDE.md
123
CLAUDE.md
@@ -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 캐시 히트율 기반 원본 서버 트래픽 및 비용 계산
|
||||
|
||||
|
||||
Reference in New Issue
Block a user