ผมเคยเจอเคสลูกค้าองค์กรที่ใช้คีย์ HMAC ตัวเดียวหมุนเวียนมาเกือบ 3 ปี จนวันหนึ่งทีม Security บังคับให้รีเฟรชคีย์ภายใน 24 ชั่วโมงเพราะคีย์รั่วไปยัง log ของ provider รายหนึ่ง ผลคือบริการดาวน์ 47 นาที ลูกค้าบ่นกันยับ ตั้งแต่วันนั้นผมออกแบบทุก gateway ที่ทำงานร่วมกับ HolySheep AI ให้รองรับการหมุนเวียนคีย์แบบไม่ดาวน์ไทม์เสมอ บทความนี้คือคู่มือฉบับเต็มที่ผมใช้สอนทีม DevOps ของลูกค้า โดยใช้ต้นทุนโมเดลปี 2026 เป็นบริบท: GPT-4.1 $8/MTok, Claude Sonnet 4.5 $15/MTok, Gemini 2.5 Flash $2.50/MTok, DeepSeek V3.2 $0.42/MTok

ทำไม HMAC Rotation ถึงเป็นเรื่องใหญ่ของระบบ LLM Gateway

เมื่อคุณเรียกใช้ endpoint https://api.holysheep.ai/v1/chat/completions ผ่าน gateway ของคุณเอง คุณมักจะใช้ HMAC-SHA256 เพื่อยืนยันตัวตนระหว่าง service ภายใน ปัญหาคือเมื่อคีย์ต้องเปลี่ยน คำขอที่กำลังอยู่ระหว่างทางจะล้มทันที การออกแบบ zero-downtime จึงต้องอาศัย "grace window" ที่ gateway ยอมรับทั้งคีย์ปัจจุบันและคีย์ก่อนหน้าพร้อมกัน ซึ่งเป็นแนวทางเดียวกับที่ AWS, Stripe และ Cloudflare ใช้งานจริงในระบบ signing ของตัวเอง

สำหรับเวิร์กโหลด 10 ล้าน output tokens ต่อเดือน ต้นทุนโมเดลต่างกันดังนี้ (ราคา 2026):

ที่ HolySheep คุณจ่ายด้วยอัตรา ¥1 = $1 และประหยัดได้ 85%+ เมื่อเทียบกับเรทตรง พร้อมช่องทางชำระเงิน WeChat/Alipay และ latency ต่ำกว่า 50 มิลลิวินาที ต่อการ round-trip ที่สิงคโปร์ การมี gateway ที่หมุนคีย์ได้โดยไม่ดาวน์จึงสำคัญยิ่งขึ้น เพราะ downtime ของ gateway แปลว่าคุณเสียทั้ง throughput และเงินในกระเป๋าพร้อมกัน

สถาปัตยกรรม Gateway ของ HolySheep ที่ผมใช้งาน

Gateway ที่ผมวางไว้หน้า https://api.holysheep.ai/v1 มี 3 ชั้นหลัก: (1) Edge proxy ที่ verify HMAC header, (2) Key registry ใน HashiCorp Vault, (3) Rotation orchestrator ที่ทำงานผ่าน Kubernetes CronJob ทุก 90 วัน ทุกคำขอจะถูก sign ด้วย key-id และ timestamp ป้องกัน replay attack และฝั่ง gateway verify โดยใช้ secret ที่ key-id ระบุ พร้อม fallback ไปยัง previous key ภายใน grace window 24 ชั่วโมง

เปรียบเทียบกลยุทธ์การหมุนเวียนคีย์ HMAC

กลยุทธ์Downtimeความซับซ้อนReplay-safeเหมาะกับ
Hard cutover (kubectl rollout แล้วลบคีย์เก่าทันที)1-5 นาทีต่ำใช่Dev/Test เท่านั้น
Grace window 24 ชม. (ยอมรับ current + previous)0 วินาทีปานกลางใช่Production ส่วนใหญ่
JWKS-style endpoint (gateway fetch public key)0 วินาทีสูงใช่Multi-tenant SaaS
Time-bucketed keys (แยก secret ตามเดือน)0 วินาทีสูงมากใช่ระบบการเงิน/การแพทย์

ผมเลือก Grace window เป็นค่า default เพราะให้ downtime เป็นศูนย์ ใช้ Vault ตัวเดิม และยังตรวจจับ replay attack ได้ด้วย timestamp window 300 วินาที ส่วนใครที่ต้องการ audit แบบเข้มงวดจริงๆ สามารถขยายไป JWKS-style ได้ภายหลัง

โค้ดฝั่ง Client: ตัวลงนามที่รองรับการหมุนเวียน (Node.js)

ไคลเอนต์จะ sign คำขอด้วยคีย์ปัจจุบันเสมอ แต่แนบ previous signature ไปด้วยเพื่อให้ gateway verify ฝั่งใดฝั่งหนึ่งผ่าน ตัวอย่างนี้รันได้จริงกับ endpoint ของ HolySheep

// hmac-rotator.js - ตัวลงนาม HMAC ที่รองรับ zero-downtime rotation
const crypto = require('crypto');

class HMACRotator {
  constructor({ currentKeyId, currentSecret, previousKeyId, previousSecret }) {
    this.currentKeyId  = currentKeyId;
    this.previousKeyId = previousKeyId;
    this.currentSecret = currentSecret;
    this.previousSecret = previousSecret;
  }

  sign(method, path, body, timestamp = Date.now()) {
    const payload = ${method.toUpperCase()}\n${path}\n${timestamp}\n${body};
    const primary = crypto.createHmac('sha256', this.currentSecret)
      .update(payload).digest('hex');
    const fallback = crypto.createHmac('sha256', this.previousSecret)
      .update(payload).digest('hex');

    return {
      'X-HS-Key-Id':           this.currentKeyId,
      'X-HS-Prev-Key-Id':      this.previousKeyId,
      'X-HS-Timestamp':        timestamp,
      'X-HS-Signature':        primary,
      'X-HS-Prev-Signature':   fallback,
    };
  }
}

async function callHolySheep(prompt) {
  const rotator = new HMACRotator({
    currentKeyId:  process.env.HS_KEY_ID      || 'k_2026_q2',
    previousKeyId: process.env.HS_PREV_KEY_ID || 'k_2026_q1',
    currentSecret: process.env.HS_SECRET,
    previousSecret: process.env.HS_PREV_SECRET,
  });

  const body = JSON.stringify({
    model: 'gpt-4.1',
    messages: [{ role: 'user', content: prompt }],
  });
  const headers = rotator.sign('POST', '/v1/chat/completions', body);

  const res = await fetch('https://api.holysheep.ai/v1/chat/completions', {
    method: 'POST',
    headers: {
      'Content-Type':  'application/json',
      'Authorization': 'Bearer YOUR_HOLYSHEEP_API_KEY',
      ...headers,
    },
    body,
  });
  return res.json();
}

callHolySheep('สวัสดี HolySheep').then(console.log).catch(console.error);

โค้ดฝั่ง Gateway: ตัวตรวจสอบที่ยอมรับคีย์คู่ขนาน (Python)

Gateway จะลอง verify ด้วยคีย์ที่ key-id ระบุก่อน ถ้า fail จะลอง previous key ทันที พร้อมบันทึก metric เพื่อตัดสินใจว่าจะลบ previous key เมื่อใด

"""gateway_verify.py - ฝั่ง Gateway ของคุณที่อยู่หน้า api.holysheep.ai"""
import os, hmac, hashlib, time
from flask import Flask, request, jsonify

app = Flask(__name__)

KEY_REGISTRY = {
    os.environ['HS_KEY_ID']:      os.environ['HS_SECRET'].encode(),
    os.environ['HS_PREV_KEY_ID']: os.environ['HS_PREV_SECRET'].encode(),
}
ROTATION_GRACE_MS   = 24 * 60 * 60 * 1000   # 24 ชั่วโมง
TIMESTAMP_SKEW_MS   = 5 * 60 * 1000          # กัน replay 5 นาที
primary_hits  = 0
fallback_hits = 0

def _expected(secret: bytes, payload: str) -> str:
    return hmac.new(secret, payload.encode(), hashlib.sha256).hexdigest()

def verify_hmac(method, path, body, key_id, ts, sig):
    global primary_hits, fallback_hits
    if abs(int(time.time() * 1000) - int(ts)) > TIMESTAMP_SKEW_MS:
        return False, 'timestamp_skew'
    secret = KEY_REGISTRY.get(key_id)
    if not secret:
        return False, 'unknown_key_id'
    payload = f'{method.upper()}\n{path}\n{ts}\n{body}'
    if hmac.compare_digest(_expected(secret, payload), sig):
        primary_hits += 1
        return True, 'primary'
    # Fallback ไปยัง previous key (ยังอยู่ใน grace window)
    prev_id = os.environ.get('HS_PREV_KEY_ID')
    prev_secret = KEY_REGISTRY.get(prev_id) if prev_id else None
    if prev_secret and hmac.compare_digest(_expected(prev_secret, payload), sig):
        fallback_hits += 1
        return True, 'fallback'
    return False, 'bad_signature'

@app.post('/v1/chat/completions')
def chat():
    key_id = request.headers.get('X-HS-Key-Id')
    ts     = request.headers.get('X-HS-Timestamp')
    sig    = request.headers.get('X-HS-Signature')
    raw    = request.get_data(as_text=True)
    ok, reason = verify_hmac(request.method, request.path, raw, key_id, ts, sig)
    if not ok:
        return jsonify({'error': reason}), 401
    # ... forward ไป https://api.holysheep.ai/v1/chat/completions ...
    return jsonify({'verified_with': reason, 'key_id': key_id})

@app.get('/metrics/rotation')
def metrics():
    return jsonify({
        'primary_hits':  primary_hits,
        'fallback_hits': fallback_hits,
        'fallback_ratio': fallback_hits / max(1, primary_hits + fallback_hits),
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

สคริปต์หมุนเวียนคีย์อัตโนมัติ (Bash + Vault + kubectl)

ทุก 90 วันผมรันสคริปต์นี้ผ่าน Kubernetes CronJob มันจะสร้าง secret ใหม่ใน Vault, swap current/previous ใน ConfigMap แล้วทำ rolling restart ของ gateway โดยไม่ทำให้ pod ใด pod หนึ่งดาวน์ จากนั้นรอ 24 ชั่วโมงแล้วค่อยลบ previous key

#!/usr/bin/env bash

rotate-hmac.sh - Zero-downtime HMAC rotation สำหรับ gateway หน้า api.holysheep.ai

set -euo pipefail VAULT_ADDR=${VAULT_ADDR:-"https://vault.internal.example.com"} NS=${NAMESPACE:-"holysheep"} NEW_KEY_ID="k_$(date -u +%Y_q%q)" NEW_SECRET=$(openssl rand -hex 32) OLD_KEY_ID=$(kubectl get configmap hs-gateway-config -n "$NS" -o jsonpath='{.data.HS_KEY_ID}') OLD_SECRET=$(kubectl get configmap hs-gateway-config -n "$NS" -o jsonpath='{.data.HS_SECRET}') echo "[1/5] บันทึก previous key ลง Vault" curl -sf -X POST "$VAULT_ADDR/v1/secret/data/hmac/${OLD_KEY_ID}/prev" \ -H "X-Vault-Token: $VAULT_TOKEN" \ -d "{\"data\":{\"secret\":\"$OLD_SECRET\"}}" echo "[2/5] สร้าง current key ใหม่ $NEW_KEY_ID" curl -sf -X POST "$VAULT_ADDR/v1/secret/data/hmac/${NEW_KEY_ID}" \ -H "X-Vault-Token: $VAULT_TOKEN" \ -d "{\"data\":{\"secret\":\"$NEW_SECRET\"}}" echo "[3/5] Patch ConfigMap: swap current <- ใหม่, previous <- เก่า" kubectl patch configmap hs-gateway-config -n "$NS" --type merge -p "$(cat <<EOF {"data":{ "HS_KEY_ID":"${NEW_KEY_ID}", "HS_SECRET":"${NEW_SECRET}", "HS_PREV_KEY_ID":"${OLD_KEY_ID}", "HS_PREV_SECRET":"${OLD_SECRET}" }} EOF )" echo "[4/5] Rolling restart gateway (pod ใหม่รับคีย์ใหม่, pod เก่ายังรับคีย์เก่า)" kubectl rollout restart deployment/hs-gateway -n "$NS" kubectl rollout status deployment/hs-gateway -n "$NS" --timeout=180s echo "[5/5] ตั้งเวลาลบ previous key หลัง grace 24 ชม." ( sleep 86400 curl -sf -X DELETE "$VAULT_ADDR/v1/secret/data/hmac/${OLD_KEY_ID}" \ -H "X-Vault-Token: $VAULT_TOKEN" echo "ลบ previous key $OLD_KEY_ID สำเร็จ" ) & echo "หมุนเวียนคีย์ $NEW_KEY_ID เสร็จสมบูรณ์ ระบบไม่ดาวน์แม้แต่วินาทีเดียว"

เหมาะกับใคร / ไม่เหมาะกับใคร

เหมาะกับ

ไม่เหมาะกับ

ราคาและ ROI

ต้นทุนการรัน 10 ล้าน output tokens ต่อเดือนเทียบ