# Fischer AgentKit — 密钥轮换 Runbook 本文档给出全部 11 个 secret slot(KTD-4 / R2a)的轮换操作流程。 所有轮换遵循「双密钥并行 → 切换 → 旧密钥退役」原则,避免服务中断。 ## 通用轮换原则 1. **零停机**:新密钥生效后再淘汰旧密钥,避免单点切换失败。 2. **审计先行**:轮换前记录当前密钥指纹(hash8),轮换后校验变更。 3. **回滚预案**:保留旧密钥值至少一个轮换周期,便于快速回滚。 4. **权限最小化**:轮换操作仅限归属角色,操作全程审计日志。 5. **后端无关**:以下步骤适用于 Sealed Secrets 与 External Secrets 两种后端, 差异处单独标注。 --- ## Slot 1:JWT 签名密钥(90 天) **影响**:所有签发的 JWT access/refresh token 失效,用户需重新登录。 **步骤**: ```bash # 1) 生成新密钥(32 字节随机串,base64) NEW_KEY=$(openssl rand -base64 32) # 2) 更新密钥后端 # Sealed Secrets: kubectl create secret generic agentkit-secrets-new --dry-run=client -o yaml \ --from-literal=jwt-signing-key="${NEW_KEY}" | \ kubeseal --controller-name=sealed-secrets --controller-namespace=kube-system \ --format yaml --merge-into agentkit-sealedsecret.yaml # External Secrets:在 Vault/SM 中更新 agentkit/jwt-signing-key # 3) 应用并等待同步 kubectl apply -f agentkit-sealedsecret.yaml -n agentkit kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 4) 验证 kubectl exec -n agentkit deploy/agentkit-agentkit -- \ python -c "import os; print('jwt key len:', len(os.environ['JWT_SIGNING_KEY']))" # 5) 用户重新登录(旧 token 失效) ``` **回滚**:保留旧密钥值,若新密钥异常,恢复 SealedSecret/ExternalSecret 并 restart。 --- ## Slot 2:API Key(180 天) **影响**:使用旧 API Key 的客户端调用失败。 **步骤**: ```bash # 1) 生成新 API Key NEW_KEY=$(openssl rand -hex 32) # 2) 更新密钥后端(同 Slot 1 步骤 2,key=api-key) # 3) 通知所有使用 API Key 的客户端更新(agentkit pair 重新生成) # 4) 应用并 restart kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 5) 验证:用新 key 调用 /api/v1/auth/me 或 SCIM 端点 ``` **回滚**:恢复旧 key 值。 --- ## Slot 3:DB 凭据 / DATABASE_URL(90 天) **影响**:数据库连接断开,需与 DBA 协同。 **步骤**: ```bash # 1) DBA 在 PostgreSQL 创建新密码(或新用户) psql -U postgres -c "ALTER USER agentkit WITH PASSWORD 'new-pg-pwd';" # 2) 更新 DATABASE_URL(含新密码) NEW_URL="postgresql+asyncpg://agentkit:new-pg-pwd@postgres:5432/agentkit" # 3) 更新密钥后端(key=database-url) # 4) restart pod(连接池重建) kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 5) 验证:触发一次 DB 操作(如 GET /api/v1/memory) # 6) DBA 回收旧密码(确认新连接正常后) ``` **注意**:PostgreSQL `ALTER USER` 立即生效,旧连接保持直到连接池重建。 建议在低峰期操作。 **回滚**:DBA 恢复旧密码 + 恢复 DATABASE_URL。 --- ## Slot 4:IDP 签名证书(365 天) **影响**:OIDC/SAML 登录校验失败。多 IDP 时仅影响轮换的 IdP。 **步骤**: ```bash # 1) 从 IdP 管理后台导出新签名证书 PEM # 2) 更新 JSON map(保留其他 IdP 证书不变) # 例如轮换 feishu 证书: NEW_CERTS='{"feishu":"-----BEGIN CERTIFICATE-----\n新证书\n-----END CERTIFICATE-----","azure_ad":"<原证书>"}' # 3) 更新密钥后端(key=idp-signing-certs) # 4) restart pod(证书热轮换不重启,但 Helm 部署需 restart 加载新 Secret) kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 5) 验证:通过该 IdP 发起一次 SSO 登录 ``` **回滚**:恢复旧证书 JSON map。 --- ## Slot 5:第三方 API Key / LLM providers(90 天) **影响**:对应 provider 的 LLM 调用失败。JSON map 结构,单 provider 轮换不影响其他。 **步骤**: ```bash # 1) 在 provider 控制台生成新 key(DashScope / DeepSeek / OpenAI / Anthropic) # 2) 更新 JSON map(保留其他 provider 不变) NEW_KEYS='{"dashscope":"sk-new1","deepseek":"sk-new2","openai":"sk-old"}' # 3) 更新密钥后端(key=third-party-api-keys) # 4) restart pod kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 5) 验证:调用对应 provider 的模型(如 agentkit chat 发一条测试消息) # 6) 在 provider 控制台撤销旧 key ``` **回滚**:恢复旧 key(需 provider 控制台未撤销旧 key,建议保留旧 key 一个周期)。 --- ## Slot 6:TLS 服务器证书(365 天) **影响**:Ingress TLS 终止证书过期,浏览器告警 / mTLS 客户端握手失败。 **步骤**: ```bash # 1) 签发新证书(cert-manager 自动续期,或手动从 CA 申请) # cert-manager 模式:证书到期前自动续期,无需手动操作。 # 2) 若手动:更新 kubernetes.io/tls 类型 Secret kubectl create secret tls agentkit-tls \ --cert=new.crt --key=new.key --dry-run=client -o yaml | \ kubectl apply -f - -n agentkit # 3) Ingress controller 自动感知新证书(无需 restart) # 4) 验证 echo | openssl s_client -connect agentkit.your-domain.com:443 -servername agentkit.your-domain.com 2>/dev/null | openssl x509 -noout -dates ``` **注意**:本 slot 不在 SealedSecret/ExternalSecret 的 encryptedData 内统一管理 (TLS Secret 类型为 `kubernetes.io/tls`,与普通 Secret 不同)。 SealedSecret 模板中登记仅用于清单追踪,实际由 cert-manager 或运维单独管理。 **回滚**:恢复旧证书 Secret。 --- ## Slot 7:mTLS 客户端证书(180 天) **影响**:与下游服务(KMS/HSM、内部 API)mTLS 握手失败。 **步骤**: ```bash # 1) 从内部 PKI 签发新客户端证书 + 私钥 + CA 证书 # 2) 更新密钥后端(key=mtls-client-cert,PEM 文本) NEW_PEM="$(cat client.crt client.key ca.crt)" # 3) 更新密钥后端 # 4) restart pod kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 5) 验证:触发一次 mTLS 调用(如 KMS 签名操作) ``` **回滚**:恢复旧 PEM。 --- ## Slot 8:KMS/HSM PKCS#11 PIN(365 天) **影响**:HSM 访问失败,密钥托管 / 签名 / 解密不可用。 **步骤**: ```bash # 1) HSM 管理员通过 HSM 管理工具轮换 PIN(具体命令依 HSM 型号) # 2) 更新密钥后端(key=kms-hsm-pin) NEW_PIN='' # 3) restart pod kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 4) 验证:触发一次 HSM 操作(如 PKCS#11 签名) ``` **注意**:HSM PIN 轮换需物理 / 管理员协同,建议提前预约维护窗口。 **回滚**:恢复旧 PIN(HSM 管理工具支持回滚 PIN)。 --- ## Slot 9:OTel exporter token(90 天) **影响**:遥测数据上报失败(trace/metrics 丢失)。服务本身不受影响。 **步骤**: ```bash # 1) 在 OTel collector / 可观测性平台生成新 token # 2) 更新密钥后端(key=otel-exporter-token,格式 'Authorization: Bearer ') NEW_TOKEN='Bearer new-otel-token' # 3) restart pod kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 4) 验证:在 collector 端确认收到新 trace/metrics ``` **回滚**:恢复旧 token。 --- ## Slot 10:Redis-PG 密码(90 天) **影响**:Redis / PostgreSQL 连接断开。需与基础设施层协同。 **步骤**: ```bash # 1) Redis 轮换密码 redis-cli -a '' CONFIG SET requirepass '' # 2) PostgreSQL 轮换密码(DBA) psql -U postgres -c "ALTER USER agentkit WITH PASSWORD 'new-pg-pwd';" # 3) 更新密钥后端(两个 key:redis-password + postgres-password) # 4) 更新 Redis 服务配置(若 Redis 由 docker-compose / StatefulSet 管理, # 需同步更新 requirepass 并 restart Redis) # 5) restart agentkit pod kubectl rollout restart deployment/agentkit-agentkit -n agentkit # 6) 验证 kubectl exec -n agentkit deploy/agentkit-agentkit -- \ python -c "import redis,os; redis.from_url(os.environ['REDIS_URL'],password=os.environ['REDIS_PASSWORD']).ping()" ``` **注意**:Redis `CONFIG SET requirepass` 立即生效,旧连接保持到断开。 建议低峰期操作,且 Redis 持久化配置(redis.conf)需同步更新,避免重启后失效。 **回滚**:恢复 Redis / PG 旧密码 + 恢复 Secret。 --- ## 紧急轮换(泄露响应) 发生密钥泄露时,立即按以下流程处置: 1. **隔离**:撤销泄露密钥(provider 控制台 / HSM / CA) 2. **轮换**:按上述对应 slot 步骤紧急轮换 3. **审计**:检索泄露密钥的使用日志,确认无异常调用 4. **通报**:通知安全团队 + 受影响用户 5. **复盘**:记录泄露原因,加固访问控制 紧急轮换不遵循「双密钥并行」原则,直接切换到新密钥并废弃旧密钥。