# ADR-010: 集中式 Secrets 管理架構 **狀態**: 已批准 **日期**: 2026-03-23 **決策者**: 統帥 ## 背景 ### 當前痛點 ``` 問題:密碼散落各處,變更一處 → 全線崩潰 Harbor 密碼存在位置: ├── GitHub Secrets (wooo-aiops) ├── GitHub Secrets (awoooi) ← 今天才補上 ├── K8s Secrets (awoooi-prod) ├── Self-hosted Runner 環境變數 ├── 開發者本地 ~/.docker/config.json └── 文檔/記憶體 MD 檔案 結果: - 變更密碼需同步 5+ 個地方 - 經常遺漏 → CI/CD 崩潰 - 無審計日誌 - 無法追蹤誰何時改了什麼 ``` ### 需要管理的 Secrets 清單 | 類別 | Secret 名稱 | 使用位置 | |------|------------|----------| | **Registry** | HARBOR_USER / HARBOR_PASSWORD | CI/CD, K8s | | **Database** | DATABASE_URL (PostgreSQL) | API, Worker | | **Cache** | REDIS_URL | API, Worker, OpenClaw | | **AI** | ANTHROPIC_API_KEY | API (Agent Teams) | | **AI** | GEMINI_API_KEY | API (Fallback) | | **AI** | OLLAMA_URL | API (Local LLM) | | **Notification** | OPENCLAW_TG_BOT_TOKEN | OpenClaw | | **Notification** | OPENCLAW_TG_CHAT_ID | OpenClaw | | **K8s** | KUBECONFIG | CI/CD | | **Webhook** | WEBHOOK_HMAC_SECRET | API | --- ## 決策 採用 **混合式 Secrets 管理架構**: 1. **Bitwarden (Self-hosted)** - Single Source of Truth 2. **Sealed Secrets** - K8s 內部密碼加密 3. **GitHub Secrets** - CI/CD 專用 (從 Bitwarden 同步) --- ## 架構設計 ``` ┌─────────────────────────────────────────────────────────────────────┐ │ AWOOOI Secrets 管理架構 │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ ┌───────────────────────────────────────────────────────────────┐ │ │ │ Bitwarden (Self-hosted on 192.168.0.188) │ │ │ │ ══════════════════════════════════════ │ │ │ │ 🔐 Single Source of Truth │ │ │ │ │ │ │ │ Organizations: │ │ │ │ └── AWOOOI/ │ │ │ │ ├── Infrastructure/ │ │ │ │ │ ├── Harbor (admin / Wooo_Harbor_2026!) │ │ │ │ │ ├── PostgreSQL (awoooi / ******) │ │ │ │ │ └── Redis (password / ******) │ │ │ │ ├── AI-Services/ │ │ │ │ │ ├── Anthropic API Key │ │ │ │ │ ├── Gemini API Key │ │ │ │ │ └── Ollama URL │ │ │ │ └── Notifications/ │ │ │ │ ├── Telegram Bot Token │ │ │ │ └── Telegram Chat ID │ │ │ └───────────────────────────────────────────────────────────────┘ │ │ │ │ │ ┌───────────────┼───────────────┐ │ │ │ │ │ │ │ ▼ ▼ ▼ │ │ ┌─────────────────┐ ┌─────────────┐ ┌─────────────────┐ │ │ │ GitHub Secrets │ │ Sealed │ │ Local Dev │ │ │ │ (CI/CD) │ │ Secrets │ │ (.env.local) │ │ │ │ │ │ (K8s) │ │ │ │ │ │ HARBOR_USER │ │ │ │ bw get password │ │ │ │ HARBOR_PASSWORD │ │ 加密存 Git │ │ "Harbor" │ │ │ │ OP_TOKEN (sync) │ │ 自動解密 │ │ │ │ │ └────────┬────────┘ └──────┬──────┘ └─────────────────┘ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────┐ │ │ │ K3s Cluster (192.168.0.120/121) │ │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │ │ │ awoooi-prod namespace │ │ │ │ │ │ ├── awoooi-secrets (from Sealed Secrets) │ │ │ │ │ │ ├── awoooi-config (ConfigMap, non-sensitive) │ │ │ │ │ │ └── Pods (consume secrets as env vars) │ │ │ │ │ └─────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────┘ ``` --- ## 實施計畫 ### Phase 1: Bitwarden Self-hosted (Day 1-2) ```bash # 在 192.168.0.188 部署 Vaultwarden (輕量版 Bitwarden) docker run -d --name vaultwarden \ -v /data/vaultwarden:/data \ -e ADMIN_TOKEN='your-admin-token' \ -e DOMAIN='https://vault.wooo.work' \ -p 8088:80 \ vaultwarden/server:latest # Nginx 設定 server { listen 443 ssl; server_name vault.wooo.work; location / { proxy_pass http://localhost:8088; } } ``` **初始化步驟:** 1. 訪問 https://vault.wooo.work 2. 建立 Organization: AWOOOI 3. 建立 Collections: Infrastructure, AI-Services, Notifications 4. 匯入現有密碼 ### Phase 2: Sealed Secrets (Day 2-3) ```bash # Step 1: 安裝 Sealed Secrets Controller kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.26.0/controller.yaml # Step 2: 取得 Public Key kubeseal --fetch-cert \ --controller-name=sealed-secrets-controller \ --controller-namespace=kube-system \ > /Users/ogt/awoooi/k8s/sealed-secrets-cert.pem # Step 3: 加密現有 Secrets cat < /tmp/secrets.yaml apiVersion: v1 kind: Secret metadata: name: awoooi-secrets namespace: awoooi-prod type: Opaque stringData: DATABASE_URL: "postgresql+asyncpg://awoooi:xxx@192.168.0.188:5432/awoooi_prod" REDIS_URL: "redis://:xxx@192.168.0.188:6380/10" HARBOR_USER: "admin" HARBOR_PASSWORD: "Wooo_Harbor_2026!" ANTHROPIC_API_KEY: "sk-ant-xxx" EOF kubeseal --cert=sealed-secrets-cert.pem \ --format=yaml \ < /tmp/secrets.yaml \ > k8s/awoooi-prod/03-sealed-secrets.yaml # 清理明文 rm /tmp/secrets.yaml # Step 4: 提交加密版本 git add k8s/awoooi-prod/03-sealed-secrets.yaml git commit -m "feat(security): migrate to Sealed Secrets" ``` ### Phase 3: GitHub Actions 整合 (Day 3-4) ```yaml # .github/workflows/sync-secrets.yml name: Sync Secrets from Bitwarden on: workflow_dispatch: schedule: - cron: '0 0 * * 0' # 每週日同步 jobs: sync: runs-on: [self-hosted, harbor, k8s] steps: - name: Install Bitwarden CLI run: | npm install -g @bitwarden/cli bw config server https://vault.wooo.work - name: Login & Sync env: BW_PASSWORD: ${{ secrets.BW_MASTER_PASSWORD }} run: | export BW_SESSION=$(bw login --raw) # 取得 Harbor 認證 HARBOR_USER=$(bw get username "Harbor") HARBOR_PASSWORD=$(bw get password "Harbor") # 更新 GitHub Secrets gh secret set HARBOR_USER --body "$HARBOR_USER" gh secret set HARBOR_PASSWORD --body "$HARBOR_PASSWORD" echo "✅ Secrets synced from Bitwarden" ``` ### Phase 4: 開發者本地環境 (Day 4) ```bash # 安裝 Bitwarden CLI brew install bitwarden-cli # 登入 bw config server https://vault.wooo.work bw login # 產生 .env.local cat > generate-env.sh << 'EOF' #!/bin/bash export BW_SESSION=$(bw unlock --raw) echo "DATABASE_URL=$(bw get password 'PostgreSQL')" > .env.local echo "REDIS_URL=$(bw get password 'Redis')" >> .env.local echo "ANTHROPIC_API_KEY=$(bw get password 'Anthropic')" >> .env.local echo "✅ .env.local generated from Bitwarden" EOF chmod +x generate-env.sh ``` --- ## 密碼 Rotation SOP ### 變更密碼流程 ``` ┌─────────────────────────────────────────────────────────────┐ │ 密碼變更 SOP (Single Source of Truth) │ ├─────────────────────────────────────────────────────────────┤ │ │ │ Step 1: 在 Bitwarden 更新密碼 │ │ └── vault.wooo.work → Edit → Save │ │ │ │ Step 2: 觸發同步 Workflow │ │ └── gh workflow run sync-secrets.yml │ │ │ │ Step 3: 重新 Seal K8s Secrets │ │ └── ./scripts/reseal-secrets.sh │ │ │ │ Step 4: 部署更新 │ │ └── kubectl apply -f k8s/awoooi-prod/ │ │ │ │ Step 5: 驗證 │ │ └── curl https://awoooi.wooo.work/api/v1/health │ │ │ └─────────────────────────────────────────────────────────────┘ ``` ### 自動化 Rotation Script ```bash #!/bin/bash # scripts/rotate-secret.sh SECRET_NAME=$1 NEW_VALUE=$2 if [ -z "$SECRET_NAME" ] || [ -z "$NEW_VALUE" ]; then echo "Usage: ./rotate-secret.sh " exit 1 fi echo "🔄 Rotating secret: $SECRET_NAME" # Step 1: Update Bitwarden export BW_SESSION=$(bw unlock --raw) bw edit item "$SECRET_NAME" --value "$NEW_VALUE" # Step 2: Sync to GitHub gh workflow run sync-secrets.yml # Step 3: Re-seal K8s secrets ./scripts/reseal-secrets.sh # Step 4: Apply to cluster kubectl apply -f k8s/awoooi-prod/03-sealed-secrets.yaml # Step 5: Rolling restart kubectl rollout restart deployment -n awoooi-prod echo "✅ Secret rotated successfully" ``` --- ## 緊急撤銷流程 ```bash # 如果密碼洩漏,立即執行: # 1. 在 Bitwarden 產生新密碼 bw generate -ulns --length 32 # 2. 更新所有相關服務 ./scripts/rotate-secret.sh "Harbor" "$(bw generate -ulns --length 32)" # 3. 撤銷舊 Token (如適用) # Harbor: Admin UI → Users → Reset Password # GitHub: Settings → Secrets → Delete old, Add new # 4. 審計日誌檢查 bw list items --search "Harbor" --pretty ``` --- ## 監控與告警 ```yaml # 新增到 Prometheus 告警規則 groups: - name: secrets-monitoring rules: - alert: SecretRotationOverdue expr: time() - secret_last_rotation_timestamp > 86400 * 90 for: 1d labels: severity: warning annotations: summary: "Secret {{ $labels.secret_name }} 超過 90 天未輪換" - alert: SecretAccessAnomaly expr: rate(secret_access_total[1h]) > 100 for: 5m labels: severity: critical annotations: summary: "異常的 Secret 存取頻率" ``` --- ## 成本分析 | 項目 | 方案 | 成本 | |------|------|------| | Secrets 儲存 | Vaultwarden (Self-hosted) | $0 | | K8s 加密 | Sealed Secrets | $0 | | 同步工具 | Bitwarden CLI | $0 | | **總計** | | **$0/年** | --- ## 驗收標準 - [ ] Vaultwarden 部署在 192.168.0.188 - [ ] 所有 Secrets 已匯入 Bitwarden - [ ] Sealed Secrets Controller 運行中 - [ ] K8s Secrets 已加密存入 Git - [ ] GitHub Actions 可從 Bitwarden 同步 - [ ] 開發者可用 CLI 產生 .env.local - [ ] Rotation SOP 文件完成 - [ ] 監控告警已設定 --- ## 附錄:Secrets 清單 (機密) > ⚠️ 此清單僅供內部參考,實際密碼存於 Bitwarden | 名稱 | 類型 | 最後更新 | 下次 Rotation | |------|------|----------|---------------| | Harbor | Registry | 2026-03-23 | 2026-06-23 | | PostgreSQL | Database | TBD | TBD | | Redis | Cache | TBD | TBD | | Anthropic | API Key | TBD | TBD | | Gemini | API Key | TBD | TBD | | Telegram Bot | Token | 2026-03-22 | 2026-06-22 |