Security Architecture

8.1 Authentication Flow

┌─────────────────────────────────────────────────────────────────────────────┐
│                         AUTHENTICATION ARCHITECTURE                          │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                          TOKEN LIFECYCLE                              │   │
│  │                                                                       │   │
│  │   1. Customer creates API token via console                          │   │
│  │      ┌──────────────┐                                                │   │
│  │      │ POST /tokens │ ──▶ Generate JWT signed with platform key      │   │
│  │      └──────────────┘      │                                         │   │
│  │                            ▼                                         │   │
│  │   2. Token stored:   ┌──────────────┐                               │   │
│  │      - Hash in D1    │ Token Claims │                               │   │
│  │      - Cache in KV   │ - customer_id│                               │   │
│  │                      │ - permissions│                               │   │
│  │                      │ - expires_at │                               │   │
│  │                      └──────────────┘                               │   │
│  │                                                                       │   │
│  │   3. Client uses token in requests                                   │   │
│  │      Authorization: Bearer <token>                                   │   │
│  │                                                                       │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                       REQUEST AUTHENTICATION                          │   │
│  │                                                                       │   │
│  │   Request ──▶ Extract Token ──▶ Validate Signature ──▶ Check Expiry  │   │
│  │                     │                    │                    │       │   │
│  │                     ▼                    ▼                    ▼       │   │
│  │              ┌─────────────┐     ┌─────────────┐     ┌─────────────┐ │   │
│  │              │ KV Cache    │     │ JWT Verify  │     │ Permission  │ │   │
│  │              │ Lookup      │     │ (EdDSA)     │     │ Check       │ │   │
│  │              └─────────────┘     └─────────────┘     └─────────────┘ │   │
│  │                                                                       │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

8.2 JWT Token Structure

// auth/src/tokens.ts
interface TokenPayload {
  // Standard claims
  iss: 'compute-arbitrage';
  sub: string;      // customer_id
  aud: 'api';
  exp: number;      // Expiration timestamp
  iat: number;      // Issued at
  jti: string;      // Unique token ID
  
  // Custom claims
  permissions: Permission[];
  tier: 'free' | 'pro' | 'enterprise';
  metadata: Record<string, string>;
}

type Permission = 
  | 'workloads:create'
  | 'workloads:read'
  | 'workloads:delete'
  | 'workloads:*'
  | 'billing:read'
  | 'tokens:manage';

export async function createToken(
  env: Env,
  customerId: string,
  options: TokenOptions
): Promise<{ token: string; id: string }> {
  const tokenId = crypto.randomUUID();
  
  const payload: TokenPayload = {
    iss: 'compute-arbitrage',
    sub: customerId,
    aud: 'api',
    exp: options.expiresAt || Math.floor(Date.now() / 1000) + 86400 * 365, // 1 year
    iat: Math.floor(Date.now() / 1000),
    jti: tokenId,
    permissions: options.permissions,
    tier: options.tier,
    metadata: options.metadata || {},
  };
  
  // Sign with Ed25519 private key
  const token = await signJWT(payload, env.JWT_PRIVATE_KEY);
  
  // Store token metadata (not the token itself)
  await env.DB.prepare(`
    INSERT INTO api_tokens (id, customer_id, token_hash, name, permissions, created_at, expires_at)
    VALUES (?, ?, ?, ?, ?, ?, ?)
  `).bind(
    tokenId,
    customerId,
    await hashToken(token),
    options.name,
    JSON.stringify(options.permissions),
    Date.now(),
    payload.exp * 1000
  ).run();
  
  // Cache token prefix for fast validation
  const tokenPrefix = token.substring(0, 16);
  await env.AUTH_KV.put(
    `token:${tokenPrefix}`,
    JSON.stringify({ customerId, permissions: options.permissions, expiresAt: payload.exp }),
    { expirationTtl: Math.max(3600, payload.exp - Math.floor(Date.now() / 1000)) }
  );
  
  return { token, id: tokenId };
}

export async function validateToken(
  env: Env,
  token: string
): Promise<TokenValidation> {
  // Fast path: check KV cache
  const tokenPrefix = token.substring(0, 16);
  const cached = await env.AUTH_KV.get(`token:${tokenPrefix}`, 'json');
  
  if (cached && cached.expiresAt > Math.floor(Date.now() / 1000)) {
    return {
      valid: true,
      customerId: cached.customerId,
      permissions: cached.permissions,
    };
  }
  
  // Slow path: full JWT validation
  try {
    const payload = await verifyJWT(token, env.JWT_PUBLIC_KEY);
    
    // Check if token was revoked
    const tokenRecord = await env.DB.prepare(
      'SELECT * FROM api_tokens WHERE id = ?'
    ).bind(payload.jti).first();
    
    if (!tokenRecord) {
      return { valid: false, error: 'Token revoked' };
    }
    
    // Update cache
    await env.AUTH_KV.put(
      `token:${tokenPrefix}`,
      JSON.stringify({
        customerId: payload.sub,
        permissions: payload.permissions,
        expiresAt: payload.exp,
      }),
      { expirationTtl: Math.min(3600, payload.exp - Math.floor(Date.now() / 1000)) }
    );
    
    return {
      valid: true,
      customerId: payload.sub,
      permissions: payload.permissions,
    };
  } catch (e) {
    return { valid: false, error: e.message };
  }
}

8.3 Network Security

┌─────────────────────────────────────────────────────────────────────────────┐
│                           NETWORK SECURITY MODEL                             │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                         End User Access                              │    │
│  │                                                                      │    │
│  │   Users ──▶ Cloudflare Edge ──▶ Workers ──▶ Workload Instances      │    │
│  │              (DDoS protection)   (Auth)      (Isolated VPCs)        │    │
│  │                                                                      │    │
│  │   - All traffic through Cloudflare (no direct instance access)      │    │
│  │   - TLS 1.3 everywhere                                              │    │
│  │   - JWT validation at edge                                          │    │
│  │   - Per-customer rate limiting                                      │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────┐    │
│  │                    Cloud Infrastructure Security                     │    │
│  │                                                                      │    │
│  │   ┌──────────────┐         ┌──────────────┐                        │    │
│  │   │   Customer   │         │   Customer   │                        │    │
│  │   │   VPC/VNet   │         │   VPC/VNet   │                        │    │
│  │   │              │         │              │                        │    │
│  │   │  ┌────────┐  │         │  ┌────────┐  │                        │    │
│  │   │  │Workload│  │         │  │Workload│  │                        │    │
│  │   │  │Instance│  │         │  │Instance│  │                        │    │
│  │   │  └────────┘  │         │  └────────┘  │                        │    │
│  │   │              │         │              │                        │    │
│  │   │  Security    │         │  Security    │                        │    │
│  │   │  Groups:     │         │  Groups:     │                        │    │
│  │   │  - Ingress:  │         │  - Ingress:  │                        │    │
│  │   │    CF IPs    │         │    CF IPs    │                        │    │
│  │   │  - Egress:   │         │  - Egress:   │                        │    │
│  │   │    Internet  │         │    Internet  │                        │    │
│  │   └──────────────┘         └──────────────┘                        │    │
│  │                                                                      │    │
│  │   - Full VPC isolation per customer                                 │    │
│  │   - Security groups allow only Cloudflare IPs                       │    │
│  │   - IAM roles scoped to minimum permissions                         │    │
│  │   - All provisioning via Kivera (audit + policy enforcement)        │    │
│  └─────────────────────────────────────────────────────────────────────┘    │
│                                                                              │
└─────────────────────────────────────────────────────────────────────────────┘

8.4 Secrets Management

// All secrets stored in Cloudflare Workers Secrets (encrypted at rest)
// Accessed via env bindings

interface Env {
  // Platform secrets
  JWT_PRIVATE_KEY: string;
  JWT_PUBLIC_KEY: string;
  
  // Kivera credentials
  KIVERA_USERNAME: string;
  KIVERA_PASSWORD: string;
  KIVERA_PROXY_ENDPOINT: string;
  
  // Per-provider credentials (stored per customer in encrypted format)
  // Actual credentials fetched from encrypted storage at runtime
  CREDENTIALS_ENCRYPTION_KEY: string;
}

// Customer credentials stored encrypted in D1
// Decrypted only when needed for provisioning
async function getCustomerCloudCredentials(
  env: Env,
  customerId: string,
  provider: string
): Promise<CloudCredentials> {
  const encrypted = await env.DB.prepare(`
    SELECT encrypted_credentials FROM customer_cloud_accounts
    WHERE customer_id = ? AND provider = ?
  `).bind(customerId, provider).first();
  
  if (!encrypted) {
    throw new Error(`No ${provider} credentials for customer`);
  }
  
  // Decrypt using platform key
  return decryptCredentials(encrypted.encrypted_credentials, env.CREDENTIALS_ENCRYPTION_KEY);
}