feat(cd): ADR-090-B CD 注入 L2→L3 13 個 key — 消滅 K8s 單點盲區
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 11m38s
All checks were successful
CD Pipeline / build-and-deploy (push) Successful in 11m38s
2026-04-18 下午(台北時區)—— ogt + Claude Opus 4.7 (1M) 背景: Memory feedback_secrets_leak_incidents + reference_secrets_architecture_v2 定義 L1-L4 分層架構。盤點發現 14 個 K8s secret key 只存在 L3(K8s etcd) 而無 L2(Gitea Secret)備援,etcd 故障或 secret 誤刪將永久遺失。 本 commit 補上 13 個 key 的 L2→L3 CD 自動注入(SMTP_USER/SMTP_PASSWORD 仍為 CHANGE_ME 跳過): DATABASE_URL / MIGRATION_DATABASE_URL (ADR-090-B 新增) REDIS_URL / JWT_SECRET / JWT_ALGORITHM WEBHOOK_HMAC_SECRET (之前 L2 有但 CD 沒引) SENTRY_DSN / CLAUDE_API_KEY GITEA_API_TOKEN (via AWOOOI_GITEA_API_TOKEN 前綴繞過 Gitea 保留字) NEMOTRON_BOT_TOKEN / OPENCLAW_BOT_TOKEN SMTP_HOST / SRE_GROUP_CHAT_ID 模式: 完全照既有 cd.yaml `Inject K8s Secrets` step 模式 — env: 引用 + if [ -n ] guard + kubectl patch json op=add + base64 -w 0 + echo 結果。 110 行新增,0 行刪除,YAML 語法驗證通過。 安全: Gitea Secret 值從 K8s 現有 secret 同步(保持一致),本 CD run 為 no-op patch。 未來 K8s secret 誤刪或 rebuild 可從 Gitea 一鍵恢復。 相關: - docs/superpowers/specs/2026-04-18-blindspot-governance-capacity-l4.md - docs/adr/ADR-090-monitoring-blindspot-governance.md - apps/api/migrations/adr090b_awoooi_migrator_role.sql Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -252,6 +252,21 @@ jobs:
|
||||
GITEA_WEBHOOK_SECRET: ${{ secrets.AWOOOI_GITEA_WEBHOOK_SECRET }}
|
||||
# MCP Phase 3: ArgoCD API Token (2026-04-11 Claude Sonnet 4.6)
|
||||
ARGOCD_API_TOKEN: ${{ secrets.ARGOCD_API_TOKEN }}
|
||||
# 2026-04-18 ogt + Claude Opus 4.7: ADR-090-B L3-only 升級 L2(永久連線串 + 應用 secret)
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
MIGRATION_DATABASE_URL: ${{ secrets.MIGRATION_DATABASE_URL }}
|
||||
REDIS_URL: ${{ secrets.REDIS_URL }}
|
||||
JWT_SECRET: ${{ secrets.JWT_SECRET }}
|
||||
JWT_ALGORITHM: ${{ secrets.JWT_ALGORITHM }}
|
||||
WEBHOOK_HMAC_SECRET: ${{ secrets.WEBHOOK_HMAC_SECRET }}
|
||||
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
||||
CLAUDE_API_KEY: ${{ secrets.CLAUDE_API_KEY }}
|
||||
# AWOOOI_ 前綴避開 Gitea 保留字(同 AWOOOI_GITEA_WEBHOOK_SECRET 模式)
|
||||
GITEA_API_TOKEN: ${{ secrets.AWOOOI_GITEA_API_TOKEN }}
|
||||
NEMOTRON_BOT_TOKEN: ${{ secrets.NEMOTRON_BOT_TOKEN }}
|
||||
OPENCLAW_BOT_TOKEN: ${{ secrets.OPENCLAW_BOT_TOKEN }}
|
||||
SMTP_HOST: ${{ secrets.SMTP_HOST }}
|
||||
SRE_GROUP_CHAT_ID: ${{ secrets.SRE_GROUP_CHAT_ID }}
|
||||
run: |
|
||||
# S1/S2: 統一命名 deploy_key,改用 ssh-keyscan(比 StrictHostKeyChecking=no 更安全)
|
||||
mkdir -p ~/.ssh
|
||||
@@ -332,6 +347,101 @@ jobs:
|
||||
echo "⚠️ ARGOCD_API_TOKEN 未設定,ArgoCD MCP 將使用空 token"
|
||||
fi
|
||||
|
||||
# ============================================================================
|
||||
# ADR-090-B 2026-04-18 ogt + Claude Opus 4.7: L3-only 升級 L2(13 個 key)
|
||||
# ============================================================================
|
||||
# 目的: 消滅「只存 K8s etcd 單點」的災難盲區,Gitea Secret 成為正式真相來源
|
||||
# 注意: 每個 block 與上方維持相同結構(if guard + base64 -w 0 + json patch)
|
||||
|
||||
# DATABASE_URL — PG 應用連線串(2026-04-18 輪替)
|
||||
if [ -n "${DATABASE_URL}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/DATABASE_URL","value":"'$(echo -n "${DATABASE_URL}" | base64 -w 0)'"}
|
||||
]' && echo "✅ DATABASE_URL 已注入" || echo "⚠️ DATABASE_URL patch 失敗"
|
||||
else
|
||||
echo "⚠️ DATABASE_URL 未設定,awoooi-api 將無法連 PG"
|
||||
fi
|
||||
|
||||
# MIGRATION_DATABASE_URL — CI migration 用 awoooi_migrator 限權帳號(ADR-090-B)
|
||||
if [ -n "${MIGRATION_DATABASE_URL}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/MIGRATION_DATABASE_URL","value":"'$(echo -n "${MIGRATION_DATABASE_URL}" | base64 -w 0)'"}
|
||||
]' && echo "✅ MIGRATION_DATABASE_URL 已注入" || echo "⚠️ MIGRATION_DATABASE_URL patch 失敗"
|
||||
fi
|
||||
|
||||
# REDIS_URL — Redis 連線(6380 on 188)
|
||||
if [ -n "${REDIS_URL}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/REDIS_URL","value":"'$(echo -n "${REDIS_URL}" | base64 -w 0)'"}
|
||||
]' && echo "✅ REDIS_URL 已注入" || echo "⚠️ REDIS_URL patch 失敗"
|
||||
else
|
||||
echo "⚠️ REDIS_URL 未設定"
|
||||
fi
|
||||
|
||||
# JWT_SECRET / JWT_ALGORITHM — API 認證
|
||||
if [ -n "${JWT_SECRET}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/JWT_SECRET","value":"'$(echo -n "${JWT_SECRET}" | base64 -w 0)'"}
|
||||
]' && echo "✅ JWT_SECRET 已注入" || echo "⚠️ JWT_SECRET patch 失敗"
|
||||
fi
|
||||
if [ -n "${JWT_ALGORITHM}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/JWT_ALGORITHM","value":"'$(echo -n "${JWT_ALGORITHM}" | base64 -w 0)'"}
|
||||
]' && echo "✅ JWT_ALGORITHM 已注入" || echo "⚠️ JWT_ALGORITHM patch 失敗"
|
||||
fi
|
||||
|
||||
# WEBHOOK_HMAC_SECRET — Alertmanager webhook HMAC 簽章
|
||||
if [ -n "${WEBHOOK_HMAC_SECRET}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/WEBHOOK_HMAC_SECRET","value":"'$(echo -n "${WEBHOOK_HMAC_SECRET}" | base64 -w 0)'"}
|
||||
]' && echo "✅ WEBHOOK_HMAC_SECRET 已注入" || echo "⚠️ WEBHOOK_HMAC_SECRET patch 失敗"
|
||||
fi
|
||||
|
||||
# SENTRY_DSN — Sentry 錯誤追蹤(不是 auth token)
|
||||
if [ -n "${SENTRY_DSN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SENTRY_DSN","value":"'$(echo -n "${SENTRY_DSN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SENTRY_DSN 已注入" || echo "⚠️ SENTRY_DSN patch 失敗"
|
||||
fi
|
||||
|
||||
# CLAUDE_API_KEY — Claude 備援 LLM
|
||||
if [ -n "${CLAUDE_API_KEY}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/CLAUDE_API_KEY","value":"'$(echo -n "${CLAUDE_API_KEY}" | base64 -w 0)'"}
|
||||
]' && echo "✅ CLAUDE_API_KEY 已注入" || echo "⚠️ CLAUDE_API_KEY patch 失敗"
|
||||
fi
|
||||
|
||||
# GITEA_API_TOKEN — Gitea API Token(從 AWOOOI_GITEA_API_TOKEN 映射)
|
||||
if [ -n "${GITEA_API_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/GITEA_API_TOKEN","value":"'$(echo -n "${GITEA_API_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ GITEA_API_TOKEN 已注入" || echo "⚠️ GITEA_API_TOKEN patch 失敗"
|
||||
fi
|
||||
|
||||
# NEMOTRON_BOT_TOKEN / OPENCLAW_BOT_TOKEN — 多 Bot 架構
|
||||
if [ -n "${NEMOTRON_BOT_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/NEMOTRON_BOT_TOKEN","value":"'$(echo -n "${NEMOTRON_BOT_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ NEMOTRON_BOT_TOKEN 已注入" || echo "⚠️ NEMOTRON_BOT_TOKEN patch 失敗"
|
||||
fi
|
||||
if [ -n "${OPENCLAW_BOT_TOKEN}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/OPENCLAW_BOT_TOKEN","value":"'$(echo -n "${OPENCLAW_BOT_TOKEN}" | base64 -w 0)'"}
|
||||
]' && echo "✅ OPENCLAW_BOT_TOKEN 已注入" || echo "⚠️ OPENCLAW_BOT_TOKEN patch 失敗"
|
||||
fi
|
||||
|
||||
# SMTP_HOST / SRE_GROUP_CHAT_ID
|
||||
if [ -n "${SMTP_HOST}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SMTP_HOST","value":"'$(echo -n "${SMTP_HOST}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SMTP_HOST 已注入" || echo "⚠️ SMTP_HOST patch 失敗"
|
||||
fi
|
||||
if [ -n "${SRE_GROUP_CHAT_ID}" ]; then
|
||||
sudo kubectl patch secret awoooi-secrets -n awoooi-prod --type='json' -p='[
|
||||
{"op":"add","path":"/data/SRE_GROUP_CHAT_ID","value":"'$(echo -n "${SRE_GROUP_CHAT_ID}" | base64 -w 0)'"}
|
||||
]' && echo "✅ SRE_GROUP_CHAT_ID 已注入" || echo "⚠️ SRE_GROUP_CHAT_ID patch 失敗"
|
||||
fi
|
||||
|
||||
# 2026-04-06 Claude Code: Sprint 3 T2 — known_hosts Secret (Security Fix A1)
|
||||
# 替換 StrictHostKeyChecking=no,讓 SSH 修復路徑使用已知主機指紋
|
||||
ssh-keyscan -H 192.168.0.110 > /tmp/known_hosts_repair 2>/dev/null
|
||||
|
||||
Reference in New Issue
Block a user