<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Secret-Management on Tarragon</title><link>https://tarrragon.github.io/blog/tags/secret-management/</link><description>Recent content in Secret-Management on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 18 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/secret-management/index.xml" rel="self" type="application/rss+xml"/><item><title>HashiCorp Vault</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/hashicorp-vault/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/hashicorp-vault/</guid><description>&lt;p>HashiCorp Vault 是 self-hosted 的 secret management 控制面、解決三個核心問題：&lt;em>static secret 集中保管&lt;/em>（KV engine、跟 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management&lt;/a> 卡同概念）、&lt;em>dynamic credential 即用即發即收&lt;/em>（database / cloud / SSH engine 在請求時動態建立短期憑證）、&lt;em>encryption-as-a-service 與內部 PKI&lt;/em>（transit engine 把加解密外包給 Vault、PKI engine 自簽憑證）。三件事在 cloud-native 替代品（&lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &amp;#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager&lt;/a> / &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &amp;#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager&lt;/a> / &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &amp;#43; Key &amp;#43; Certificate）、整合 Managed Identity &amp;#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault&lt;/a>）裡通常拆成不同 service、且綁單一雲。&lt;/p>
&lt;h2 id="服務定位">服務定位&lt;/h2>
&lt;p>Vault 的核心定位是 &lt;em>跨雲 + 跨環境 + 跨 secret 形態的單一 secret 控制面&lt;/em>。當組織同時跑 AWS + GCP + on-prem K8s、又需要 dynamic database credential + 內部 PKI + envelope encryption、用三個 cloud-native service 拼起來會出現 &lt;em>secret 治理鏈不連續&lt;/em>（AWS 的 secret 怎麼授權 GCP service 取用、on-prem app 怎麼拿短期 cloud credential、內部 CA 跟外部 ACM 怎麼分工）。Vault 把這層 &lt;em>統一抽象&lt;/em> — 應用端只跟 Vault 講話、Vault 後端接各雲 KMS / database / PKI。&lt;/p>
&lt;p>跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &amp;#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager&lt;/a> / &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &amp;#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager&lt;/a> 相比、Vault 多了：&lt;em>dynamic credential engine&lt;/em>（cloud-native 對應產品有限）、&lt;em>transit engine&lt;/em> 做 encryption-as-a-service、&lt;em>PKI engine&lt;/em> 自簽內部憑證、&lt;em>跨雲統一介面&lt;/em>。代價是 &lt;em>自管運維&lt;/em>（HA cluster、auto-unseal、replication、upgrade）— 跟自管 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/keycloak/" data-link-title="Keycloak" data-link-desc="Open source self-hosted Identity Provider、Red Hat 主導、Realm-based multi-tenancy、適合資料主權與自訂 flow 需求">Keycloak&lt;/a> 的取捨同類。HCP Vault（HashiCorp Cloud Platform）是 HashiCorp 託管版、把運維交還、但綁 HashiCorp。&lt;/p></description><content:encoded><![CDATA[<p>HashiCorp Vault 是 self-hosted 的 secret management 控制面、解決三個核心問題：<em>static secret 集中保管</em>（KV engine、跟 <a href="/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management</a> 卡同概念）、<em>dynamic credential 即用即發即收</em>（database / cloud / SSH engine 在請求時動態建立短期憑證）、<em>encryption-as-a-service 與內部 PKI</em>（transit engine 把加解密外包給 Vault、PKI engine 自簽憑證）。三件事在 cloud-native 替代品（<a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a> / <a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a>）裡通常拆成不同 service、且綁單一雲。</p>
<h2 id="服務定位">服務定位</h2>
<p>Vault 的核心定位是 <em>跨雲 + 跨環境 + 跨 secret 形態的單一 secret 控制面</em>。當組織同時跑 AWS + GCP + on-prem K8s、又需要 dynamic database credential + 內部 PKI + envelope encryption、用三個 cloud-native service 拼起來會出現 <em>secret 治理鏈不連續</em>（AWS 的 secret 怎麼授權 GCP service 取用、on-prem app 怎麼拿短期 cloud credential、內部 CA 跟外部 ACM 怎麼分工）。Vault 把這層 <em>統一抽象</em> — 應用端只跟 Vault 講話、Vault 後端接各雲 KMS / database / PKI。</p>
<p>跟 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a> 相比、Vault 多了：<em>dynamic credential engine</em>（cloud-native 對應產品有限）、<em>transit engine</em> 做 encryption-as-a-service、<em>PKI engine</em> 自簽內部憑證、<em>跨雲統一介面</em>。代價是 <em>自管運維</em>（HA cluster、auto-unseal、replication、upgrade）— 跟自管 <a href="/blog/backend/07-security-data-protection/vendors/keycloak/" data-link-title="Keycloak" data-link-desc="Open source self-hosted Identity Provider、Red Hat 主導、Realm-based multi-tenancy、適合資料主權與自訂 flow 需求">Keycloak</a> 的取捨同類。HCP Vault（HashiCorp Cloud Platform）是 HashiCorp 託管版、把運維交還、但綁 HashiCorp。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本頁、讀者能判斷：</p>
<ol>
<li>哪些 secret 適合 Vault（dynamic credential、跨雲、PKI、encryption-as-a-service）、哪些直接用雲端 native service 即可</li>
<li>Vault deployment 的最低安全需求（auto-unseal、HA、audit device、policy、replication）</li>
<li>Vault 自己出事時的降級路徑（seal storm、root token 復原、audit log gap）</li>
<li>何時用 Vault、何時走 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">Secrets Manager</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a> / <a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a> 的取捨</li>
</ol>
<h2 id="最短判讀路徑">最短判讀路徑</h2>
<p>判斷 Vault deployment 是否健康、最少看五件事：</p>
<ul>
<li><strong>誰能做什麼</strong>：root token 是否已 revoke、policy 是否走 path-based least privilege、admin 是否走 OIDC / <a href="/blog/backend/07-security-data-protection/vendors/aws-iam/" data-link-title="AWS IAM" data-link-desc="AWS cloud resource permission engine、Role / Policy / STS、跨帳號信任邊界與 OIDC federation 的核心">AWS IAM auth</a> 而不是 token、break-glass token 是否離線存</li>
<li><strong>Auth method 收緊</strong>：AppRole / Kubernetes / OIDC / JWT auth 哪些開、role 對應的 policy 是不是過寬、TTL 是否短、<code>bound_*</code> 條件是否鎖（namespace / audience / subject）</li>
<li><strong>Secret engine 設定</strong>：KV v2 開 versioning？dynamic engine（database / aws / pki）lease TTL 多久、max TTL 限制是什麼、revocation 是否驗證生效</li>
<li><strong>Seal / unseal 治理</strong>：是否走 auto-unseal（KMS-backed）、recovery key 持有者跟 Shamir threshold、replication 跟 DR cluster 是否同步</li>
<li><strong>證據是否可回查</strong>：audit device（file / syslog / socket）是否多 channel、是否同步到 SIEM、replay 攻擊防護是否開（HMAC + nonce）</li>
</ul>
<p>五件事任一缺失、就是 <a href="/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">Audit Log</a> 與 <a href="/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management</a> 邊界的待補項目。</p>
<h2 id="日常操作與決策形狀">日常操作與決策形狀</h2>
<p><strong>Auth method 設計</strong>：AppRole 適合不在雲端 metadata 內的 workload（on-prem、CI runner）但 <em>secret_id</em> 本身要妥善保管；Kubernetes auth 適合 K8s 內 workload、用 ServiceAccount token + projected token；<a href="/blog/backend/07-security-data-protection/vendors/aws-iam/" data-link-title="AWS IAM" data-link-desc="AWS cloud resource permission engine、Role / Policy / STS、跨帳號信任邊界與 OIDC federation 的核心">AWS IAM auth</a> 適合 AWS 內 workload、走 STS 簽名驗證、不需要存 secret；OIDC / JWT 適合 human admin + CI（GitHub Actions / GitLab CI 走 OIDC token）。每個 auth method 對應 <em>一組 role</em>、role 綁 <em>policy</em> 跟 <em>TTL</em>。</p>
<p><strong>Secret engine 分層</strong>：KV v2（static secret + version history）作為基線；dynamic database engine（PostgreSQL / MySQL / MongoDB）發短期 DB user、<code>max_ttl = 1h</code> 級別、過期 Vault 自動 revoke；AWS / Azure / GCP secret engine 對 cloud account 發短期 STS credential / service account key；PKI engine 自簽憑證、跟 <a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a> 整合做 K8s workload mTLS；transit engine 做 envelope encryption — app 把資料丟給 Vault 加密、key 不離 Vault。</p>
<p><strong>Policy（path-based）</strong>：Vault policy 是 <em>path + capabilities</em>（create / read / update / delete / list / sudo）的 mapping。常見錯配：給 <code>secret/*</code> read 等於整個組織所有 secret 都看得到、應該用 <code>secret/data/{team}/*</code> 之類前綴限定；admin policy 不要給 <code>sudo</code> 太寬、policy 變更走 PR review + CI apply。</p>
<p><strong>Rotation 跟 lease 治理</strong>：static secret（KV）的 rotation 是 <em>app 自己做</em>（拿新 secret 後手動 update）；dynamic secret 是 <em>Vault 控制 lease 生命週期</em>、app 只要在 TTL 內續租即可。對應 <a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a>：static secret 的 rotation 必須有 <em>scope map</em> — 哪些 service 用了同一把 secret、哪個 service 支援零停機 rotation、誰是 last to be rotated。沒這份 map 就會發生「rotate 後某個被遺忘的 cron job 認證失敗、整個下游崩」。</p>
<p><strong>Seal / unseal 設計</strong>：Vault 啟動時 sealed、必須 unseal 才能服務。Shamir secret sharing 是預設（5 key holders、3 threshold）— 任何重啟需要找齊 3 個人合 unseal、production 場景幾乎都該換 auto-unseal（用 <a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">GCP KMS</a> / <a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a> 當 master key custodian）。代價是 <em>把 master key 託給雲廠</em> — 不接受的組織保留 Shamir + 嚴格 key holder rotation。</p>
<p><strong>Audit device 是 <em>必開</em></strong>：Vault 預設不開 audit、要手動 enable（<code>vault audit enable file path=/var/log/vault_audit.log</code>）。沒 audit device 在 production = 事故時 <em>連 token 被誰用過都查不到</em>。建議多 channel（file + syslog + 推到外部 SIEM）— 單一 channel 失效（disk full、socket broken）Vault 會拒絕請求、影響 availability、所以多 channel 是必要冗餘。</p>
<p><strong>Break-glass 與 root token</strong>：初始化時產生的 root token 應該 <em>用完立刻 revoke</em>、改用 admin policy + OIDC auth。break-glass scenario 用 <em>recovery key 重新發 root token</em>、recovery key 走 Shamir 多人持有 + 離線存。</p>
<h2 id="核心取捨表">核心取捨表</h2>
<table>
  <thead>
      <tr>
          <th>取捨維度</th>
          <th>Vault (self-hosted)</th>
          <th>HCP Vault</th>
          <th>AWS Secrets Manager</th>
          <th>Google Secret Manager</th>
          <th>Azure Key Vault</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>部署模型</td>
          <td>自管 cluster（HA + replication）</td>
          <td>HashiCorp 託管</td>
          <td>AWS managed</td>
          <td>GCP managed</td>
          <td>Azure managed</td>
      </tr>
      <tr>
          <td>跨雲</td>
          <td>強 — 同一介面跨 AWS / GCP / Azure / on-prem</td>
          <td>強</td>
          <td>弱 — 綁 AWS</td>
          <td>弱 — 綁 GCP</td>
          <td>弱 — 綁 Azure</td>
      </tr>
      <tr>
          <td>Dynamic credential</td>
          <td>DB / cloud / SSH engine 完整</td>
          <td>同 OSS</td>
          <td>無 — 僅 RDS / Redshift static rotation Lambda</td>
          <td>無 — 自寫 Cloud Function；secret-less 走 WIF</td>
          <td>無 — 純 static；secret-less 走 Managed Identity</td>
      </tr>
      <tr>
          <td>PKI / transit</td>
          <td>內建 PKI engine + transit engine</td>
          <td>同 OSS</td>
          <td>走 <a href="/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">AWS ACM</a> + <a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">KMS</a></td>
          <td>走 cloud KMS + Certificate Authority Service</td>
          <td>走 <a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a> cert 功能</td>
      </tr>
      <tr>
          <td>運維成本</td>
          <td>高 — HA、upgrade、replication、cert 自己顧</td>
          <td>低 — HashiCorp 顧</td>
          <td>低</td>
          <td>低</td>
          <td>低</td>
      </tr>
      <tr>
          <td>第三方信任成本</td>
          <td>低 — 自管</td>
          <td>中 — HashiCorp 控制面</td>
          <td>中 — AWS 控制面</td>
          <td>中 — GCP 控制面</td>
          <td>中 — Microsoft 控制面</td>
      </tr>
      <tr>
          <td>適合場景</td>
          <td>跨雲、需要 dynamic credential、內部 PKI、預算允許</td>
          <td>想要 Vault 能力但不想自管</td>
          <td>AWS-heavy + 簡單 static secret</td>
          <td>GCP-heavy + Workload Identity 已主導</td>
          <td>Azure-heavy + Managed Identity 已主導</td>
      </tr>
      <tr>
          <td>退場成本</td>
          <td>中 — 自己掌握資料、但 dynamic engine 接線多</td>
          <td>中</td>
          <td>低</td>
          <td>低</td>
          <td>低</td>
      </tr>
  </tbody>
</table>
<p>選 Vault 的核心訴求：<em>跨雲 + dynamic credential + 內部 PKI + transit encryption 至少滿足兩項</em>、且能投入 SRE 量能跑 HA cluster、有 SIEM 接 audit log、能接受 self-hosted 的 upgrade / cert / DB 運維成本。單純需要 AWS-only static secret rotation、直接用 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">Secrets Manager</a> 更便宜更簡單。</p>
<h2 id="進階主題">進階主題</h2>
<p><strong>Dynamic credential 的 lease 生命週期治理</strong>：dynamic engine 發出的 credential 都帶 lease ID、Vault 在 TTL 到期時自動 revoke（database engine 真的會 DROP USER、cloud engine 真的會 DeleteAccessKey）。設計時要算清楚 <em>app 連線池的 connection lifetime</em> — DB connection 持續用同一組 credential、credential lease 過期但 connection 還在會出現 <em>staled credential</em> 問題。常見作法：lease TTL &gt; connection idle timeout * 2、加 lease renewal mechanism（app 在 TTL 50% 時主動 renew）。</p>
<p><strong>Transit engine（encryption-as-a-service）</strong>：app 不持 encryption key、把 plaintext 丟給 Vault <code>encrypt</code> API、拿 ciphertext 回來；解密時把 ciphertext 給 Vault <code>decrypt</code> API。Key 完全不離 Vault、所有 cryptographic operation 在 Vault 內、app 只需要 <em>encrypt / decrypt capability</em>。對應 <a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Storm-0558 signing key chain</a> 的對照啟示：key 不能 export 是減 blast radius 的關鍵設計 — transit 把這個原則內建。</p>
<p><strong>PKI engine + cert-manager 整合</strong>：Vault PKI engine 可以當內部 root CA + intermediate CA、issue 短期 cert（hours-level）給 K8s workload；<a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a> 用 Vault PKI issuer 自動更新 cert。比起手動跑 OpenSSL CA、Vault PKI 的優勢是 <em>cert lifecycle 進 Vault audit</em>、跟 secret rotation 用同一套 evidence chain（呼應 <a href="/blog/backend/07-security-data-protection/credential-rotation-scoped-evidence/" data-link-title="7.27 Credential Rotation with Scoped Evidence 實作示範" data-link-desc="以 webhook/API credential 輪替示範 scope map、證據欄位與回退窗口如何一起設計。">credential rotation scoped evidence</a>）。</p>
<p><strong>Namespace（Enterprise）跟 multi-tenancy</strong>：Enterprise 版 namespace 是 <em>tenant 邏輯隔離</em>、每個 namespace 有自己的 auth method、policy、secret engine。OSS 版沒 namespace — 多團隊共用 Vault 要靠 path 命名規約 + policy prefix 拼隔離、邊界較鬆。大組織通常需要 namespace 才能避免單一 admin 跨 team 越界。</p>
<p><strong>Replication（Enterprise）</strong>：Performance Replication（主從 + 多 region active）跟 DR Replication（純 standby）是兩個獨立功能。production HA 通常需要 <em>同 region 的 cluster + 跨 region 的 DR replication</em>、recovery key 跟 unseal 機制要跨 cluster 一致。</p>
<h2 id="排錯與失敗快速判讀">排錯與失敗快速判讀</h2>
<ul>
<li><strong>Audit device 沒開</strong>：production 啟動時忘了 enable audit、事故發生時無 forensic data — 啟動 checklist 必含「enable audit before serving traffic」、SRE runbook 用 health check 驗</li>
<li><strong>Policy 過寬</strong>：給整個 <code>secret/*</code> read、單一 token 等於拿到全公司 secret — 用 path prefix 限定到 <code>{team}/{env}/*</code>、policy review 走 PR</li>
<li><strong>Dynamic credential lease 太長 / 沒 max_ttl</strong>：DB user 跑了一週還沒收、攻擊者只要拿到一次就長期可用 — 設定 lease TTL = 1h、max_ttl = 24h</li>
<li><strong>Auto-unseal KMS access 沒監控</strong>：<a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">GCP KMS</a> 的 Vault auto-unseal key 沒 alert 異常使用 — KMS 端設 alert（GetKeyValue / Decrypt 突增）</li>
<li><strong>Replication lag 沒 alert</strong>：Performance / DR replication 落後幾分鐘到幾小時、failover 時拿到 stale state — Prometheus 監控 <code>vault.replication.*</code> metric</li>
<li><strong>Root token 未 revoke</strong>：初始化時的 root token 還在用、policy / audit / OIDC 全 bypass — 初始化 checklist 強制 revoke、CI 跑 <code>vault token lookup</code> 驗證 root 不可用</li>
<li><strong>Sealed 後 unseal key 找不到人</strong>：production cluster 緊急 restart、Shamir threshold 3 但有 1 個 key holder 在度假 — production 必須 auto-unseal、recovery key 走 <a href="/blog/backend/07-security-data-protection/identity-access-boundary/" data-link-title="7.2 身分與授權邊界" data-link-desc="以問題驅動方式整理身分、授權、會話與供應商身分鏈">break-glass</a> 流程</li>
</ul>
<h2 id="何時改走其他服務">何時改走其他服務</h2>
<table>
  <thead>
      <tr>
          <th>需求形狀</th>
          <th>改走</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>AWS-only + 簡單 static secret</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a></td>
      </tr>
      <tr>
          <td>GCP-only + 已用 Workload Identity</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a></td>
      </tr>
      <tr>
          <td>Azure-only + 已用 Managed Identity</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a></td>
      </tr>
      <tr>
          <td>大型 cryptographic / HSM 需求</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/cloudhsm/" data-link-title="AWS CloudHSM" data-link-desc="Single-tenant dedicated HSM（FIPS 140-2 Level 3）、AWS 不持 Crypto User credential、合規 &#43; 資料主權場景的 key custody">CloudHSM</a>（FIPS 140-2 Level 3、Vault auto-unseal 後端）</td>
      </tr>
      <tr>
          <td>公開憑證 PKI（serving cert）</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">AWS ACM</a> / <a href="/blog/backend/07-security-data-protection/vendors/letsencrypt/" data-link-title="Let&#39;s Encrypt" data-link-desc="免費 &#43; 自動化的公共 ACME CA、90 天 TTL 強制自動化、跨雲跨平台 public TLS cert 的事實基礎">Let&rsquo;s Encrypt</a></td>
      </tr>
      <tr>
          <td>K8s workload cert 自動化</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a>（可用 Vault 當 issuer）</td>
      </tr>
      <tr>
          <td>跨服務 workload identity (SPIFFE)</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/spire/" data-link-title="SPIRE" data-link-desc="SPIFFE Runtime Environment、attested workload identity、short-lived SVID &#43; Trust Bundle、跨組織 federation">SPIRE</a></td>
      </tr>
      <tr>
          <td>Secret 全公司 rotation 證據鏈</td>
          <td><a href="/blog/backend/07-security-data-protection/credential-rotation-scoped-evidence/" data-link-title="7.27 Credential Rotation with Scoped Evidence 實作示範" data-link-desc="以 webhook/API credential 輪替示範 scope map、證據欄位與回退窗口如何一起設計。">7.5 Credential Rotation Scoped Evidence</a></td>
      </tr>
  </tbody>
</table>
<h2 id="不在本頁內的主題">不在本頁內的主題</h2>
<ul>
<li>Vault 完整 API reference 跟 CLI 詳盡用法</li>
<li>每個 secret engine 的內部實作細節（DB connection pool、cloud SDK 呼叫順序）</li>
<li>Enterprise 各 license tier 的功能對照</li>
<li>Terraform / Ansible 跟 Vault 整合的完整步驟</li>
<li>各 auth method 的 OIDC / SAML provider 設定教學</li>
</ul>
<h2 id="案例回寫">案例回寫</h2>
<p>Vault 在 07 案例庫沒有直接 vendor-level 事件、以下案例採對照引用：</p>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>跟 Vault 的關係（對照）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a></td>
          <td>static secret rotation 必須有 scope map — Vault KV 多 service 共用同一把 secret 時、rotation 要分批 + 雙軌驗證窗口、不能一次 push 全域更新</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Microsoft Storm-0558 Signing Key Chain (red-team)</a></td>
          <td>transit engine 的設計啟示 — key 不離保護邊界、即使被讀也搬不走、跟 HSM-bound 同 mindset</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/supply-chain/circleci-2023-secrets-rotation/" data-link-title="7.R7.2.3 CircleCI 2023：CI secrets 輪替壓力" data-link-desc="工程端點入侵後，CI 平台 secrets 如何成為高風險擴散點">CircleCI 2023 Secrets Rotation (red-team)</a></td>
          <td>CI 平台 secret 集中化的 blast radius — Vault AppRole secret_id 散落在 CI runner 時、CI 出事 = 大量 AppRole credential 一次外洩、需 scope tag + 優先級 rotation</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/okta-support-system-incident-2023/" data-link-title="7.C5 Okta：2023 Support System 事件" data-link-desc="支援系統憑證風險如何擴散到客戶租戶的案例。">Okta Support System 2023</a></td>
          <td>對照啟示 — Vault 自己的 support / debug tooling（root token、recovery key）也是 secret leak vector、HAR 級別的事件可發生在任何 admin console</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>上游：<a href="/blog/backend/07-security-data-protection/secrets-and-machine-credential-governance/" data-link-title="7.6 秘密管理與機器憑證治理" data-link-desc="以問題驅動方式整理 secret、token、key 與機器身份治理">7.6 秘密管理與機器憑證治理</a>、<a href="/blog/backend/07-security-data-protection/detection-coverage-and-signal-governance/" data-link-title="7.13 偵測覆蓋率與訊號治理" data-link-desc="定義偵測覆蓋、訊號品質與誤報成本的治理問題">7.13 偵測覆蓋率與訊號治理</a></li>
<li>平行：<a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a>、<a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a>、<a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a></li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Google Cloud KMS</a>（Vault auto-unseal master key custodian）</li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a>（用 Vault PKI engine 作為 K8s workload cert issuer）</li>
<li>跨模組：<a href="/blog/backend/08-incident-response/vendors/" data-link-title="事故處理 Vendor 清單" data-link-desc="規劃 on-call、incident response、status page 與 postmortem 工具的服務頁撰寫順序與判準">8 事故處理 vendor 清單</a>（Vault 事件如何 routing 進 IR 流程）</li>
<li>官方：<a href="https://developer.hashicorp.com/vault/docs">Vault Documentation</a></li>
</ul>
]]></content:encoded></item><item><title>AWS Secrets Manager</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/</guid><description>&lt;p>AWS Secrets Manager 是 AWS 原生的 &lt;em>static secret 集中保管 service&lt;/em>、核心能力是把 secret 用 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &amp;#43; Grant 雙軌授權">KMS&lt;/a> 加密儲存、加上 &lt;em>built-in rotation Lambda&lt;/em>（針對 RDS / Redshift / DocumentDB）跟 &lt;em>Resource Policy + IAM Policy 雙層 grant&lt;/em>、把 secret lifecycle 鎖在 AWS account / IAM 邊界內。設計取捨跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault&lt;/a> 不同 — Secrets Manager 不做 dynamic credential、不做 transit encryption、不做內部 PKI、只把 &lt;em>static secret + AWS native DB rotation&lt;/em> 這條路徑做到極致。&lt;/p>
&lt;h2 id="服務定位">服務定位&lt;/h2>
&lt;p>Secrets Manager 的定位是 &lt;em>AWS-only workload 的 static secret 控制面&lt;/em>、跟 &lt;a href="https://docs.aws.amazon.com/systems-manager/">SSM Parameter Store&lt;/a> SecureString 在 &lt;em>存 secret&lt;/em> 這層功能重疊、但設計目的不同。Parameter Store 是 &lt;em>parameter 管理&lt;/em>（free tier、advanced parameter 每 10000 個約 $0.05、KMS 加密但無 staging label 與 rotation Lambda）；Secrets Manager 是 &lt;em>secret 管理&lt;/em>（每個 secret per month $0.40 + API call、有 staging label / rotation Lambda / Resource Policy / Cross-Region Replica）。價差 8 倍以上、選擇基準在 &lt;em>是否需要 rotation 跟 cross-account sharing&lt;/em>。&lt;/p>
&lt;p>跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault&lt;/a> 比、Secrets Manager 是 &lt;em>單一雲、簡單、低運維&lt;/em>、Vault 是 &lt;em>跨雲、dynamic credential、高表達力&lt;/em>。AWS-only 組織用 Vault 等於多扛一個 HA cluster 運維成本只為了拿 KV engine 跟 RDS rotation、ROI 不划算；反向跨雲組織用 Secrets Manager 等於每個雲都自己一套 secret store、治理鏈會斷。跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &amp;#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager&lt;/a> / &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &amp;#43; Key &amp;#43; Certificate）、整合 Managed Identity &amp;#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault&lt;/a> 比、設計理念類似（雲廠 managed、KMS 加密、IAM 授權）但 rotation 機制各家不同 — Secrets Manager 用 built-in Lambda 四階段 flow、GSM 用 Pub/Sub event 觸發自寫 Cloud Function、Azure 用 Key Vault rotation policy + Event Grid。&lt;/p></description><content:encoded><![CDATA[<p>AWS Secrets Manager 是 AWS 原生的 <em>static secret 集中保管 service</em>、核心能力是把 secret 用 <a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">KMS</a> 加密儲存、加上 <em>built-in rotation Lambda</em>（針對 RDS / Redshift / DocumentDB）跟 <em>Resource Policy + IAM Policy 雙層 grant</em>、把 secret lifecycle 鎖在 AWS account / IAM 邊界內。設計取捨跟 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a> 不同 — Secrets Manager 不做 dynamic credential、不做 transit encryption、不做內部 PKI、只把 <em>static secret + AWS native DB rotation</em> 這條路徑做到極致。</p>
<h2 id="服務定位">服務定位</h2>
<p>Secrets Manager 的定位是 <em>AWS-only workload 的 static secret 控制面</em>、跟 <a href="https://docs.aws.amazon.com/systems-manager/">SSM Parameter Store</a> SecureString 在 <em>存 secret</em> 這層功能重疊、但設計目的不同。Parameter Store 是 <em>parameter 管理</em>（free tier、advanced parameter 每 10000 個約 $0.05、KMS 加密但無 staging label 與 rotation Lambda）；Secrets Manager 是 <em>secret 管理</em>（每個 secret per month $0.40 + API call、有 staging label / rotation Lambda / Resource Policy / Cross-Region Replica）。價差 8 倍以上、選擇基準在 <em>是否需要 rotation 跟 cross-account sharing</em>。</p>
<p>跟 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a> 比、Secrets Manager 是 <em>單一雲、簡單、低運維</em>、Vault 是 <em>跨雲、dynamic credential、高表達力</em>。AWS-only 組織用 Vault 等於多扛一個 HA cluster 運維成本只為了拿 KV engine 跟 RDS rotation、ROI 不划算；反向跨雲組織用 Secrets Manager 等於每個雲都自己一套 secret store、治理鏈會斷。跟 <a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a> / <a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a> 比、設計理念類似（雲廠 managed、KMS 加密、IAM 授權）但 rotation 機制各家不同 — Secrets Manager 用 built-in Lambda 四階段 flow、GSM 用 Pub/Sub event 觸發自寫 Cloud Function、Azure 用 Key Vault rotation policy + Event Grid。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本頁、讀者能判斷：</p>
<ol>
<li>哪些 secret 用 Secrets Manager、哪些可以下放到 Parameter Store、哪些該走 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a> 的 dynamic credential</li>
<li>Secrets Manager 的 <em>雙層 grant 模型</em>（Resource Policy + IAM Policy）跟 KMS encryption key custody 怎麼配</li>
<li>Built-in rotation 跟 Custom Rotation Lambda 的設計邊界、staging label 在 zero-downtime rotation 內的角色</li>
<li>何時 Secrets Manager 已經不夠用、要往 Vault / 跨雲 broker 走</li>
</ol>
<h2 id="最短判讀路徑">最短判讀路徑</h2>
<p>判斷一個 Secrets Manager 部署是否健康、最少看四件事：</p>
<ul>
<li><strong>誰能 GetSecretValue</strong>：IAM Policy 那邊是不是用 <code>secretsmanager:GetSecretValue</code> 限定到 <em>特定 secret ARN</em>（不是 <code>*</code>）、Resource Policy 是不是只允許特定 principal（不是 <code>Principal: *</code>）、跨帳號 share 有沒有用 ABAC tag 限縮</li>
<li><strong>KMS key custody</strong>：secret 用 <em>AWS-managed key</em>（<code>aws/secretsmanager</code>）還是 <em>customer-managed key</em>（CMK）— production 應該全部 CMK、key policy 限定 only Secrets Manager service principal 可用、KMS key 持有者跟 secret 持有者要分離</li>
<li><strong>Rotation 設定</strong>：rotation 開了沒、rotation interval 多久、Lambda 過去執行 success rate、staging label 在 rotation 過程中是否依序 promote（AWSPENDING → AWSCURRENT → AWSPREVIOUS）</li>
<li><strong>CloudTrail data event</strong>：<code>GetSecretValue</code> 是 <em>Data event</em>、預設不記、要手動開 data event logging — 沒開等於事故時看不到 <em>誰拿了 secret</em>、只看得到 management API（CreateSecret / UpdateSecret）</li>
</ul>
<p>四件事任一缺失、就是 <a href="/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management</a> 跟 <a href="/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">Audit Log</a> 邊界的待補項目。</p>
<h2 id="日常操作與決策形狀">日常操作與決策形狀</h2>
<p><strong>Resource Policy + IAM Policy 雙層 grant</strong>：Secrets Manager 跟 S3 bucket policy 同模型 — IAM Policy 控制 <em>principal 端能做什麼</em>、Resource Policy 控制 <em>secret 端允許誰來</em>、兩者要 <em>都同意</em> 才放行。常見錯配：Resource Policy 寫 <code>Principal: &quot;*&quot;</code> 加 <code>aws:SourceAccount</code> condition 想做跨帳號 share、但 condition 漏寫或寫錯就變成公開可讀。跨帳號 share 一定要明確列 <code>Principal: arn:aws:iam::123456789012:role/AppRole</code>、不要靠 wildcard + condition 拼隔離。</p>
<p><strong>IAM Policy 細粒度授權</strong>：<code>secretsmanager:GetSecretValue</code> 該限定到 <em>specific secret ARN</em>（不是 <code>*</code>）、配合 ABAC tag condition（<code>secretsmanager:ResourceTag/team = payments</code>）限縮 blast radius。對應 <a href="/blog/backend/07-security-data-protection/red-team/cases/supply-chain/circleci-2023-secrets-rotation/" data-link-title="7.R7.2.3 CircleCI 2023：CI secrets 輪替壓力" data-link-desc="工程端點入侵後，CI 平台 secrets 如何成為高風險擴散點">CircleCI 2023 Secrets Rotation</a> — CI 出事時要能依 tag 快速列出 <em>CI runner 可拿的所有 secret</em>、沒這套 tag 就只能盲目 rotate 全部。</p>
<p><strong>KMS encryption key 選 CMK 不是 default</strong>：每個 secret 用一把 KMS key 加密、預設用 AWS-managed key <code>aws/secretsmanager</code>、production 應該換 customer-managed key（CMK）。差別在 <em>key policy 是不是自己控</em> — AWS-managed key 的 policy 同 account 任何 service 可呼叫、CMK 的 key policy 可以鎖到 only Secrets Manager service principal 加 only specific role 可 Decrypt。對應 <a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Storm-0558</a> 的對照啟示：<em>key 的 blast radius 來自 key policy</em>、用 CMK 把 policy 寫窄是減 blast radius 的關鍵動作。</p>
<p><strong>Built-in Rotation Lambda 只限 AWS native DB</strong>：Secrets Manager 內建 rotation template 涵蓋 RDS（PostgreSQL / MySQL / MariaDB / Oracle / SQL Server）/ Aurora / Redshift / DocumentDB — 拿 AWS 提供的 Lambda template、設定 rotation interval（最短 1 天、最長 365 天）、Secrets Manager 自動排程觸發。其他 DB（self-hosted PostgreSQL、MongoDB Atlas、Snowflake）或 API key 要寫 <em>Custom Rotation Lambda</em>、走 4-step state machine：<code>createSecret</code>（產新 credential 存為 AWSPENDING）、<code>setSecret</code>（把新 credential 寫到 target system）、<code>testSecret</code>（用新 credential 驗證可連）、<code>finishSecret</code>（promote AWSPENDING → AWSCURRENT）。Lambda 任一步失敗 Secrets Manager 會 rollback、舊 credential 不受影響。</p>
<p><strong>Staging Label（AWSCURRENT / AWSPENDING / AWSPREVIOUS）</strong>：staging label 是 <em>指向 version 的 pointer</em>、app 一律用 <code>GetSecretValue</code> 不帶 VersionStage 拿 AWSCURRENT、rotation 過程中 Secrets Manager 先把新 credential 標 AWSPENDING、testSecret 過後 promote 到 AWSCURRENT、舊的降到 AWSPREVIOUS。設計初衷是 <em>zero-downtime rotation</em> — 但 <em>只有 app 端支援 AWSPREVIOUS fallback</em> 期間才有意義：rotation 完成瞬間有些 app instance 還拿著舊 credential，target system 應該同時接受 AWSCURRENT 跟 AWSPREVIOUS（DB rotation template 會在 setSecret 階段保留舊 user 一段時間）。對應 <a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a>：scope map 沒做、AWSPREVIOUS 窗口期太短、長尾 batch job 拿到舊 credential 就掛。</p>
<p><strong>Cross-Region Replica</strong>：multi-region app 把 secret replicate 到其他 region、replica 在 replica region 有獨立 ARN、KMS key 跟 rotation 都要在 replica region 各自配（不能跨 region 共用 KMS key）。replica 是 <em>讀副本</em>、寫只能在 primary region、rotation 觸發後新 version 自動 sync 到 replica（有秒級延遲）。failover 時 app 直接讀 replica region ARN、不需要 cross-region call。</p>
<p><strong>Cross-Account Sharing</strong>：跨帳號 share secret 走 Resource Policy + 對方帳號 IAM Policy 雙向授權 — Resource Policy 列對方 account 的具體 role ARN、對方 role 的 IAM Policy 加 <code>GetSecretValue</code> 對應 ARN。KMS key 也要跨帳號授權（KMS key policy 加對方 role 的 Decrypt 權限）— 漏了 KMS 授權會出現 <em>GetSecretValue 成功但 Decrypt 失敗</em> 的詭異錯誤。</p>
<h2 id="核心取捨表">核心取捨表</h2>
<table>
  <thead>
      <tr>
          <th>取捨維度</th>
          <th>AWS Secrets Manager</th>
          <th>SSM Parameter Store SecureString</th>
          <th><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a></th>
          <th><a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a></th>
          <th><a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a></th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>部署模型</td>
          <td>AWS managed</td>
          <td>AWS managed</td>
          <td>自管 cluster</td>
          <td>GCP managed</td>
          <td>Azure managed</td>
      </tr>
      <tr>
          <td>跨雲</td>
          <td>弱 — 綁 AWS</td>
          <td>弱 — 綁 AWS</td>
          <td>強</td>
          <td>弱 — 綁 GCP</td>
          <td>弱 — 綁 Azure</td>
      </tr>
      <tr>
          <td>每月每 secret 成本</td>
          <td>~$0.40 + API call</td>
          <td>free / advanced ~$0.05/10k</td>
          <td>self-hosted 成本</td>
          <td>~$0.06 + API call</td>
          <td>~$0.03 + operation</td>
      </tr>
      <tr>
          <td>Built-in rotation</td>
          <td>RDS / Redshift / DocumentDB 內建 Lambda</td>
          <td>無</td>
          <td>dynamic engine 自動發短期 credential</td>
          <td>無 built-in</td>
          <td>Key Vault rotation policy（key 為主）</td>
      </tr>
      <tr>
          <td>Staging label</td>
          <td>AWSCURRENT / AWSPENDING / AWSPREVIOUS</td>
          <td>無、用 version number</td>
          <td>KV v2 用 version</td>
          <td>version 機制</td>
          <td>version 機制</td>
      </tr>
      <tr>
          <td>Cross-account share</td>
          <td>Resource Policy + IAM</td>
          <td>不支援（同 account only）</td>
          <td>Vault namespace + policy</td>
          <td>IAM cross-project</td>
          <td>RBAC cross-tenant</td>
      </tr>
      <tr>
          <td>Dynamic credential</td>
          <td>無（rotation Lambda 是 static 換 static）</td>
          <td>無</td>
          <td>有（DB / cloud / SSH engine）</td>
          <td>弱（IAM impersonation）</td>
          <td>弱（Managed Identity）</td>
      </tr>
      <tr>
          <td>適合場景</td>
          <td>AWS-only + static secret + RDS rotation 為主</td>
          <td>AWS-only + 大量低敏 config + 不需 rotation</td>
          <td>跨雲 + dynamic credential + 內部 PKI</td>
          <td>GCP-only + Workload Identity 已主導</td>
          <td>Azure-only + Managed Identity 已主導</td>
      </tr>
      <tr>
          <td>退場成本</td>
          <td>低</td>
          <td>低</td>
          <td>中</td>
          <td>低</td>
          <td>低</td>
      </tr>
  </tbody>
</table>
<p>選 Secrets Manager 的核心訴求：<em>AWS-only</em> + <em>大部分 secret 是 static 或 AWS native DB credential</em> + <em>需要 cross-account share 或 rotation Lambda</em> + <em>不想 / 沒量能自管 Vault</em>。如果只是要存 config（feature flag、non-sensitive endpoint）、Parameter Store 8 倍便宜；如果跨雲 + 需要 dynamic credential / transit / PKI、Vault 才能滿足。</p>
<h2 id="進階主題">進階主題</h2>
<p><strong>Custom Rotation Lambda 設計</strong>：4-step state machine 是 <em>idempotent contract</em> — Lambda 必須能被 Secrets Manager 重試任意步驟而不破壞狀態。常見實作陷阱：createSecret 不檢查 AWSPENDING 是否已存在、重試時又產生一把新的、AWSPENDING 對不上 setSecret 寫進去的；setSecret 沒處理「target system 已經有同名 user」的情況、第二次跑會卡住。Template 提供的 PostgreSQL rotation Lambda 用 <em>cloning approach</em> — 在 DB 內 clone 一份 user、改密碼、保留舊 user 跨 rotation 一個週期、下次 rotation 才 drop。</p>
<p><strong>Resource Policy + ABAC tag 跨帳號</strong>：跨帳號 share 時用 ABAC tag 條件比硬列 role ARN 有彈性 — Resource Policy 寫 <code>Condition: aws:PrincipalTag/team = payments</code>、對方 account 任何帶該 tag 的 role 都可讀。代價是 <em>tag 治理</em> 變成 critical control：對方 account 內誰能 attach tag = 誰能拿 secret、IAM Policy 要鎖 <code>iam:TagRole</code> 跟 <code>iam:UntagRole</code> 權限。</p>
<p><strong>Rotation 失敗的監控訊號</strong>：Lambda 執行失敗會在 CloudWatch 留 invocation error、Secrets Manager 把 rotation 標記為 failed、但 <em>secret 仍可用</em>（AWSCURRENT 保留舊 version）— 容易出現 <em>半年沒 rotate 成功但 app 看起來正常</em> 的盲區。要監控 <code>SecretsManager.RotationFailed</code> event（EventBridge rule）+ <code>LastRotatedDate</code> metric 超過 rotation interval 1.5 倍就 alert。</p>
<p><strong>跟 <a href="/blog/backend/07-security-data-protection/vendors/aws-iam/" data-link-title="AWS IAM" data-link-desc="AWS cloud resource permission engine、Role / Policy / STS、跨帳號信任邊界與 OIDC federation 的核心">AWS IAM</a> 整合</strong>：誰可以 <code>GetSecretValue</code> 完全由 IAM 控制、最佳實踐是 <em>workload role</em> 拿 secret（EC2 instance role / ECS task role / Lambda execution role / EKS IRSA）、不要硬把 AWS credential 塞進 secret 再給 application read。Secret 內容應該是 <em>DB password / API token / third-party credential</em>、不應該是 <em>AWS credential</em>（AWS credential 用 IAM role 短期 STS 拿就好）。</p>
<p><strong>CloudTrail data event 的成本權衡</strong>：開 <code>GetSecretValue</code> data event 等於每次 secret 取用都進 CloudTrail、高 QPS application 一天可能跑數百萬筆、CloudTrail 成本（每 100k events 約 $0.10）跟 S3 儲存成本會明顯上升。降本作法：在 EventBridge 用 <em>filtering</em>（只送特定 sensitive secret 的 data event 到 SIEM）、CloudWatch Logs 端設 retention 短一點（7-30 天熱資料、長尾走 S3 + Athena）。</p>
<h2 id="排錯與失敗快速判讀">排錯與失敗快速判讀</h2>
<ul>
<li><strong>GetSecretValue AccessDenied 但 IAM Policy 看起來對</strong>：檢查 Resource Policy 是否限定 source account / VPC、檢查 KMS key policy 是否允許該 role Decrypt — 兩層 grant + KMS 三點任一缺都會 AccessDenied</li>
<li><strong>跨帳號 secret 拿不到</strong>：Resource Policy 沒列對方 role、或 KMS key policy 沒給對方 Decrypt 權限 — 跨帳號要同步配三處（Resource Policy + 對方 IAM + KMS key policy）</li>
<li><strong>Rotation 一直失敗但沒人發現</strong>：沒設 EventBridge alert on <code>RotationFailed</code>、AWSCURRENT 保持舊 version、app 正常但 secret 過期 — 必設 LastRotatedDate metric alert</li>
<li><strong>App 拿到 stale secret rotation 後爆掉</strong>：app 端用了 SDK cache（如 AWS SDK 的 Secrets Manager Cache）、rotation 完成後 cache 沒 invalidate — cache TTL 要短於 staging label 重疊窗口、或實作 retry-on-auth-fail 觸發 cache refresh</li>
<li><strong>CloudTrail 看不到誰拿 secret</strong>：沒開 data event logging — 在 CloudTrail trail 設定加上 <code>AWS::SecretsManager::Secret</code> 為 data resource</li>
<li><strong>跨 region replica rotation 失效</strong>：rotation Lambda 只在 primary region 配、replica region 沒對應 Lambda — 每個 region 各自配 Lambda、或乾脆只在 primary rotate 讓 replica 自動 sync</li>
<li><strong>AWSPREVIOUS fallback 沒生效 batch job 掛</strong>：rotation Lambda finishSecret 太快 drop 舊 user、batch job 拿到舊 credential 連 DB 失敗 — DB rotation template 預設保留舊 user 一個 rotation 週期、custom Lambda 要自己實作雙軌窗口</li>
</ul>
<h2 id="何時改走其他服務">何時改走其他服務</h2>
<table>
  <thead>
      <tr>
          <th>需求形狀</th>
          <th>改走</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>大量低敏 config / feature flag</td>
          <td><a href="https://docs.aws.amazon.com/systems-manager/">SSM Parameter Store</a>（free tier、無 rotation 需求）</td>
      </tr>
      <tr>
          <td>跨雲統一 secret 控制面</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a></td>
      </tr>
      <tr>
          <td>Dynamic DB credential（non-AWS DB）</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault database engine</a></td>
      </tr>
      <tr>
          <td>Workload 拿 AWS credential</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-iam/" data-link-title="AWS IAM" data-link-desc="AWS cloud resource permission engine、Role / Policy / STS、跨帳號信任邊界與 OIDC federation 的核心">AWS IAM</a> role（EC2 instance role / ECS task role / IRSA）— 不要把 AWS credential 塞 secret</td>
      </tr>
      <tr>
          <td>Encryption-as-a-service / envelope encryption</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a> Encrypt / Decrypt API、或 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault transit engine</a></td>
      </tr>
      <tr>
          <td>內部 PKI / mTLS workload cert</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a> + <a href="/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">AWS Private CA</a></td>
      </tr>
      <tr>
          <td>Secret rotation 跨服務 scope 治理</td>
          <td><a href="/blog/backend/07-security-data-protection/credential-rotation-scoped-evidence/" data-link-title="7.27 Credential Rotation with Scoped Evidence 實作示範" data-link-desc="以 webhook/API credential 輪替示範 scope map、證據欄位與回退窗口如何一起設計。">7.5 Credential Rotation Scoped Evidence</a></td>
      </tr>
  </tbody>
</table>
<h2 id="不在本頁內的主題">不在本頁內的主題</h2>
<ul>
<li>Secrets Manager 完整 API reference 跟 SDK 用法</li>
<li>每種 RDS engine 的 rotation Lambda template 內部 SQL 細節</li>
<li>AWS pricing 詳細計算（每 region 略有差異）</li>
<li>Terraform / CDK 跟 Secrets Manager 的 IaC 整合</li>
<li>AWS account organization / SCP 怎麼限制 secret 建立</li>
</ul>
<h2 id="案例回寫">案例回寫</h2>
<p>Secrets Manager 在 07 案例庫沒有直接 vendor-level 事件、以下案例採對照引用：</p>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>跟 Secrets Manager 的關係（對照）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a></td>
          <td>Secrets Manager rotation 必須有 scope map — 跨服務共用同一把 secret 時、AWSPREVIOUS 窗口期 + 雙軌驗證要對齊長尾 batch job、不能單靠 Lambda 自動 promote</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/supply-chain/circleci-2023-secrets-rotation/" data-link-title="7.R7.2.3 CircleCI 2023：CI secrets 輪替壓力" data-link-desc="工程端點入侵後，CI 平台 secrets 如何成為高風險擴散點">CircleCI 2023 Secrets Rotation (red-team)</a></td>
          <td>CI 出事時 Secrets Manager 內 <em>所有 CI runner role 可拿的 secret</em> 都要 rotate — 必須事先以 ABAC tag 標 blast radius、不然只能盲掃整個 account</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Microsoft Storm-0558 Signing Key Chain (red-team)</a></td>
          <td>對照啟示 — Secrets Manager 的 KMS encryption key 必須走 CMK 而非 AWS-managed key、key policy 限定 only Secrets Manager service principal 且 only specific role 可 Decrypt、把 blast radius 鎖在 key policy 內</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>上游：<a href="/blog/backend/07-security-data-protection/secrets-and-machine-credential-governance/" data-link-title="7.6 秘密管理與機器憑證治理" data-link-desc="以問題驅動方式整理 secret、token、key 與機器身份治理">7.6 秘密管理與機器憑證治理</a>、<a href="/blog/backend/07-security-data-protection/detection-coverage-and-signal-governance/" data-link-title="7.13 偵測覆蓋率與訊號治理" data-link-desc="定義偵測覆蓋、訊號品質與誤報成本的治理問題">7.13 偵測覆蓋率與訊號治理</a></li>
<li>平行：<a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a>、<a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a>、<a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a></li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a>（Secrets Manager 加密 key custodian、CMK 與 key policy 治理）</li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/aws-iam/" data-link-title="AWS IAM" data-link-desc="AWS cloud resource permission engine、Role / Policy / STS、跨帳號信任邊界與 OIDC federation 的核心">AWS IAM</a>（誰可以 GetSecretValue、跨帳號 share 的 principal 來源）</li>
<li>跨模組：<a href="/blog/backend/08-incident-response/vendors/" data-link-title="事故處理 Vendor 清單" data-link-desc="規劃 on-call、incident response、status page 與 postmortem 工具的服務頁撰寫順序與判準">8 事故處理 vendor 清單</a>（secret 外洩事件如何 routing 進 IR 流程）</li>
<li>官方：<a href="https://docs.aws.amazon.com/secretsmanager/">AWS Secrets Manager Documentation</a></li>
</ul>
]]></content:encoded></item><item><title>Google Secret Manager</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-secret-manager/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-secret-manager/</guid><description>&lt;p>Google Secret Manager（GSM）是 GCP 原生的 &lt;em>static secret 集中保管&lt;/em> 服務、設計上刻意保持 &lt;em>簡單&lt;/em>：只負責 secret 儲存、版本管理、IAM 授權、跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &amp;#43; Cloud HSM &amp;#43; External Key Manager">Cloud KMS&lt;/a> 整合的 envelope encryption。rotation orchestration、cross-region replication policy、dynamic credential issuing 都不在 GSM 自己做、留給上層用 Cloud Function / Cloud Run 自組。跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &amp;#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager&lt;/a> 最大的差異是 &lt;em>沒有 built-in rotation Lambda&lt;/em> — rotation logic 要自己寫、GSM 只提供 &lt;em>Rotation Schedule + Pub/Sub event&lt;/em> 當觸發點。&lt;/p>
&lt;h2 id="服務定位">服務定位&lt;/h2>
&lt;p>GSM 的定位是 &lt;em>GCP-native 的 secret 集中點&lt;/em>、解決三件事：把 secret 從 environment variable / Cloud Build substitution / GitHub secret 收回單一受控位置；用 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Google Cloud IAM&lt;/a> 的 &lt;em>role binding on secret resource&lt;/em> 控制誰能讀；走 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Workload Identity Federation&lt;/a> 讓 GKE / Cloud Run / 外部 workload（GitHub Actions / AWS / Azure）安全取用、避免長期 service account key 散落。&lt;/p>
&lt;p>跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault&lt;/a> 比、GSM 沒有 dynamic credential engine、沒有 transit / PKI engine、沒有跨雲統一介面 — 但運維成本接近於零、跟 GCP IAM / KMS / Cloud Logging 的整合是 first-class。跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &amp;#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager&lt;/a> 比、GSM 把 rotation orchestration 推給應用層、自由度高但代價是 &lt;em>rotation 流程要自己設計&lt;/em>；跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &amp;#43; Key &amp;#43; Certificate）、整合 Managed Identity &amp;#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault&lt;/a> 比、兩者 mindset 相近（單雲、IAM-driven、CMEK 整合）、各自綁雲。&lt;/p></description><content:encoded><![CDATA[<p>Google Secret Manager（GSM）是 GCP 原生的 <em>static secret 集中保管</em> 服務、設計上刻意保持 <em>簡單</em>：只負責 secret 儲存、版本管理、IAM 授權、跟 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud KMS</a> 整合的 envelope encryption。rotation orchestration、cross-region replication policy、dynamic credential issuing 都不在 GSM 自己做、留給上層用 Cloud Function / Cloud Run 自組。跟 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a> 最大的差異是 <em>沒有 built-in rotation Lambda</em> — rotation logic 要自己寫、GSM 只提供 <em>Rotation Schedule + Pub/Sub event</em> 當觸發點。</p>
<h2 id="服務定位">服務定位</h2>
<p>GSM 的定位是 <em>GCP-native 的 secret 集中點</em>、解決三件事：把 secret 從 environment variable / Cloud Build substitution / GitHub secret 收回單一受控位置；用 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Google Cloud IAM</a> 的 <em>role binding on secret resource</em> 控制誰能讀；走 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Workload Identity Federation</a> 讓 GKE / Cloud Run / 外部 workload（GitHub Actions / AWS / Azure）安全取用、避免長期 service account key 散落。</p>
<p>跟 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a> 比、GSM 沒有 dynamic credential engine、沒有 transit / PKI engine、沒有跨雲統一介面 — 但運維成本接近於零、跟 GCP IAM / KMS / Cloud Logging 的整合是 first-class。跟 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a> 比、GSM 把 rotation orchestration 推給應用層、自由度高但代價是 <em>rotation 流程要自己設計</em>；跟 <a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a> 比、兩者 mindset 相近（單雲、IAM-driven、CMEK 整合）、各自綁雲。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本頁、讀者能判斷：</p>
<ol>
<li>哪些 secret 適合 GSM（GCP-only、static、靠 IAM 授權即可）、哪些該走 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a> 或其他雲端 native</li>
<li>GSM 最低安全設定（CMEK、Data Access audit、Workload Identity Federation、IAM Conditions）</li>
<li>自寫 rotation Cloud Function 時必須處理的 <em>版本切換窗口</em> 跟 <em>fallback 邏輯</em></li>
<li>何時 GSM 不夠用、要往 Vault / Berglas / Cloud HSM 走</li>
</ol>
<h2 id="最短判讀路徑">最短判讀路徑</h2>
<p>判讀一個 GSM deployment 是否健康、最少看四件事：</p>
<ul>
<li><strong>誰能讀 secret</strong>：secret resource 上的 IAM binding 是不是用最小單位授權（per-secret、不是 project-level <code>roles/secretmanager.secretAccessor</code>）、有沒有上 IAM Conditions 限定時間 / IP / resource tag</li>
<li><strong>Key custody 分離</strong>：encryption key 是 Google-managed default key、還是 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud KMS</a> CMEK？CMEK 的 key 持有 admin 跟 secret access admin 是不是分人</li>
<li><strong>取用路徑</strong>：workload 取 secret 是走 <em>service account key</em>（壞模式、長期憑證散落）還是 <em>Workload Identity Federation</em>（GKE WIF / 外部 OIDC token exchange）</li>
<li><strong>證據是否可回查</strong>：Admin Activity audit 預設開、Data Access audit（<code>AccessSecretVersion</code> 誰呼叫）預設 <em>關</em>、production 要手動 enable + 接 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Cloud Logging sink</a> 推到 SIEM</li>
</ul>
<p>四件事任一缺失、就是 <a href="/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">Audit Log</a> 與 <a href="/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management</a> 邊界的待補項目。</p>
<h2 id="日常操作與決策形狀">日常操作與決策形狀</h2>
<p><strong>IAM Conditions 收 scope</strong>：GSM 的 secretAccessor role 預設綁到 secret resource、但組織常見錯配是給整個 project 上 <code>roles/secretmanager.secretAccessor</code> — 等於整個 project 所有 secret 都能讀。應該用 <em>per-secret binding</em>、再加 IAM Conditions（<code>resource.name.endsWith('prod-db-password')</code>、<code>request.time &lt; timestamp('...')</code>）限縮時間窗口。對應 <a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/okta-cloudflare-2023-support-supply-chain/" data-link-title="7.R7.1.2 Okta &#43; Cloudflare 2023：支援流程與身分供應鏈" data-link-desc="支援工單與第三方身份供應商路徑如何變成入侵鏈的一部分">Okta Cloudflare 2023 supply chain</a> 的對照啟示：第三方 token scope 過寬時、上游事件直接傳導下游、IAM Conditions 是收 scope 的工具。</p>
<p><strong>Secret Version + Alias 模型</strong>：每個 secret 有 monotonic version（v1、v2、v3…）、預設 alias <code>latest</code> 指向最新 enabled version。rotation 不是「更新現有 secret」、是 <em>建立新 version + 把舊 version disable</em>。應用端要支援 <em>讀新 version 失敗時 fallback 舊 version</em>、或在 rotation Cloud Function 內實作 <em>雙軌驗證窗口</em>（新版本上線後一段時間舊版還能讀、確認所有 consumer 切過去再 destroy 舊版）。沒這層設計、一次 rotation 就會打掉沒及時更新的 consumer。</p>
<p><strong>CMEK（Customer-Managed Encryption Key）</strong>：GSM 預設用 Google-managed key、production 應該指向 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud KMS</a> CMEK。意義是 <em>把 key 持有跟 secret 取用分離</em> — 即使 secret admin 被攻破、沒有 CMEK 的 <code>decrypt</code> 權限拿不到明文。代價是 CMEK key region 跟 secret replication 要對齊（key 在 <code>us-central1</code> 但 secret 設 automatic replication = key 進不去其他 region、secret access 會失敗）。</p>
<p><strong>Replication 策略</strong>：automatic 是 GCP 自動跨 region replicate（高可用、不需要管 region 一致性、但 data residency 受 GCP 全球策略支配）；user-managed 是手動指定 region list（精細控制資料駐留、適合有 GDPR / 跨境合規需求的場景、但 region 加減要自己管 + CMEK key 要在每個指定 region 都存在）。一個常見錯配：選 user-managed 但只設一個 region — 等於沒有跨 region 冗餘、該 region 出事 secret 完全讀不到。</p>
<p><strong>Rotation 是自管 schedule</strong>：GSM 提供的不是 rotation logic、是 <em>Rotation Schedule</em>（cron 或固定間隔）、到期會發 <em>Pub/Sub message</em> 到指定 topic、由 <em>自己寫的 Cloud Function / Cloud Run</em> 訂閱該 topic 執行實際 rotation（呼叫上游系統 API 生新 credential、寫成新 secret version、disable 舊 version）。對應 <a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a>：rotation Cloud Function 必須自己處理 <em>scope map</em>（哪些 consumer 用了同一把 secret）跟 <em>雙軌驗證窗口</em>（confirm 所有 consumer 切到新版本才 disable 舊版）、不像 AWS Secrets Manager 有 built-in 四階段 flow（<code>createSecret</code> → <code>setSecret</code> → <code>testSecret</code> → <code>finishSecret</code>）。</p>
<p><strong>Workload Identity Federation 取用</strong>：external workload（GitHub Actions / AWS workload / Azure workload / on-prem K8s）用 WIF 拿 GSM secret 是現代預設模式 — workload 用自己的 OIDC token（GitHub OIDC、AWS STS）跟 GCP STS 交換 short-lived access token、再用 token 呼叫 GSM。避開了「長期 service account JSON key 散落 CI / 第三方環境」的問題。GKE 內 workload 走 <em>GKE Workload Identity</em>（pod ServiceAccount → GCP service account 綁定）取 secret、也是同 mindset。</p>
<p><strong>Audit log 治理</strong>：GSM 的 audit 分兩層 — Admin Activity（create / delete / IAM 變更、預設開、免費）、Data Access（<code>AccessSecretVersion</code>、預設 <em>關</em>、開啟有 log 量跟 BigQuery export cost）。production 不開 Data Access = 事故時 <em>連 secret 被誰取過都查不到</em>、必須在 project IAM Audit Config 開、Cloud Logging sink 推到 SIEM 或 BigQuery（見 <a href="/blog/backend/07-security-data-protection/detection-coverage-and-signal-governance/" data-link-title="7.13 偵測覆蓋率與訊號治理" data-link-desc="定義偵測覆蓋、訊號品質與誤報成本的治理問題">7.13 偵測覆蓋率與訊號治理</a>）。</p>
<h2 id="核心取捨表">核心取捨表</h2>
<table>
  <thead>
      <tr>
          <th>取捨維度</th>
          <th>Google Secret Manager</th>
          <th>HashiCorp Vault</th>
          <th>AWS Secrets Manager</th>
          <th>Azure Key Vault</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>部署模型</td>
          <td>GCP managed</td>
          <td>自管 cluster（HA + replication）</td>
          <td>AWS managed</td>
          <td>Azure managed</td>
      </tr>
      <tr>
          <td>跨雲</td>
          <td>弱 — 綁 GCP</td>
          <td>強 — 同一介面跨 AWS / GCP / Azure / on-prem</td>
          <td>弱 — 綁 AWS</td>
          <td>弱 — 綁 Azure</td>
      </tr>
      <tr>
          <td>Rotation 模型</td>
          <td>自寫 Cloud Function（Pub/Sub trigger）</td>
          <td>dynamic engine 自動 lease</td>
          <td>built-in Lambda 四階段 flow</td>
          <td>自寫 Function App（Event Grid trigger）</td>
      </tr>
      <tr>
          <td>Dynamic credential</td>
          <td>無（靠 IAM impersonation 替代）</td>
          <td>DB / cloud / SSH engine 完整</td>
          <td>RDS rotation 有、cloud STS 較弱</td>
          <td>較弱（依靠 Managed Identity）</td>
      </tr>
      <tr>
          <td>Encryption key</td>
          <td>Google-managed default / <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud KMS</a> CMEK</td>
          <td>自管 / KMS auto-unseal</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a> CMK</td>
          <td>Azure Key Vault key</td>
      </tr>
      <tr>
          <td>External workload</td>
          <td>Workload Identity Federation（成熟）</td>
          <td>AppRole / Kubernetes / OIDC auth</td>
          <td>IAM Roles Anywhere（較新）</td>
          <td>Managed Identity / Workload Identity</td>
      </tr>
      <tr>
          <td>運維成本</td>
          <td>低</td>
          <td>高 — HA、upgrade、replication 自己顧</td>
          <td>低</td>
          <td>低</td>
      </tr>
      <tr>
          <td>適合場景</td>
          <td>GCP-heavy + WIF 已主導 + static secret 為主</td>
          <td>跨雲、dynamic credential、內部 PKI</td>
          <td>AWS-heavy + 需要 built-in rotation 收斂</td>
          <td>Azure-heavy + Managed Identity 已主導</td>
      </tr>
      <tr>
          <td>退場成本</td>
          <td>低</td>
          <td>中 — dynamic engine 接線多</td>
          <td>低</td>
          <td>低</td>
      </tr>
  </tbody>
</table>
<p>選 GSM 的核心訴求：workload 主要跑在 GCP（GKE / Cloud Run / Cloud Build）、已經用 Workload Identity Federation 收 service account key、secret 形態以 static 為主（DB password、third-party API key、private key）、rotation 邏輯願意用 Cloud Function 自寫。要跨雲、要 dynamic credential、要內建 rotation flow、需要 transit encryption — 走 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">Vault</a>。</p>
<h2 id="進階主題">進階主題</h2>
<p><strong>CMEK + Cloud KMS 雙軌權限分離</strong>：production 應該 <em>至少</em> 把 prod secret 的 CMEK key 跟 secret IAM 分到不同 admin group — secret admin 可以建 / 改 secret 但不能 decrypt（沒 KMS <code>cloudkms.cryptoKeyDecrypter</code>），KMS admin 可以管 key 但不能讀 secret 內容。對應 <a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Microsoft Storm-0558 signing key chain</a> 的對照啟示：key 不離 KMS 邊界、跟 HSM-bound 同 mindset；CMEK 是把這個原則內建到 secret 路徑。</p>
<p><strong>Berglas（OSS pattern）</strong>：<a href="https://github.com/GoogleCloudPlatform/berglas">Berglas</a> 是 Google 開源的 GSM client library + CLI、在 Cloud Run / Cloud Function / GKE 啟動時把 <code>sm://...</code> 參考自動 resolve 成實際 secret value、注進環境變數或檔案。比起應用端寫 SDK 取 secret 的好處：<em>secret 不進 container image / build manifest</em>、只有 runtime 取得；缺點是多一層 dependency、且 Berglas 自己有 IAM 需求要管。</p>
<p><strong>GKE Workload Identity 取用</strong>：GKE pod 用 ServiceAccount → IAM service account 綁定（透過 <code>iam.gke.io/gcp-service-account</code> annotation）、pod 內呼叫 GSM API 自動帶 GCP service account 身份、metadata server 簽 token。比起把 service account JSON key mount 進 pod、Workload Identity 沒有長期 credential 在 pod 內、credential rotation 由 GCP metadata 自動處理。</p>
<p><strong>Secret rotation Cloud Function 樣板</strong>：訂閱 secret 的 rotation topic（Pub/Sub）、message 帶 secret name 跟 trigger reason；Function 內呼叫上游系統 API（DB / SaaS）生新 credential、用 <code>secretmanager.AddSecretVersion</code> 寫新 version、等一段時間（雙軌驗證窗口）後 <code>DisableSecretVersion</code> 舊 version、最後 <code>DestroySecretVersion</code> 完成 rotation。<strong>雙軌窗口的長度必須大於 consumer 的最長 cache TTL</strong>、否則沒及時 refresh 的 consumer 會在 disable 後失敗。</p>
<p><strong>Pub/Sub event subscription（new in 2023+）</strong>：除了 rotation schedule 自動發 event、GSM 也支援對 secret 任意變更（new version、IAM change）發 Pub/Sub message、可接 SOAR / SIEM 做 <em>secret 異常變更告警</em>（例：非 CI service account 在週末新增 secret version）。</p>
<h2 id="排錯與失敗快速判讀">排錯與失敗快速判讀</h2>
<ul>
<li><strong>取 secret 拿到 PERMISSION_DENIED</strong>：通常是 IAM binding 在 project 層但 secret 在某 sub-resource、或 IAM Conditions 把當前 caller 排除 — 用 <code>gcloud secrets get-iam-policy</code> 直接看 binding、確認 condition 表達式</li>
<li><strong>CMEK 設定後突然讀不到 secret</strong>：CMEK key region 跟 secret replication region 不對齊、或 caller 沒有 KMS decrypt 權限 — 確認 key 在所有 replication region 都有版本、secret accessor service account 有 <code>cloudkms.cryptoKeyDecrypter</code></li>
<li><strong>Rotation Cloud Function 跑了但 consumer 認證失敗</strong>：雙軌窗口太短或 consumer 沒實作 <em>latest version 失敗 fallback</em>、舊版 disable 後孤兒 consumer 直接斷 — 把雙軌窗口拉到 cache TTL × 2、補 fallback 邏輯</li>
<li><strong>Data Access audit 沒紀錄</strong>：預設關、要在 project IAM Audit Config 明確開 <code>secretmanager.googleapis.com</code> 的 DATA_READ — 不開等於沒辦法回答「事故當下誰讀了 secret」</li>
<li><strong>External workload 拿不到 secret</strong>：Workload Identity Federation 的 provider attribute mapping 沒對齊（GitHub OIDC token 的 <code>repository</code> claim 沒被 map 到 attribute condition）— 走 <code>gcloud iam workload-identity-pools providers describe</code> 看 mapping、用 token introspection 驗實際 claim</li>
<li><strong>Secret version 累積過多</strong>：rotation 只 disable 不 destroy、版本無限長 — 加 lifecycle policy（手動 / Cloud Function 排程）destroy 超過 N 個版本以前的舊版</li>
<li><strong>GKE pod 用 Workload Identity 但拿不到 secret</strong>：通常是 GKE 沒 enable Workload Identity feature、或 <code>iam.gke.io/gcp-service-account</code> annotation 拼錯、或 GCP service account 沒給 K8s ServiceAccount <code>iam.workloadIdentityUser</code> — 三層都要對才能通</li>
</ul>
<h2 id="何時改走其他服務">何時改走其他服務</h2>
<table>
  <thead>
      <tr>
          <th>需求形狀</th>
          <th>改走</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>跨雲 secret 統一介面</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a></td>
      </tr>
      <tr>
          <td>需要 dynamic database / cloud credential</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a> dynamic engine</td>
      </tr>
      <tr>
          <td>需要 built-in 四階段 rotation flow</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a>（若可遷 AWS）</td>
      </tr>
      <tr>
          <td>Encryption-as-a-service / 內部 PKI</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a> transit / PKI engine</td>
      </tr>
      <tr>
          <td>FIPS 140-2 Level 3 HSM 需求</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud HSM</a>（KMS 後端可改 HSM）</td>
      </tr>
      <tr>
          <td>公開憑證 PKI</td>
          <td>Google Certificate Authority Service / <a href="/blog/backend/07-security-data-protection/vendors/letsencrypt/" data-link-title="Let&#39;s Encrypt" data-link-desc="免費 &#43; 自動化的公共 ACME CA、90 天 TTL 強制自動化、跨雲跨平台 public TLS cert 的事實基礎">Let&rsquo;s Encrypt</a></td>
      </tr>
      <tr>
          <td>K8s workload cert 自動化</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a></td>
      </tr>
      <tr>
          <td>Secret rotation 證據鏈</td>
          <td><a href="/blog/backend/07-security-data-protection/credential-rotation-scoped-evidence/" data-link-title="7.27 Credential Rotation with Scoped Evidence 實作示範" data-link-desc="以 webhook/API credential 輪替示範 scope map、證據欄位與回退窗口如何一起設計。">7.5 Credential Rotation Scoped Evidence</a></td>
      </tr>
  </tbody>
</table>
<h2 id="不在本頁內的主題">不在本頁內的主題</h2>
<ul>
<li>GSM 完整 REST API 跟 <code>gcloud secrets</code> 詳盡子命令</li>
<li>Cloud KMS key lifecycle 跟 rotation 細節（看 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Google Cloud KMS</a> 章）</li>
<li>Workload Identity Federation 完整設定步驟（attribute mapping、condition expression、provider 設定看 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Google Cloud IAM</a> 章）</li>
<li>Berglas 完整 CLI 用法</li>
<li>Cloud Function / Cloud Run 部署細節</li>
<li>GCP Organization Policy 跟 secret 跨 project 共享的進階場景</li>
</ul>
<h2 id="案例回寫">案例回寫</h2>
<p>GSM 在 07 案例庫沒有直接 vendor-level 事件、以下案例採對照引用：</p>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>跟 GSM 的關係（對照）</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a></td>
          <td>GSM rotation 是自寫 Cloud Function、scope map 跟雙軌驗證窗口都要自己設計、不像 AWS Secrets Manager 有 built-in 四階段 flow — 設計時就要把 consumer scope 跟 cache TTL 算進 rotation 排程</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Microsoft Storm-0558 Signing Key Chain (red-team)</a></td>
          <td>對照啟示 — GSM CMEK 把 encryption key 放 <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud KMS</a>、key 不離 KMS 邊界、跟 HSM-bound 同 mindset；secret admin 跟 KMS admin 分人是減 blast radius 的關鍵</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/okta-cloudflare-2023-support-supply-chain/" data-link-title="7.R7.1.2 Okta &#43; Cloudflare 2023：支援流程與身分供應鏈" data-link-desc="支援工單與第三方身份供應商路徑如何變成入侵鏈的一部分">Okta Cloudflare 2023 Support Supply Chain (red-team)</a></td>
          <td>對照啟示 — GSM 管的第三方 token（GitHub PAT / Slack token / SaaS API key）scope 過寬時、上游事件直接傳導下游、要走 IAM Conditions 收 caller scope 跟過期時間</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>上游：<a href="/blog/backend/07-security-data-protection/secrets-and-machine-credential-governance/" data-link-title="7.6 秘密管理與機器憑證治理" data-link-desc="以問題驅動方式整理 secret、token、key 與機器身份治理">7.6 秘密管理與機器憑證治理</a>、<a href="/blog/backend/07-security-data-protection/detection-coverage-and-signal-governance/" data-link-title="7.13 偵測覆蓋率與訊號治理" data-link-desc="定義偵測覆蓋、訊號品質與誤報成本的治理問題">7.13 偵測覆蓋率與訊號治理</a></li>
<li>平行：<a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a>、<a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a>、<a href="/blog/backend/07-security-data-protection/vendors/azure-key-vault/" data-link-title="Azure Key Vault" data-link-desc="Azure 三合一 service（Secret &#43; Key &#43; Certificate）、整合 Managed Identity &#43; Entra ID RBAC、Premium tier 走 HSM">Azure Key Vault</a></li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Google Cloud KMS</a>（GSM CMEK 後端、key custody 分離）</li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">Google Cloud IAM</a>（secret IAM binding、Workload Identity Federation 設定）</li>
<li>跨模組：<a href="/blog/backend/08-incident-response/vendors/" data-link-title="事故處理 Vendor 清單" data-link-desc="規劃 on-call、incident response、status page 與 postmortem 工具的服務頁撰寫順序與判準">8 事故處理 vendor 清單</a>（GSM 事件如何 routing 進 IR 流程）</li>
<li>官方：<a href="https://cloud.google.com/secret-manager/docs">Secret Manager Documentation</a></li>
</ul>
]]></content:encoded></item><item><title>Azure Key Vault</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-key-vault/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-key-vault/</guid><description>&lt;p>Azure Key Vault 是 Azure 平台把 &lt;em>secret&lt;/em>、&lt;em>cryptographic key&lt;/em>、&lt;em>X.509 certificate&lt;/em> 三類資產 &lt;em>合進同一個 service&lt;/em> 的設計。Vault instance 本身是 first-class ARM resource、有 FQDN endpoint（&lt;code>https://&amp;lt;vault-name&amp;gt;.vault.azure.net&lt;/code>）、跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &amp;#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&amp;#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Azure RBAC&lt;/a> 跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &amp;#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&amp;#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Entra ID&lt;/a> Managed Identity 深度整合 — 每個 Vault 自己一個邊界、區別於 region-wide service 的模型。&lt;/p>
&lt;h2 id="服務定位">服務定位&lt;/h2>
&lt;p>Azure Key Vault 的核心定位是 &lt;em>三合一 secret + key + cert service 加 Azure-native secret-less 取用&lt;/em>。AWS 是 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &amp;#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">Secrets Manager&lt;/a> + &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &amp;#43; Grant 雙軌授權">KMS&lt;/a> + &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &amp;#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">ACM&lt;/a> 三個獨立 service、職責邊界清楚但要管三套權限；GCP 是 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &amp;#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager&lt;/a> + &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &amp;#43; Cloud HSM &amp;#43; External Key Manager">Cloud KMS&lt;/a> + Certificate Authority Service 三個獨立；Azure 把這三件事合在 Key Vault — 同一 RBAC role 可同時管 secret / key / cert、減少 IAM 維護成本、但治理上需要在 Vault 內用 &lt;em>naming convention + 多 Vault instance&lt;/em> 自己劃分敏感度邊界（例：production secret / cert 分開不同 Vault、admin access 分人）。&lt;/p></description><content:encoded><![CDATA[<p>Azure Key Vault 是 Azure 平台把 <em>secret</em>、<em>cryptographic key</em>、<em>X.509 certificate</em> 三類資產 <em>合進同一個 service</em> 的設計。Vault instance 本身是 first-class ARM resource、有 FQDN endpoint（<code>https://&lt;vault-name&gt;.vault.azure.net</code>）、跟 <a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Azure RBAC</a> 跟 <a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Entra ID</a> Managed Identity 深度整合 — 每個 Vault 自己一個邊界、區別於 region-wide service 的模型。</p>
<h2 id="服務定位">服務定位</h2>
<p>Azure Key Vault 的核心定位是 <em>三合一 secret + key + cert service 加 Azure-native secret-less 取用</em>。AWS 是 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">Secrets Manager</a> + <a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">KMS</a> + <a href="/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">ACM</a> 三個獨立 service、職責邊界清楚但要管三套權限；GCP 是 <a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a> + <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Cloud KMS</a> + Certificate Authority Service 三個獨立；Azure 把這三件事合在 Key Vault — 同一 RBAC role 可同時管 secret / key / cert、減少 IAM 維護成本、但治理上需要在 Vault 內用 <em>naming convention + 多 Vault instance</em> 自己劃分敏感度邊界（例：production secret / cert 分開不同 Vault、admin access 分人）。</p>
<p>跟 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a> 相比、Azure Key Vault 是 Azure-only 的 <em>static-focused</em> 服務 — 沒有 dynamic credential engine、沒有 transit encryption-as-a-service、沒有跨雲統一介面。優勢是 <em>零運維</em> + <em>Managed Identity 取用免 client secret</em> + <em>Premium tier 直接 HSM-backed</em>。Azure-heavy + 一站式 secret/key/cert + secret-less workload 取用是 Key Vault 的甜蜜點。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本頁、讀者能判斷：</p>
<ol>
<li>哪些 secret / key / cert 適合放 Key Vault、哪些該走 <a href="https://learn.microsoft.com/azure/key-vault/managed-hsm/overview">Managed HSM</a>（FIPS 140-2 Level 3 需求）</li>
<li>Access Policy 跟 Azure RBAC 兩種授權模型的差異與 migration 路徑</li>
<li>Soft Delete + Purge Protection 的 <em>防誤刪</em> 與 <em>防勒索</em> 邊界</li>
<li>何時用 Key Vault、何時改走 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a>（跨雲 + dynamic credential）的取捨</li>
</ol>
<h2 id="最短判讀路徑">最短判讀路徑</h2>
<p>判斷 Azure Key Vault deployment 是否健康、最少看四件事：</p>
<ul>
<li><strong>誰能 access</strong>：Vault 用 Access Policy 還是 Azure RBAC、是否還有 legacy Access Policy 沒清掉、Managed Identity 的 role assignment 是否最小化（Key Vault Secrets User 而非 Key Vault Administrator）</li>
<li><strong>RBAC vs Access Policy 模型</strong>：production 應該全走 Azure RBAC（跟 <a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Azure RBAC vendor</a> 同套）、舊 Access Policy 是 migration backlog、不可長期兩軌並存</li>
<li><strong>Soft Delete + Purge Protection</strong>：兩個都應開、Soft Delete 90 天 retention、Purge Protection 開了之後連 owner 都不能立即 purge — 防誤刪 + 防 ransomware 一次性刪光</li>
<li><strong>Diagnostic Logs</strong>：Key Vault <em>預設不記操作 log</em>、必須手動配 Diagnostic Setting 推 Log Analytics / Event Hub / Storage — 沒這層 <code>KeyVaultGet</code> / <code>SecretGet</code> 都沒 audit trail</li>
</ul>
<p>四件事任一缺失、就是 <a href="/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">Audit Log</a> 與 <a href="/blog/backend/knowledge-cards/secret-management/" data-link-title="Secret Management" data-link-desc="說明 token、key、password 與憑證如何保存、輪替與撤銷">Secret Management</a> 邊界的待補項目。</p>
<h2 id="日常操作與決策形狀">日常操作與決策形狀</h2>
<p><strong>Vault Standard vs Premium</strong>：Standard 用 software protection（key 存在 Microsoft-managed software boundary）、Premium 用 FIPS 140-2 Level 2 HSM-backed key、key material 在 HSM 內、不可 export。Premium 適合 <em>signing key / wrapping key 等高敏 key</em>、Standard 適合 <em>application secret + 常規 envelope encryption key</em>。要 FIPS 140-2 Level 3、Standard 跟 Premium 都不夠、必須用 Managed HSM。</p>
<p><strong>Access Policy vs Azure RBAC（兩種授權）</strong>：Access Policy 是 Key Vault legacy 模型 — 在 Vault 物件上掛一張 capability 表（Get / List / Set / Delete / Encrypt / Sign 等細粒度權限）、跟 Azure RBAC 體系獨立。Azure RBAC 模型是新版 — 用 Azure built-in role（Key Vault Secrets User / Key Vault Crypto User / Key Vault Administrator）走 <a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Entra ID</a> 統一身份治理。production 全走 RBAC、舊 Vault 的 Access Policy 是 migration backlog — 兩軌並存會出現 <em>RBAC 拒絕但 Access Policy 允許</em> 的權限漏洞。</p>
<p><strong>Managed Identity 取用（secret-less）</strong>：Azure VM / Function / App Service / AKS pod 走 <em>Managed Identity</em> 直接呼叫 Key Vault API — 不需要存 client secret 或 cert。Workload 拿 IMDS token、token 帶 Entra ID identity、Key Vault 端用 RBAC role assignment 驗證 — 這是 Azure-native 的 secret-less 取用模式、跟 <a href="/blog/backend/07-security-data-protection/vendors/aws-iam/" data-link-title="AWS IAM" data-link-desc="AWS cloud resource permission engine、Role / Policy / STS、跨帳號信任邊界與 OIDC federation 的核心">AWS IAM Role for Service Account</a> / <a href="/blog/backend/07-security-data-protection/vendors/google-cloud-iam/" data-link-title="Google Cloud IAM" data-link-desc="GCP cloud resource permission engine、Role Binding / Service Account / Workload Identity Federation、resource hierarchy 為核心的權限治理">GCP Workload Identity</a> 同類設計。production 應該 <em>只允許</em> Managed Identity 取用、禁用 service principal + client secret。</p>
<p><strong>Secret rotation（手動 / event-driven）</strong>：Key Vault Secret <em>沒有像 <a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a> 內建的 rotation Lambda</em>。Rotation 走兩條路：手動更新 secret version（app 端拉新版）、或 Event Grid 通知 secret 過期 + Azure Function 觸發 rotation。後者需要自己寫 rotation logic、Key Vault 只提供 <em>版本管理</em> 跟 <em>過期通知</em>、不負責執行 rotation。</p>
<p><strong>Key Rotation Policy</strong>：Key（不是 Secret）有 native Rotation Policy — Vault 在 key 到期前自動生成新版、舊版保留可解密但不再 encrypt。policy 設 <code>rotationPeriod</code> + <code>notifyBeforeExpiry</code>、Key Vault 自動跑、不需要外部觸發。Secret 沒這功能、Key 才有。</p>
<p><strong>Certificate auto-renewal</strong>：Certificate object 可整合 <em>Issuer</em>（DigiCert / GlobalSign / 自簽）做 auto-issue + auto-renew — Key Vault 在到期前自動跑 CSR、向 Issuer 申請新 cert、寫回同一個 Certificate object（保留歷史版本）。比起手動跑 OpenSSL + 寫進 <a href="/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">AWS ACM</a>、Certificate object 的優勢是 <em>Issuer 在 Vault 端統一治理</em> — 不過只支援整合過的 public CA。</p>
<p><strong>Soft Delete + Purge Protection</strong>：Soft Delete 預設開（2020 後新 Vault 強制開）、delete 後 90 天 retention、Recover 可救回。Purge Protection 是 <em>額外</em> 開關 — 開了之後 retention 內任何人（包含 subscription owner）都不能 <code>purge</code> 立即清除、必須等 90 天到期才會物理刪除。這是 <em>防勒索</em> 的關鍵 — 沒 Purge Protection、attacker 拿到 owner role 可以 delete + purge 一次性清光。</p>
<p><strong>Private Endpoint</strong>：Key Vault 預設是 public endpoint（FQDN 走 internet）。Private Endpoint 把 Vault 拉進 VNet、只走內網存取 — 高敏 Vault 應該關 public access、強制走 Private Endpoint + Firewall rule（IP 白名單）。</p>
<h2 id="核心取捨表">核心取捨表</h2>
<table>
  <thead>
      <tr>
          <th>取捨維度</th>
          <th>Azure Key Vault</th>
          <th>AWS（拆三個）</th>
          <th>GCP（拆三個）</th>
          <th>HashiCorp Vault</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>部署模型</td>
          <td>Azure managed、三合一</td>
          <td>AWS managed、Secrets Manager + KMS + ACM 各獨立</td>
          <td>GCP managed、GSM + Cloud KMS + CAS 各獨立</td>
          <td>自管或 HCP managed</td>
      </tr>
      <tr>
          <td>服務邊界</td>
          <td>一個 Vault 內 secret/key/cert 共用 ACL</td>
          <td>三個 service 各自 IAM policy、邊界清楚</td>
          <td>三個 service 各自 IAM policy</td>
          <td>一個 cluster 內 path-based policy</td>
      </tr>
      <tr>
          <td>Secret-less 取用</td>
          <td>Managed Identity 原生</td>
          <td>IAM Role for Service Account / IRSA</td>
          <td>Workload Identity Federation</td>
          <td>AppRole / K8s / cloud IAM auth</td>
      </tr>
      <tr>
          <td>Dynamic credential</td>
          <td>無 — 純 static</td>
          <td>部分（RDS rotation Lambda）</td>
          <td>較弱（依靠 IAM impersonation）</td>
          <td>強 — database / cloud / SSH engine</td>
      </tr>
      <tr>
          <td>HSM 等級</td>
          <td>Standard 軟體 / Premium FIPS 140-2 Level 2 / Managed HSM Level 3</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">KMS</a> Level 3 / <a href="/blog/backend/07-security-data-protection/vendors/cloudhsm/" data-link-title="AWS CloudHSM" data-link-desc="Single-tenant dedicated HSM（FIPS 140-2 Level 3）、AWS 不持 Crypto User credential、合規 &#43; 資料主權場景的 key custody">CloudHSM</a> Level 3</td>
          <td>Cloud KMS HSM Level 3 / Cloud HSM Level 3</td>
          <td>走後端 KMS（AWS / GCP / Azure）</td>
      </tr>
      <tr>
          <td>Certificate auto-renew</td>
          <td>內建（整合 DigiCert / GlobalSign）</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/aws-acm/" data-link-title="AWS ACM" data-link-desc="AWS-managed certificate provisioning、DNS validation &#43; auto-renewal、整合 ELB / CloudFront / API Gateway、Private CA 後端">ACM</a> auto-renew、限 AWS-issued</td>
          <td>CAS + Public CA 整合</td>
          <td>PKI engine 自簽 + <a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a></td>
      </tr>
      <tr>
          <td>跨雲</td>
          <td>弱 — Azure-only</td>
          <td>弱 — AWS-only</td>
          <td>弱 — GCP-only</td>
          <td>強 — 跨雲統一介面</td>
      </tr>
      <tr>
          <td>適合場景</td>
          <td>Azure-heavy + 三合一一站式 + Managed Identity</td>
          <td>AWS-heavy + 職責拆分 + RDS 自動 rotation</td>
          <td>GCP-heavy + Workload Identity Federation</td>
          <td>跨雲 + dynamic credential + 內部 PKI</td>
      </tr>
  </tbody>
</table>
<p>選 Azure Key Vault 的核心訴求：<em>Azure-only</em>、需要 <em>secret + key + cert</em> 一站式、workload 走 <em>Managed Identity</em> secret-less 取用、可接受 <em>無 dynamic credential</em>。需要跨雲統一 secret 控制面、或要 dynamic database credential、走 <a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a>。</p>
<h2 id="進階主題">進階主題</h2>
<p><strong>Managed HSM（dedicated）</strong>：Managed HSM 是 <em>dedicated single-tenant HSM cluster</em>、FIPS 140-2 Level 3、跟 multi-tenant 的 Key Vault Premium 是不同 service。Managed HSM 適合 <em>主權合規</em>（key material 完全自有控制權、Microsoft 也不可存取）、<em>金融 / 醫療 / 政府場景</em>。代價是 <em>貴</em> 跟 <em>初始化要走 ceremony</em>（多人持有 activation key、Microsoft 不可單方面操作）— 不是 Premium 的簡單升級、是另一條 product line。</p>
<p><strong>Premium tier HSM-backed Key</strong>：Premium tier 的 key 有 <code>HSM-protected</code> 屬性、key material 在 multi-tenant HSM 內、API call 還是走標準 Key Vault endpoint、但 cryptographic operation 在 HSM 跑。比 Standard 慢一點、價格高、適合 <em>signing key / wrapping key / root encryption key</em> — 一般 application secret 還是 Standard 即可。</p>
<p><strong>Certificate Issuer 整合</strong>：Vault 內可註冊 Issuer（DigiCert / GlobalSign / Entrust）、提供 API credential、Vault 在 Certificate 到期前自動跑 CSR、向 Issuer 申請、Issuer 簽完寫回 Vault。Self-signed / Unknown Issuer 也支援、後者表示 <em>Vault 產 CSR、人或 pipeline 拿去外部 CA 簽完再 import 回 Vault</em>。</p>
<p><strong>Cross-tenant key access（federated identity）</strong>：Key Vault 可允許跨 Entra ID tenant 的 service principal 取用 — 透過 Federated Identity Credential（Workload Identity Federation）、外部 tenant 的 identity（甚至 GitHub Actions OIDC、AWS workload）拿 token 來 Key Vault 驗證。這是 cross-cloud workload 拉 Azure secret 的方式、不需要存 Azure service principal credential。</p>
<p><strong>跟 <a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Entra ID</a> Conditional Access 整合</strong>：Key Vault 用 Azure RBAC 模型時、可走 Conditional Access policy — <em>特定 IP</em>、<em>已 enrolled 裝置</em>、<em>MFA 已驗證</em> 才能取用 secret / key。production 高敏 Vault 應該疊 Conditional Access、避免單純 RBAC 在 token leak 時就直接被存取。</p>
<h2 id="排錯與失敗快速判讀">排錯與失敗快速判讀</h2>
<ul>
<li><strong>Diagnostic Setting 沒開</strong>：production Vault 啟用後忘了配 Diagnostic Setting 推 log、事故發生時無 <code>SecretGet</code> / <code>KeyDecrypt</code> 紀錄 — 啟動 checklist 必含「Diagnostic Setting → Log Analytics」、Azure Policy 強制全 subscription Vault 都配</li>
<li><strong>Access Policy 跟 RBAC 兩軌並存</strong>：migration 過程中 RBAC 已切換但舊 Access Policy 沒清、出現 <em>RBAC 拒絕但 Access Policy 允許</em> — migration 一次切斷、跑 <code>az keyvault update --enable-rbac-authorization true</code> 後清空所有 Access Policy</li>
<li><strong>Soft Delete 沒開 / Purge Protection 沒開</strong>：誤刪 secret 救不回、或 attacker 拿到 owner role 一次 purge 清光 — 新 Vault 兩個都強制開、Azure Policy 阻擋 <code>enablePurgeProtection: false</code> 的 Vault 建立</li>
<li><strong>Managed Identity role 過寬</strong>：給 workload identity <code>Key Vault Administrator</code> 而非 <code>Key Vault Secrets User</code> — workload 拿到 admin role 等於可改 ACL — role assignment 走 least privilege built-in role</li>
<li><strong>Premium key 跑非 HSM operation</strong>：Premium key 配錯 attribute、key 變成 software-protected 而非 HSM-protected — 建 key 時明示 <code>--protection hsm</code>、CI 驗證 key attribute</li>
<li><strong>Certificate auto-renew Issuer credential 過期</strong>：Vault 內 DigiCert API credential 過期、auto-renew 默默失敗、cert 到期前才發現 — Issuer credential 也要 rotation + monitor</li>
<li><strong>Public access 開著</strong>：Vault 沒關 public endpoint、secret 暴露在 internet（雖然有 RBAC、但 attack surface 多一層）— 高敏 Vault 強制 Private Endpoint + Firewall rule</li>
</ul>
<h2 id="何時改走其他服務">何時改走其他服務</h2>
<table>
  <thead>
      <tr>
          <th>需求形狀</th>
          <th>改走</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>跨雲統一 secret 控制面</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a></td>
      </tr>
      <tr>
          <td>Dynamic database / cloud credential</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a>（database / cloud secret engine）</td>
      </tr>
      <tr>
          <td>FIPS 140-2 Level 3 HSM</td>
          <td><a href="https://learn.microsoft.com/azure/key-vault/managed-hsm/overview">Managed HSM</a> / <a href="/blog/backend/07-security-data-protection/vendors/cloudhsm/" data-link-title="AWS CloudHSM" data-link-desc="Single-tenant dedicated HSM（FIPS 140-2 Level 3）、AWS 不持 Crypto User credential、合規 &#43; 資料主權場景的 key custody">CloudHSM</a></td>
      </tr>
      <tr>
          <td>內部 PKI workload mTLS</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a> + Vault PKI / SPIRE</td>
      </tr>
      <tr>
          <td>公開 web cert 自動更新（非 Azure-issued）</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/letsencrypt/" data-link-title="Let&#39;s Encrypt" data-link-desc="免費 &#43; 自動化的公共 ACME CA、90 天 TTL 強制自動化、跨雲跨平台 public TLS cert 的事實基礎">Let&rsquo;s Encrypt</a> + cert-manager</td>
      </tr>
      <tr>
          <td>Entra ID 身份治理 / Conditional Access</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Azure RBAC</a></td>
      </tr>
      <tr>
          <td>Secret rotation 證據鏈</td>
          <td><a href="/blog/backend/07-security-data-protection/credential-rotation-scoped-evidence/" data-link-title="7.27 Credential Rotation with Scoped Evidence 實作示範" data-link-desc="以 webhook/API credential 輪替示範 scope map、證據欄位與回退窗口如何一起設計。">7.5 Credential Rotation Scoped Evidence</a></td>
      </tr>
  </tbody>
</table>
<h2 id="不在本頁內的主題">不在本頁內的主題</h2>
<ul>
<li>Key Vault REST API / Azure CLI 完整 reference</li>
<li>Managed HSM activation ceremony 完整步驟</li>
<li>Bicep / Terraform 配置 Key Vault 的完整 IaC 範例</li>
<li>Certificate Issuer（DigiCert / GlobalSign）的合約與計價細節</li>
<li>每個 Entra ID role 的細粒度 permission map</li>
</ul>
<h2 id="案例回寫">案例回寫</h2>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>跟 Azure Key Vault 的關係</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/azure-ad-identity-control-plane-2021/" data-link-title="7.C3 Azure AD：2021 Identity Control-plane 事件" data-link-desc="身分控制面事件如何影響多服務信任鏈與回復優先序。">Azure AD Identity Control Plane 2021</a></td>
          <td>Key Vault 是身份控制面下游、Entra ID 出事時 Managed Identity 取 Vault 也失敗 — 需要 fallback access plan（emergency Access Policy + separate identity 走 break-glass）</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/microsoft-storm-0558-signing-key-2023/" data-link-title="7.C4 Microsoft：Storm-0558 簽章金鑰事件" data-link-desc="簽章金鑰事件如何回寫 identity 信任邊界與觀測證據鏈。">Microsoft Storm-0558 Signing Key 2023</a></td>
          <td>Key Vault Premium / Managed HSM 把 signing key 鎖硬體、key 不離保護邊界、跟 HSM-bound 同 mindset — signing key 必上 Premium 或 Managed HSM、不放 Standard</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/microsoft-storm-0558-2023-signing-key-chain/" data-link-title="7.R7.1.5 Microsoft Storm-0558 2023：簽章金鑰鏈與郵件存取" data-link-desc="從簽章金鑰保護失效到雲端郵件存取，拆解身分信任鏈的關鍵控制點">Microsoft Storm-0558 Signing Key Chain (red-team)</a></td>
          <td>Asymmetric Key + Diagnostic Logs 是「誰用 key」的稽核基礎 — production Vault 必開 Diagnostic Setting 推 SIEM、不然 key 被誰用過完全沒紀錄</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/cases/failure-credential-rotation-without-scope/" data-link-title="7.C9 反例：憑證輪替未分 Scope" data-link-desc="憑證輪替若未分域分批，容易造成跨系統連鎖中斷。">Failure: Credential Rotation Without Scope</a></td>
          <td>Key Vault Secret 跨 service 共用時 rotation 要分域 — Vault 端用 Event Grid 通知 + app 端訂閱 rotation event、不能一次 push 全域更新</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>上游：<a href="/blog/backend/07-security-data-protection/secrets-and-machine-credential-governance/" data-link-title="7.6 秘密管理與機器憑證治理" data-link-desc="以問題驅動方式整理 secret、token、key 與機器身份治理">7.6 秘密管理與機器憑證治理</a>、<a href="/blog/backend/07-security-data-protection/transport-trust-and-certificate-lifecycle/" data-link-title="7.5 傳輸信任與憑證生命週期" data-link-desc="以問題驅動方式整理傳輸信任鏈、會話完整性與憑證節奏">7.5 傳輸信任與憑證生命週期</a>（Key Vault Certificate + Managed HSM 為 TLS / signing key 的 root custodian）、<a href="/blog/backend/07-security-data-protection/identity-access-boundary/" data-link-title="7.2 身分與授權邊界" data-link-desc="以問題驅動方式整理身分、授權、會話與供應商身分鏈">7.2 身分與授權邊界</a></li>
<li>平行（secret store）：<a href="/blog/backend/07-security-data-protection/vendors/aws-secrets-manager/" data-link-title="AWS Secrets Manager" data-link-desc="AWS 原生 secret store &#43; 內建 RDS / Redshift rotation Lambda、Resource Policy 跨帳號共享、KMS 加密">AWS Secrets Manager</a>、<a href="/blog/backend/07-security-data-protection/vendors/google-secret-manager/" data-link-title="Google Secret Manager" data-link-desc="GCP 原生 secret store、CMEK &#43; Workload Identity Federation 整合、rotation 走自寫 Cloud Function 而非 built-in Lambda">Google Secret Manager</a>、<a href="/blog/backend/07-security-data-protection/vendors/hashicorp-vault/" data-link-title="HashiCorp Vault" data-link-desc="Self-hosted secret management 與 dynamic credential / encryption-as-a-service / PKI engine、跨雲跨環境的 secret 控制面">HashiCorp Vault</a></li>
<li>平行（KMS-class）：<a href="/blog/backend/07-security-data-protection/vendors/aws-kms/" data-link-title="AWS KMS" data-link-desc="AWS 原生 key management service、envelope encryption / digital signing / Multi-Region Key、Key Policy &#43; Grant 雙軌授權">AWS KMS</a>、<a href="/blog/backend/07-security-data-protection/vendors/google-cloud-kms/" data-link-title="Google Cloud KMS" data-link-desc="GCP 原生 key management service、KeyRing / CryptoKey Version 設計、CMEK 整合 &#43; Cloud HSM &#43; External Key Manager">Google Cloud KMS</a>、<a href="/blog/backend/07-security-data-protection/vendors/cloudhsm/" data-link-title="AWS CloudHSM" data-link-desc="Single-tenant dedicated HSM（FIPS 140-2 Level 3）、AWS 不持 Crypto User credential、合規 &#43; 資料主權場景的 key custody">CloudHSM</a>（Key Vault 是跨類 vendor、同時是 secret store 跟 key management）</li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/azure-rbac/" data-link-title="Azure RBAC &#43; Entra ID" data-link-desc="Azure 雙層身份/權限體系、Entra ID（IdP）&#43; Azure RBAC（resource permission）、Conditional Access、PIM、Managed Identity">Azure RBAC</a>（Managed Identity + RBAC 取用模型）</li>
<li>下游：<a href="/blog/backend/07-security-data-protection/vendors/cert-manager/" data-link-title="cert-manager" data-link-desc="K8s 原生 certificate lifecycle automation、支援 Let&#39;s Encrypt / Vault PKI / Venafi 等多 issuer、auto-renewal &#43; Challenge solver">cert-manager</a>（K8s workload cert 自動化、可整合 Key Vault Certificate）</li>
<li>跨模組：<a href="/blog/backend/08-incident-response/vendors/" data-link-title="事故處理 Vendor 清單" data-link-desc="規劃 on-call、incident response、status page 與 postmortem 工具的服務頁撰寫順序與判準">8 事故處理 vendor 清單</a>（Key Vault 事件如何 routing 進 IR 流程）</li>
<li>官方：<a href="https://learn.microsoft.com/azure/key-vault/">Azure Key Vault Documentation</a></li>
</ul>
]]></content:encoded></item><item><title>Secret Management</title><link>https://tarrragon.github.io/blog/backend/knowledge-cards/secret-management/</link><pubDate>Thu, 23 Apr 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/knowledge-cards/secret-management/</guid><description>&lt;p>Secret management 的核心概念是「用受控流程管理可取得系統權限的秘密資料」。Secret 包含 API key、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/database/" data-link-title="Database" data-link-desc="說明 database 在後端系統中如何承擔正式狀態、查詢與一致性責任">database&lt;/a> password、JWT signing key、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/tls-mtls/" data-link-title="TLS / mTLS" data-link-desc="說明傳輸加密與雙向憑證驗證如何保護跨邊界資料流">TLS&lt;/a> private key、webhook secret 與第三方 credential。&lt;/p>
&lt;h2 id="概念位置">概念位置&lt;/h2>
&lt;p>Secret 是高風險操作能力。它們應集中放在受控系統中，並具備儲存位置、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/authorization/" data-link-title="Authorization" data-link-desc="說明授權如何判斷誰能對哪些資源執行哪些操作">authorization&lt;/a>、使用範圍、輪替週期、撤銷流程與 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">audit log&lt;/a>。&lt;/p>
&lt;h2 id="可觀察訊號與例子">可觀察訊號與例子&lt;/h2>
&lt;p>系統需要 secret management 的訊號是服務開始連接 database、&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/broker/" data-link-title="Broker" data-link-desc="說明 broker 在訊息傳遞系統中負責保存、路由與交付訊息">broker&lt;/a>、雲端 API 或第三方支付。Webhook signing secret 洩漏後，攻擊者可能偽造進站事件；database 密碼洩漏後，資料存取邊界會失效。&lt;/p>
&lt;h2 id="設計責任">設計責任&lt;/h2>
&lt;p>Secret 管理要包含 &lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/least-privilege/" data-link-title="Least Privilege" data-link-desc="說明身份、服務與人員只應取得完成工作所需的最小權限">least privilege&lt;/a>、環境隔離、輪替演練、撤銷、版本管理與部署注入方式。&lt;a href="https://tarrragon.github.io/blog/backend/knowledge-cards/runbook/" data-link-title="Runbook" data-link-desc="說明 runbook 如何把事故判斷與操作步驟標準化">Runbook&lt;/a> 應說明疑似洩漏時如何停用、輪替、追查與恢復。&lt;/p></description><content:encoded><![CDATA[<p>Secret management 的核心概念是「用受控流程管理可取得系統權限的秘密資料」。Secret 包含 API key、<a href="/blog/backend/knowledge-cards/database/" data-link-title="Database" data-link-desc="說明 database 在後端系統中如何承擔正式狀態、查詢與一致性責任">database</a> password、JWT signing key、<a href="/blog/backend/knowledge-cards/tls-mtls/" data-link-title="TLS / mTLS" data-link-desc="說明傳輸加密與雙向憑證驗證如何保護跨邊界資料流">TLS</a> private key、webhook secret 與第三方 credential。</p>
<h2 id="概念位置">概念位置</h2>
<p>Secret 是高風險操作能力。它們應集中放在受控系統中，並具備儲存位置、<a href="/blog/backend/knowledge-cards/authorization/" data-link-title="Authorization" data-link-desc="說明授權如何判斷誰能對哪些資源執行哪些操作">authorization</a>、使用範圍、輪替週期、撤銷流程與 <a href="/blog/backend/knowledge-cards/audit-log/" data-link-title="Audit Log" data-link-desc="說明高風險操作如何留下可追溯、可稽核的紀錄">audit log</a>。</p>
<h2 id="可觀察訊號與例子">可觀察訊號與例子</h2>
<p>系統需要 secret management 的訊號是服務開始連接 database、<a href="/blog/backend/knowledge-cards/broker/" data-link-title="Broker" data-link-desc="說明 broker 在訊息傳遞系統中負責保存、路由與交付訊息">broker</a>、雲端 API 或第三方支付。Webhook signing secret 洩漏後，攻擊者可能偽造進站事件；database 密碼洩漏後，資料存取邊界會失效。</p>
<h2 id="設計責任">設計責任</h2>
<p>Secret 管理要包含 <a href="/blog/backend/knowledge-cards/least-privilege/" data-link-title="Least Privilege" data-link-desc="說明身份、服務與人員只應取得完成工作所需的最小權限">least privilege</a>、環境隔離、輪替演練、撤銷、版本管理與部署注入方式。<a href="/blog/backend/knowledge-cards/runbook/" data-link-title="Runbook" data-link-desc="說明 runbook 如何把事故判斷與操作步驟標準化">Runbook</a> 應說明疑似洩漏時如何停用、輪替、追查與恢復。</p>
]]></content:encoded></item><item><title>Shared Secret 安全輪替設計：雙密過渡期、自動化與緊急流程</title><link>https://tarrragon.github.io/blog/work-log/shared-secret-%E5%AE%89%E5%85%A8%E8%BC%AA%E6%9B%BF%E8%A8%AD%E8%A8%88%E9%9B%99%E5%AF%86%E9%81%8E%E6%B8%A1%E6%9C%9F%E8%87%AA%E5%8B%95%E5%8C%96%E8%88%87%E7%B7%8A%E6%80%A5%E6%B5%81%E7%A8%8B/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/work-log/shared-secret-%E5%AE%89%E5%85%A8%E8%BC%AA%E6%9B%BF%E8%A8%AD%E8%A8%88%E9%9B%99%E5%AF%86%E9%81%8E%E6%B8%A1%E6%9C%9F%E8%87%AA%E5%8B%95%E5%8C%96%E8%88%87%E7%B7%8A%E6%80%A5%E6%B5%81%E7%A8%8B/</guid><description>&lt;h2 id="shared-secret-rotation-這篇要解決什麼">Shared Secret Rotation 這篇要解決什麼&lt;/h2>
&lt;p>Shared Secret rotation 的核心責任是讓 credential 換新時維持可用性、可追蹤性與可撤銷性。它表面上像是一行 SQL update，實際上牽涉 server 與多個 client 的切換時序：&lt;/p>
&lt;ul>
&lt;li>兩邊不同時切、就斷線&lt;/li>
&lt;li>多 client 場景下、總有一兩個沒升級&lt;/li>
&lt;li>緊急洩漏要立即撤換、同時控制服務中斷範圍&lt;/li>
&lt;li>Rotation 中途失敗、舊新 secret 都不通&lt;/li>
&lt;/ul>
&lt;p>這些是維運層的真實痛點。只說「定期 rotate your secret」只能描述目標，還需要雙密期、測試、監控、通知與回退流程，才能把 rotation 變成可執行的操作契約。&lt;/p>
&lt;p>本文聚焦三件事：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>雙密過渡期&lt;/strong>：怎麼讓 client 可以在任意時點切換、不會斷線&lt;/li>
&lt;li>&lt;strong>自動化工具&lt;/strong>：AWS Secrets Manager / HashiCorp Vault / GCP Secret Manager 各自的 rotation 機制&lt;/li>
&lt;li>&lt;strong>緊急 vs 定期&lt;/strong>：兩種流程的差異、何時用哪個&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;strong>本文位置&lt;/strong>：本文是 &lt;a href="https://tarrragon.github.io/blog/work-log/api-%E8%AA%8D%E8%AD%89%E7%9A%84%E4%B8%89%E5%B1%A4%E4%BF%A1%E4%BB%BB%E9%82%8A%E7%95%8C%E4%BD%BF%E7%94%A8%E8%80%85%E7%B3%BB%E7%B5%B1%E8%B7%A8%E7%B3%BB%E7%B5%B1-provisioning/" data-link-title="API 認證的三層信任邊界：使用者、系統、跨系統 Provisioning" data-link-desc="API 認證的信任邊界分層（Bearer Token / Shared Secret / Provisioning）：各層的洩漏後果與撤銷方式，以及混用造成的設計失效模式。">API 認證的三層信任邊界&lt;/a> Layer 2 的深入篇。主文聚焦「為什麼系統間要獨立 credential」、本文聚焦「Shared Secret 輪替的工程實務」。&lt;/p>&lt;/blockquote>
&lt;hr>
&lt;h2 id="rotation-解決什麼威脅">Rotation 解決什麼威脅&lt;/h2>
&lt;p>Rotation 是縮短 secret 暴露窗與清理殘留 access 的 lifecycle 控制。它降低三種具體威脅：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>威脅&lt;/th>
 &lt;th>Rotation 怎麼緩解&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;strong>未察覺的洩漏&lt;/strong>&lt;/td>
 &lt;td>Secret 可能已被外洩、定期換能限制攻擊者使用的時間窗&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>離職員工殘留 access&lt;/strong>&lt;/td>
 &lt;td>員工離職後系統 access 沒撤徹底、rotation 把該員工知道的 secret 變廢&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;strong>長期暴露的 metadata&lt;/strong>&lt;/td>
 &lt;td>Secret 越久、log / backup / git history 留存的副本越多&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>Rotation 本身有成本與風險，切換設計不完整時會造成斷線。所以實務目標是「在切換可控的前提下，選一個能接受的頻率」。&lt;/p>
&lt;p>常見定期頻率：&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>業界場景&lt;/th>
 &lt;th>典型頻率&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>一般 SaaS&lt;/td>
 &lt;td>90 天 / 180 天&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>金融、醫療&lt;/td>
 &lt;td>30 天 / 90 天&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>高敏感（國防、政府）&lt;/td>
 &lt;td>7 天 / 14 天、或事件觸發&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>純內部、低風險&lt;/td>
 &lt;td>半年 / 一年、或永不 rotate&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;blockquote>
&lt;p>&lt;strong>頻率取決於威脅模型與操作能力&lt;/strong>：NIST SP 800-63B 對多數場景認可 30-90 天足夠、過於激進的 rotation 反而提高出錯機率。7-14 天適用於合規條款明文要求或私鑰可硬體保護的場景；多數 SaaS 可以停在 30-180 天區間。&lt;/p>&lt;/blockquote>
&lt;p>「事件觸發才換」也有合理情境。純內部 cron job、secret 外流管道少、rotation 成本大於風險時，可以選擇以事件觸發取代固定排程；重點是留下 owner、inventory 與重新評估條件。&lt;/p>
&lt;hr>
&lt;h2 id="核心機制雙密過渡期dual-secret-rollover">核心機制：雙密過渡期（Dual-secret Rollover）&lt;/h2>
&lt;h3 id="直接-atomic-切換的失效點">直接 atomic 切換的失效點&lt;/h3>
&lt;p>最直覺的 rotation 流程是：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">T0: 兩邊都是 secret_v1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">T1: server 端換成 secret_v2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">T2: client 端換成 secret_v2&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>失效點出在 T1 到 T2 之間：server 只認 v2，但 client 還在用 v1，這段窗口內的 request 都會 401。即使窗口只有幾秒，production 流量也可能產生大量錯誤。&lt;/p>
&lt;p>更糟的是「client 更新後忘了 reload process」這種情境 — 配置檔已改、但跑著的 server / worker process 還握著舊 secret 在記憶體裡、直到下次重啟才生效。窗口可能拉長到幾分鐘到幾小時。&lt;/p></description><content:encoded><![CDATA[<h2 id="shared-secret-rotation-這篇要解決什麼">Shared Secret Rotation 這篇要解決什麼</h2>
<p>Shared Secret rotation 的核心責任是讓 credential 換新時維持可用性、可追蹤性與可撤銷性。它表面上像是一行 SQL update，實際上牽涉 server 與多個 client 的切換時序：</p>
<ul>
<li>兩邊不同時切、就斷線</li>
<li>多 client 場景下、總有一兩個沒升級</li>
<li>緊急洩漏要立即撤換、同時控制服務中斷範圍</li>
<li>Rotation 中途失敗、舊新 secret 都不通</li>
</ul>
<p>這些是維運層的真實痛點。只說「定期 rotate your secret」只能描述目標，還需要雙密期、測試、監控、通知與回退流程，才能把 rotation 變成可執行的操作契約。</p>
<p>本文聚焦三件事：</p>
<ol>
<li><strong>雙密過渡期</strong>：怎麼讓 client 可以在任意時點切換、不會斷線</li>
<li><strong>自動化工具</strong>：AWS Secrets Manager / HashiCorp Vault / GCP Secret Manager 各自的 rotation 機制</li>
<li><strong>緊急 vs 定期</strong>：兩種流程的差異、何時用哪個</li>
</ol>
<blockquote>
<p><strong>本文位置</strong>：本文是 <a href="/blog/work-log/api-%E8%AA%8D%E8%AD%89%E7%9A%84%E4%B8%89%E5%B1%A4%E4%BF%A1%E4%BB%BB%E9%82%8A%E7%95%8C%E4%BD%BF%E7%94%A8%E8%80%85%E7%B3%BB%E7%B5%B1%E8%B7%A8%E7%B3%BB%E7%B5%B1-provisioning/" data-link-title="API 認證的三層信任邊界：使用者、系統、跨系統 Provisioning" data-link-desc="API 認證的信任邊界分層（Bearer Token / Shared Secret / Provisioning）：各層的洩漏後果與撤銷方式，以及混用造成的設計失效模式。">API 認證的三層信任邊界</a> Layer 2 的深入篇。主文聚焦「為什麼系統間要獨立 credential」、本文聚焦「Shared Secret 輪替的工程實務」。</p></blockquote>
<hr>
<h2 id="rotation-解決什麼威脅">Rotation 解決什麼威脅</h2>
<p>Rotation 是縮短 secret 暴露窗與清理殘留 access 的 lifecycle 控制。它降低三種具體威脅：</p>
<table>
  <thead>
      <tr>
          <th>威脅</th>
          <th>Rotation 怎麼緩解</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>未察覺的洩漏</strong></td>
          <td>Secret 可能已被外洩、定期換能限制攻擊者使用的時間窗</td>
      </tr>
      <tr>
          <td><strong>離職員工殘留 access</strong></td>
          <td>員工離職後系統 access 沒撤徹底、rotation 把該員工知道的 secret 變廢</td>
      </tr>
      <tr>
          <td><strong>長期暴露的 metadata</strong></td>
          <td>Secret 越久、log / backup / git history 留存的副本越多</td>
      </tr>
  </tbody>
</table>
<p>Rotation 本身有成本與風險，切換設計不完整時會造成斷線。所以實務目標是「在切換可控的前提下，選一個能接受的頻率」。</p>
<p>常見定期頻率：</p>
<table>
  <thead>
      <tr>
          <th>業界場景</th>
          <th>典型頻率</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>一般 SaaS</td>
          <td>90 天 / 180 天</td>
      </tr>
      <tr>
          <td>金融、醫療</td>
          <td>30 天 / 90 天</td>
      </tr>
      <tr>
          <td>高敏感（國防、政府）</td>
          <td>7 天 / 14 天、或事件觸發</td>
      </tr>
      <tr>
          <td>純內部、低風險</td>
          <td>半年 / 一年、或永不 rotate</td>
      </tr>
  </tbody>
</table>
<blockquote>
<p><strong>頻率取決於威脅模型與操作能力</strong>：NIST SP 800-63B 對多數場景認可 30-90 天足夠、過於激進的 rotation 反而提高出錯機率。7-14 天適用於合規條款明文要求或私鑰可硬體保護的場景；多數 SaaS 可以停在 30-180 天區間。</p></blockquote>
<p>「事件觸發才換」也有合理情境。純內部 cron job、secret 外流管道少、rotation 成本大於風險時，可以選擇以事件觸發取代固定排程；重點是留下 owner、inventory 與重新評估條件。</p>
<hr>
<h2 id="核心機制雙密過渡期dual-secret-rollover">核心機制：雙密過渡期（Dual-secret Rollover）</h2>
<h3 id="直接-atomic-切換的失效點">直接 atomic 切換的失效點</h3>
<p>最直覺的 rotation 流程是：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">T0: 兩邊都是 secret_v1
</span></span><span class="line"><span class="ln">2</span><span class="cl">T1: server 端換成 secret_v2
</span></span><span class="line"><span class="ln">3</span><span class="cl">T2: client 端換成 secret_v2</span></span></code></pre></div><p>失效點出在 T1 到 T2 之間：server 只認 v2，但 client 還在用 v1，這段窗口內的 request 都會 401。即使窗口只有幾秒，production 流量也可能產生大量錯誤。</p>
<p>更糟的是「client 更新後忘了 reload process」這種情境 — 配置檔已改、但跑著的 server / worker process 還握著舊 secret 在記憶體裡、直到下次重啟才生效。窗口可能拉長到幾分鐘到幾小時。</p>
<h3 id="解法server-端同時接受新舊兩把">解法：server 端同時接受新舊兩把</h3>
<p>雙密過渡期把 rotation 分成 3 個階段：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">T0：穩態
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">  server: [v1]
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">  client: [v1]
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">  狀態：v1 工作
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">T1：發新 secret、server 雙密期開始
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">  server: [v1, v2]   ← server 同時接受 v1 跟 v2
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">  client: [v1]
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">  狀態：兩個都 work、client 還沒切
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl">T2：通知 client 切到 v2
</span></span><span class="line"><span class="ln">12</span><span class="cl">  server: [v1, v2]
</span></span><span class="line"><span class="ln">13</span><span class="cl">  client: [v2]       ← client 升級、開始用 v2
</span></span><span class="line"><span class="ln">14</span><span class="cl">  狀態：v2 work、v1 也仍 work（過渡期）
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl">T3：確認所有 client 都切完、關閉 v1
</span></span><span class="line"><span class="ln">17</span><span class="cl">  server: [v2]       ← 移除 v1
</span></span><span class="line"><span class="ln">18</span><span class="cl">  client: [v2]
</span></span><span class="line"><span class="ln">19</span><span class="cl">  狀態：穩態、只 v1 失效</span></span></code></pre></div><p>關鍵在於 <strong>server 在 T1-T3 之間同時接受兩把</strong> — 不論 client 在這段期間用哪一把都能通過驗證。client 可以在自己的時程內升級、不需要跟 server 切換同步。</p>
<h3 id="雙密期的長度設計">雙密期的長度設計</h3>
<p>雙密期是一個可用性與暴露窗的取捨。兩把同時有效時，系統需要同時保護兩把 secret，也需要追蹤兩個版本的使用比例；時間拉太短會造成 client 來不及切換，時間拉太長會擴大舊 secret 的有效窗口。</p>
<p>設計建議：</p>
<table>
  <thead>
      <tr>
          <th>場景</th>
          <th>雙密期長度建議</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>純內部、可強制升級</td>
          <td>24-48 小時</td>
      </tr>
      <tr>
          <td>對外 client、需要溝通</td>
          <td>7-14 天</td>
      </tr>
      <tr>
          <td>大量第三方整合</td>
          <td>30-90 天 + 多次提醒</td>
      </tr>
      <tr>
          <td>緊急 rotation（已洩漏）</td>
          <td>盡量縮短、視覆蓋速度而定</td>
      </tr>
  </tbody>
</table>
<p>監控指標：在雙密期內、應該追蹤「用 v1 vs 用 v2 的 request 比例」 — 當 v1 比例降到 0%、且持續穩定一段時間後、才安全地關閉 v1。</p>
<h3 id="怎麼實作同時接受兩把">怎麼實作「同時接受兩把」</h3>
<p>實作模式有兩種：</p>
<h4 id="模式-aarray-比對">模式 A：array 比對</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="n">VALID_SECRETS</span> <span class="o">=</span> <span class="p">[</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;SHARED_SECRET_CURRENT&#39;</span><span class="p">],</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">    <span class="n">os</span><span class="o">.</span><span class="n">environ</span><span class="p">[</span><span class="s1">&#39;SHARED_SECRET_PREVIOUS&#39;</span><span class="p">],</span>  <span class="c1"># 可選、若在雙密期</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="p">]</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">def</span> <span class="nf">verify</span><span class="p">(</span><span class="n">received</span><span class="p">):</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">    <span class="k">for</span> <span class="n">secret</span> <span class="ow">in</span> <span class="n">VALID_SECRETS</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="k">if</span> <span class="ow">not</span> <span class="n">secret</span><span class="p">:</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">            <span class="k">continue</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">        <span class="k">if</span> <span class="n">hmac</span><span class="o">.</span><span class="n">compare_digest</span><span class="p">(</span><span class="n">secret</span><span class="p">,</span> <span class="n">received</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">            <span class="k">return</span> <span class="kc">True</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">    <span class="k">return</span> <span class="kc">False</span></span></span></code></pre></div><p>這個模式適合內部固定夥伴與少量服務，因為驗證邏輯簡單、沒有額外狀態。主要風險是兩把 secret 都要部署到 server，env var / config 變多，且每個 instance 都要確認讀到相同版本。</p>
<h4 id="模式-bsecret-store--version">模式 B：secret store + version</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">def</span> <span class="nf">verify</span><span class="p">(</span><span class="n">received</span><span class="p">):</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">    <span class="n">current_version</span> <span class="o">=</span> <span class="n">secret_store</span><span class="o">.</span><span class="n">get_version</span><span class="p">(</span><span class="s1">&#39;shared_secret&#39;</span><span class="p">,</span> <span class="s1">&#39;current&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="n">previous_version</span> <span class="o">=</span> <span class="n">secret_store</span><span class="o">.</span><span class="n">get_version</span><span class="p">(</span><span class="s1">&#39;shared_secret&#39;</span><span class="p">,</span> <span class="s1">&#39;previous&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="k">return</span> <span class="n">hmac</span><span class="o">.</span><span class="n">compare_digest</span><span class="p">(</span><span class="n">current_version</span><span class="p">,</span> <span class="n">received</span><span class="p">)</span> <span class="ow">or</span> \
</span></span><span class="line"><span class="ln">5</span><span class="cl">           <span class="n">hmac</span><span class="o">.</span><span class="n">compare_digest</span><span class="p">(</span><span class="n">previous_version</span><span class="p">,</span> <span class="n">received</span><span class="p">)</span></span></span></code></pre></div><p>這個模式適合對外 API 或 client 數量較多的系統，因為 secret 集中管理、版本狀態可查。主要風險是驗證流程依賴 secret store，需要設計 cache、fallback 與 store 失效時的行為。</p>
<p>對外開放 API 通常用模式 B、可結合 AWS Secrets Manager / Vault 等工具。內部固定夥伴系統可以用模式 A 起步、複雜後再遷移。</p>
<hr>
<h2 id="自動化-rotation-工具">自動化 Rotation 工具</h2>
<p>純手動 rotation 在 client 數量增加後不可持續 — 自動化工具的價值是把「<strong>產生新 secret → 部署到 server → 通知 client → 撤銷舊 secret</strong>」整套流程程式化。</p>
<h3 id="aws-secrets-manager">AWS Secrets Manager</h3>
<p>機制：</p>
<ul>
<li>註冊一個 <strong>Rotation Lambda</strong>、AWS 排程觸發（例如每 90 天）</li>
<li>Lambda 跑 4 階段流程：<code>createSecret</code> → <code>setSecret</code> → <code>testSecret</code> → <code>finishSecret</code></li>
<li>每個階段都有 retry、失敗會回到上一個穩態</li>
</ul>
<p>Lambda 範例責任分工：</p>
<table>
  <thead>
      <tr>
          <th>階段</th>
          <th>動作</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><code>createSecret</code></td>
          <td>產生新 secret、存到 AWSPENDING 版本</td>
      </tr>
      <tr>
          <td><code>setSecret</code></td>
          <td>把新 secret 部署到目標 service</td>
      </tr>
      <tr>
          <td><code>testSecret</code></td>
          <td>用新 secret 跑驗證 request</td>
      </tr>
      <tr>
          <td><code>finishSecret</code></td>
          <td>把 AWSPENDING 升級為 AWSCURRENT、舊版改為 AWSPREVIOUS</td>
      </tr>
  </tbody>
</table>
<p>雙密期天然存在：AWSCURRENT + AWSPREVIOUS 兩個 staging label 同時可讀。Client 在 rotation 進行中、可以拿到 AWSPREVIOUS 作為 fallback。</p>
<p>適合場景：AWS 生態系、目標 service 是 RDS / Redshift / DocumentDB（有 native rotation Lambda template）或自定義（custom Lambda）。</p>
<h3 id="hashicorp-vault">HashiCorp Vault</h3>
<p>Vault 有兩種 rotation 策略：</p>
<p><strong>Static Secrets + Rotation Periodic</strong>：傳統 shared secret、Vault 每 N 天自動換、puts 到 vault path、client poll 拿。</p>
<p><strong>Dynamic Secrets</strong>：Vault 不存 long-lived secret、每次 client 請求時臨時產生（DB credential、AWS IAM credential 等）、TTL 短（小時到天）、過期即廢。Dynamic secret 沒有 rotation 概念 — 因為每個 secret 都只活一小段時間、洩漏窗本來就有限。</p>
<table>
  <thead>
      <tr>
          <th>模式</th>
          <th>適合</th>
          <th>限制</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Static + Periodic</td>
          <td>跨組織 API、需可預測的 secret</td>
          <td>仍需 client 端處理雙密期</td>
      </tr>
      <tr>
          <td>Dynamic</td>
          <td>內部 service 互呼、DB access</td>
          <td>目標系統要支援 short-lived credential</td>
      </tr>
  </tbody>
</table>
<p>適合場景：multi-cloud、不想綁 AWS、需要 dynamic secret 跨多種 backend。</p>
<h3 id="gcp-secret-manager">GCP Secret Manager</h3>
<p>機制較簡單 — Secret Manager 提供 <strong>versioning</strong>、每個 secret 有多個 version、client 可指定要「latest」還是特定 version。</p>
<p>Rotation 流程通常自己實作（GCP 沒提供類似 AWS 的 Rotation Lambda template）：</p>
<ol>
<li><code>addSecretVersion(name, new_secret)</code> — 加新 version</li>
<li>部署到 server（server 同時讀 latest + previous）</li>
<li>通知 client / 等 client 升級</li>
<li><code>destroySecretVersion(name, old_version)</code> — 撤銷舊 version</li>
</ol>
<p>雙密期靠 client 端邏輯（同時試 latest 跟 previous）實現。</p>
<p>適合場景：GCP 生態系、自有 rotation 邏輯不想被 vendor opinion 綁住。</p>
<h3 id="三者比較">三者比較</h3>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>AWS Secrets Manager</th>
          <th>HashiCorp Vault</th>
          <th>GCP Secret Manager</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>排程觸發</td>
          <td>內建</td>
          <td>內建（periodic）</td>
          <td>不內建（自己排 Cloud Scheduler）</td>
      </tr>
      <tr>
          <td>雙密期支援</td>
          <td>AWSCURRENT / PREVIOUS labels</td>
          <td>Static 需自寫、Dynamic 不需</td>
          <td>Version-based</td>
      </tr>
      <tr>
          <td>Dynamic credential</td>
          <td>需 custom Lambda</td>
          <td>Native support</td>
          <td>不支援</td>
      </tr>
      <tr>
          <td>跨雲 / 跨 region</td>
          <td>AWS-only</td>
          <td>跨雲</td>
          <td>GCP-only</td>
      </tr>
      <tr>
          <td>維運成本</td>
          <td>低（managed）</td>
          <td>高（自管 Vault cluster）</td>
          <td>低（managed）</td>
      </tr>
  </tbody>
</table>
<h3 id="自建-rotation-系統的最小元件">自建 rotation 系統的最小元件</h3>
<p>小規模系統可以自建最小 rotation 元件，前提是 secret 系統本身也被視為敏感基礎設施。最小元件包含：</p>
<ol>
<li><strong>Secret 存儲</strong>：DB table <code>secrets(id, version, value, created_at, retired_at)</code></li>
<li><strong>發放 API</strong>：<code>GET /secrets/current</code> 回 latest active version</li>
<li><strong>驗證邏輯</strong>：應用層讀 current + previous 兩個 active version</li>
<li><strong>排程</strong>：cron job 觸發 <code>rotate(secret_name)</code> — 產新 version、標記舊版 retired、設 retired_at</li>
<li><strong>監控</strong>：log 每個 version 被驗證的次數、舊版降到 0 後關閉</li>
</ol>
<p>這個方案適合內部小規模系統。判斷是否可行時，要同步檢查 DB encryption at rest、access log、權限分離與備援；否則自建系統可能把 rotation 風險轉移成 secret store 風險。</p>
<hr>
<h2 id="緊急-rotation洩漏發生時的流程">緊急 rotation：洩漏發生時的流程</h2>
<h3 id="跟定期-rotation-的差異">跟定期 rotation 的差異</h3>
<p>定期 rotation 目標是「<strong>不中斷服務</strong>」、所以雙密期長、給 client 充分時間切換。</p>
<p>緊急 rotation 目標是「<strong>最快讓舊 secret 失效</strong>」 — 即使犧牲部分可用性也要立刻撤銷。兩者流程完全不同：</p>
<table>
  <thead>
      <tr>
          <th>維度</th>
          <th>定期 rotation</th>
          <th>緊急 rotation</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>觸發</td>
          <td>排程</td>
          <td>事件（洩漏、員工離職、被盜）</td>
      </tr>
      <tr>
          <td>優先級</td>
          <td>不中斷服務</td>
          <td>立即撤銷舊 secret</td>
      </tr>
      <tr>
          <td>雙密期</td>
          <td>長（天到月）</td>
          <td>短（小時、甚至不容忍）</td>
      </tr>
      <tr>
          <td>通知方式</td>
          <td>文件、email、提早提醒</td>
          <td>直接 push、必要時打電話</td>
      </tr>
      <tr>
          <td>Client 不升級</td>
          <td>等</td>
          <td>強制斷線</td>
      </tr>
  </tbody>
</table>
<h3 id="緊急-rotation-流程模板">緊急 rotation 流程模板</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln"> 1</span><span class="cl">T0: 偵測或回報洩漏
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">   ↓
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">T0+0~15min: 評估
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">   - 確認洩漏範圍（哪些 secret、影響哪些 client）
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">   - 評估「立即斷舊 secret」對 production 的影響
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">   - 決定是否走緊急流程 vs 縮短的定期流程
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">   ↓
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">T0+15min~1hr: 部署新 secret
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">   - 產生新 secret
</span></span><span class="line"><span class="ln">10</span><span class="cl">   - 部署到 server、開啟雙密期
</span></span><span class="line"><span class="ln">11</span><span class="cl">   - 主動 push 新 secret 給已知 client（內部用 channel 通知、外部 client email + dashboard）
</span></span><span class="line"><span class="ln">12</span><span class="cl">   ↓
</span></span><span class="line"><span class="ln">13</span><span class="cl">T0+1hr~24hr: 強制切換
</span></span><span class="line"><span class="ln">14</span><span class="cl">   - 監控用舊 secret 的 request 比例
</span></span><span class="line"><span class="ln">15</span><span class="cl">   - 跟未升級的 client 個別聯繫
</span></span><span class="line"><span class="ln">16</span><span class="cl">   - 視情境設「強制斷線時間點」並提早警告
</span></span><span class="line"><span class="ln">17</span><span class="cl">   ↓
</span></span><span class="line"><span class="ln">18</span><span class="cl">T0+24hr~72hr: 撤銷舊 secret
</span></span><span class="line"><span class="ln">19</span><span class="cl">   - 即使仍有 client 在用舊 secret、也斷
</span></span><span class="line"><span class="ln">20</span><span class="cl">   - 接受部分服務中斷、優先於 secret 繼續暴露
</span></span><span class="line"><span class="ln">21</span><span class="cl">   ↓
</span></span><span class="line"><span class="ln">22</span><span class="cl">事後: 檢討
</span></span><span class="line"><span class="ln">23</span><span class="cl">   - 洩漏怎麼發生（log 翻查、code audit）
</span></span><span class="line"><span class="ln">24</span><span class="cl">   - 偵測機制能否更快
</span></span><span class="line"><span class="ln">25</span><span class="cl">   - 流程哪裡可以改進</span></span></code></pre></div><p>關鍵權衡：<strong>「斷線成本」vs「secret 繼續暴露的損害」</strong>。對金融、醫療等高敏感場景、寧可斷線；對非關鍵內部服務、可能可以拉長雙密期。沒有通用答案、要場景判斷。</p>
<h3 id="偵測洩漏的訊號">偵測洩漏的訊號</h3>
<p>緊急 rotation 的前提是「<strong>知道洩漏發生了</strong>」 — 但很多洩漏直到攻擊者開始用 secret 才被發現、間隔可能是幾個月。</p>
<p>主動偵測手段：</p>
<table>
  <thead>
      <tr>
          <th>訊號</th>
          <th>怎麼偵測</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Secret 出現在公開 repo</strong></td>
          <td>GitHub Secret Scanning、GitGuardian、TruffleHog</td>
      </tr>
      <tr>
          <td><strong>異常使用 pattern</strong></td>
          <td>異常時間、異常 IP、異常 request 量</td>
      </tr>
      <tr>
          <td><strong>多個 IP 同時用同一 secret</strong></td>
          <td>應用層 log 分析、SIEM 工具</td>
      </tr>
      <tr>
          <td><strong>離職員工觸發 access</strong></td>
          <td>跟 HR 系統整合的 access review</td>
      </tr>
  </tbody>
</table>
<p>把這些設成監控告警、是降低「洩漏到察覺」窗口的關鍵。</p>
<hr>
<h2 id="多-client-的同步難題">多 client 的同步難題</h2>
<h3 id="問題本質client-不在你的控制範圍">問題本質：client 不在你的控制範圍</h3>
<p>對外開放 API 的場景，Shared Secret 散落在第三方 client 的 server。Rotation 因此變成「怎麼讓第三方在你的時程內配合」的協調問題，不只是技術問題。</p>
<p>常見痛點：</p>
<ul>
<li>通知 email 進垃圾匣、第三方沒看到</li>
<li>第三方的工程師離職、新接手者不知道有 rotation 排程</li>
<li>第三方的 deploy 流程慢、提前一週通知還是來不及</li>
<li>第三方根本不在線（小型客戶、半年才用一次 API）</li>
</ul>
<h3 id="grace-period-設計">Grace period 設計</h3>
<p>Grace period 是「<strong>舊 secret 撤銷後、給 client 緩衝期重新申請</strong>」的機制。比硬性 deadline 更彈性：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">T0: 公告 rotation、雙密期開始
</span></span><span class="line"><span class="ln">2</span><span class="cl">T0+30天: 雙密期結束、舊 secret 撤銷
</span></span><span class="line"><span class="ln">3</span><span class="cl">T0+30~60天: Grace period
</span></span><span class="line"><span class="ln">4</span><span class="cl">   - 用舊 secret 的 request 回 410 Gone（或 401 + 可讀的 error code，視 API 慣例）+ 連結到 &#34;secret expired&#34; 頁
</span></span><span class="line"><span class="ln">5</span><span class="cl">   - 提供 self-service 重設 secret 的流程
</span></span><span class="line"><span class="ln">6</span><span class="cl">   - 仍然斷線、但 client 知道怎麼自己救
</span></span><span class="line"><span class="ln">7</span><span class="cl">T0+60天: 完全關閉、需要重新申請新 client account</span></span></code></pre></div><p>Grace period 的關鍵是在拒絕舊 secret 的同時，提供足夠資訊讓 client 自助修復。判讀訊號是錯誤回應是否能指出 secret 已過期、去哪裡重設、何時完全關閉；若只回無上下文的 401，client 仍會被導向錯誤排障路徑。</p>
<h3 id="強制升級的工具">強制升級的工具</h3>
<p>對於必須統一升級的場景（例如安全合規要求）、有幾種強制手段：</p>
<table>
  <thead>
      <tr>
          <th>手段</th>
          <th>怎麼運作</th>
          <th>適合</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>HTTP 410 + 訊息</strong></td>
          <td>舊 secret 不只 401、回 410 + 升級指引</td>
          <td>一般對外 API</td>
      </tr>
      <tr>
          <td><strong>暫時降級而非斷線</strong></td>
          <td>舊 secret 仍 work、但限流 / 降級權限</td>
          <td>重要 client、寧可降級不要斷</td>
      </tr>
      <tr>
          <td><strong>個別溝通 + 客製化期限</strong></td>
          <td>對大 client 個別協商 deadline</td>
          <td>高價值合作夥伴</td>
      </tr>
      <tr>
          <td><strong>合約強制條款</strong></td>
          <td>簽約時就寫清楚「Y 年內必須能配合 rotation」</td>
          <td>B2B SaaS</td>
      </tr>
  </tbody>
</table>
<hr>
<h2 id="失敗模式與緩解">失敗模式與緩解</h2>
<h3 id="失敗-1雙密期太短client-沒升級">失敗 1：雙密期太短、client 沒升級</h3>
<p><strong>症狀</strong>：rotation 後第二週，某 client 開始 401，才發現他沒收到通知或尚未升級。</p>
<p><strong>緩解</strong>：</p>
<ul>
<li>雙密期至少覆蓋「最大已知 client 的 deploy cycle」</li>
<li>雙密期內監控「用舊 secret 的 client 數量」、降到 0 才關</li>
<li>緊急 rotation 例外、要事先評估可接受的斷線成本</li>
</ul>
<h3 id="失敗-2rotation-中斷新舊都不通">失敗 2：rotation 中斷、新舊都不通</h3>
<p><strong>症狀</strong>：deploy 新 secret 到 server 中途失敗、一半 server 是新、一半是舊 — request 隨機 401。</p>
<p><strong>緩解</strong>：</p>
<ul>
<li>部署用 rolling update、確認每個 instance 都生效再進下一個</li>
<li>部署前確認「server 是雙密 mode」、即使部署到一半也能容錯</li>
<li>保留快速 rollback 機制（10 分鐘內能 revert）</li>
</ul>
<h3 id="失敗-3新-secret-沒測通就上線">失敗 3：新 secret 沒測通就上線</h3>
<p><strong>症狀</strong>：新 secret 部署完、第一個 client 試了發現格式不對 / 長度限制 / 特殊字元編碼問題、大量 401。</p>
<p><strong>緩解</strong>：</p>
<ul>
<li>Rotation 流程加 <code>testSecret</code> 階段（AWS Lambda 模式）— 切換前用新 secret 跑一輪驗證 request</li>
<li>Staging 環境先跑完整 rotation 流程、再上 prod</li>
<li>新 secret 的 format 跟舊一致（同長度、同字元集）、減少 client 端的 parsing 風險</li>
</ul>
<h3 id="失敗-4rotation-缺少-ownersecret-長期暴露">失敗 4：Rotation 缺少 owner、secret 長期暴露</h3>
<p><strong>症狀</strong>：上次 rotate 已是 3 年前，原本的負責人離職，接手者不知道有這個 secret 存在。</p>
<p><strong>緩解</strong>：</p>
<ul>
<li>Secret 管理工具強制設 <code>expires_at</code>、過期前自動提醒</li>
<li>Inventory 表：所有 production secret 列管、定期 audit</li>
<li>Rotation 排程進 calendar、輪值負責</li>
</ul>
<h3 id="失敗-5rotation-後-audit-log-沒更新">失敗 5：rotation 後 audit log 沒更新</h3>
<p><strong>症狀</strong>：洩漏發生、要追「這個 secret 給過誰用」、但 audit log 只記了「secret 被用了」、沒記版本、無法區分新舊。</p>
<p><strong>緩解</strong>：</p>
<ul>
<li>Audit log 記 secret version、不只 secret 本身</li>
<li>Rotation 事件本身也要 log（誰、什麼時候、為什麼）</li>
<li>Log 保留期跨多次 rotation cycle、避免歷史追溯斷鏈</li>
</ul>
<hr>
<h2 id="收尾">收尾</h2>
<p>Shared Secret rotation 的本質是<strong>有意識管理 secret 的 lifecycle</strong>。從發放、儲存、輪替到撤銷，每個階段都有對應的工程設計與監控訊號。</p>
<p>幾個核心原則：</p>
<ol>
<li><strong>雙密過渡期是底層機制</strong> — 任何 rotation 方案都建立在「server 能同時接受兩把」之上</li>
<li><strong>自動化工具值得投資</strong> — 規模小用 secret manager（AWS / Vault / GCP），規模大可以自建，避免停在純手動</li>
<li><strong>定期跟緊急是兩套流程</strong> — 定期重不中斷，緊急重立刻撤，流程、通知與回退標準要分開</li>
<li><strong>多 client 是協調問題</strong> — 比技術問題難解、grace period + 強制升級工具是常用解法</li>
<li><strong>失敗模式要演練</strong> — production 第一次跑 rotation 前，先在 staging 演練完整流程與回退路徑</li>
</ol>
<p>延伸閱讀：</p>
<ul>
<li><a href="/blog/work-log/api-%E8%AA%8D%E8%AD%89%E7%9A%84%E4%B8%89%E5%B1%A4%E4%BF%A1%E4%BB%BB%E9%82%8A%E7%95%8C%E4%BD%BF%E7%94%A8%E8%80%85%E7%B3%BB%E7%B5%B1%E8%B7%A8%E7%B3%BB%E7%B5%B1-provisioning/" data-link-title="API 認證的三層信任邊界：使用者、系統、跨系統 Provisioning" data-link-desc="API 認證的信任邊界分層（Bearer Token / Shared Secret / Provisioning）：各層的洩漏後果與撤銷方式，以及混用造成的設計失效模式。">API 認證的三層信任邊界</a> — 本文的主篇、Shared Secret 在「Layer 2 系統層」的位置</li>
<li><a href="/blog/work-log/laravel-sanctum-%E7%9A%84-bearer-token-%E8%A8%AD%E8%A8%88%E5%89%96%E6%9E%90pksecret-%E7%82%BA%E4%BB%80%E9%BA%BC%E9%80%99%E6%A8%A3%E8%A8%AD%E8%A8%88/" data-link-title="Laravel Sanctum 的 Bearer Token 設計剖析：{PK}|{secret} 為什麼這樣設計" data-link-desc="Laravel Sanctum `{PK}|{secret}` 格式的設計理由、hash 儲存取捨、constant-time 比對位置，以及跟 GitHub PAT、Stripe API Key 的差異。">Laravel Sanctum 的 Bearer Token 設計剖析</a> — Layer 1 使用者 token 的儲存原則（hash + constant-time）也適用於 Layer 2</li>
<li><a href="/blog/work-log/mtls-%E5%AF%A6%E9%9A%9B%E6%80%8E%E9%BA%BC%E8%A8%AD%E5%AE%9A%E8%88%87%E9%81%8B%E7%B6%ADca-%E9%9A%8E%E5%B1%A4%E6%86%91%E8%AD%89%E7%94%9F%E5%91%BD%E9%80%B1%E6%9C%9F%E6%92%A4%E9%8A%B7%E6%A9%9F%E5%88%B6/" data-link-title="mTLS 實際怎麼設定與運維：CA 階層、憑證生命週期、撤銷機制" data-link-desc="mTLS 落地的運維決策（CA 階層、憑證儲存、撤銷機制）與基礎設施整合（nginx / envoy / service mesh），以及跟 API Key / OAuth 的成本與安全取捨。">mTLS 實際怎麼設定與運維</a> — 不用 shared secret 的另一條路、憑證 lifecycle 跟 secret lifecycle 的對照</li>
</ul>
]]></content:encoded></item></channel></rss>