feat: add Queue-based server provisioning with security fixes

- Add Cloudflare Queue for async server provisioning
  - Producer: callback-handler.ts sends to queue
  - Consumer: provision-consumer.ts processes orders
  - DLQ: provision-dlq.ts handles failed orders with refund

- Security improvements (from code review):
  - Store password hash instead of plaintext (SHA-256)
  - Exclude root_password from logs
  - Add retryable flag to prevent duplicate instance creation
  - Atomic balance deduction with db.batch()
  - Race condition prevention with UPDATE...WHERE status='pending'
  - Auto-refund on DLQ processing

- Validation improvements:
  - OS image whitelist validation
  - Session required fields validation
  - Queue handler refactoring

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-24 22:54:15 +09:00
parent 2494593b62
commit 1fead51eff
7 changed files with 488 additions and 87 deletions

View File

@@ -1,4 +1,4 @@
import { Env, EmailMessage } from './types';
import { Env, EmailMessage, ProvisionMessage } from './types';
import { sendMessage, setWebhook, getWebhookInfo } from './telegram';
import { handleWebhook } from './routes/webhook';
import { handleApiRequest } from './routes/api';
@@ -6,6 +6,8 @@ import { handleHealthCheck } from './routes/health';
import { parseBankSMS } from './services/bank-sms-parser';
import { matchPendingDeposit } from './services/deposit-matcher';
import { reconcileDeposits, formatReconciliationReport } from './utils/reconciliation';
import { handleProvisionQueue } from './queue/provision-consumer';
import { handleProvisionDLQ } from './queue/provision-dlq';
export default {
// HTTP 요청 핸들러
@@ -279,4 +281,19 @@ Documentation: https://github.com/your-repo
// 정합성 검증 실패가 전체 Cron을 중단시키지 않도록 에러를 catch만 하고 계속 진행
}
},
// Queue 핸들러 (서버 프로비저닝)
async queue(batch: MessageBatch<ProvisionMessage>, env: Env): Promise<void> {
const QUEUE_HANDLERS: Record<string, (batch: MessageBatch<ProvisionMessage>, env: Env) => Promise<void>> = {
'server-provision-queue': handleProvisionQueue,
'provision-dlq': handleProvisionDLQ,
};
const handler = QUEUE_HANDLERS[batch.queue];
if (handler) {
return handler(batch, env);
}
console.error(`[Queue] Unknown queue: ${batch.queue}`);
},
};