<?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>Boundary on Tarragon</title><link>https://tarrragon.github.io/blog/tags/boundary/</link><description>Recent content in Boundary on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/boundary/index.xml" rel="self" type="application/rss+xml"/><item><title>Mock 邊界判斷決策表</title><link>https://tarrragon.github.io/blog/testing/05-test-design-judgment/mock-boundary-decision/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/testing/05-test-design-judgment/mock-boundary-decision/</guid><description>&lt;p>Mock 的適用範圍由它模擬的層級決定。Mock 忠實模擬 API 層的契約（方法簽名、參數型別），但無法模擬協議層的語意差異和環境層的行為差異。判斷「這個 test 用 mock 夠不夠」的依據是：test 要驗證的行為發生在哪一層。&lt;/p>
&lt;h2 id="決策依據">決策依據&lt;/h2>
&lt;h3 id="mock-夠用的場景">Mock 夠用的場景&lt;/h3>
&lt;p>Test 驗證的行為完全在程式碼內部 — 函式邏輯、狀態機轉換、資料轉換、錯誤處理分支。這些行為不依賴外部服務的協議細節，mock 提供的 API 層模擬已經足夠。&lt;/p>
&lt;p>判斷問題：&lt;strong>如果把 mock 替換成真實服務，test 的斷言結果會不會改變？&lt;/strong> 如果不會改變，mock 夠用。&lt;/p>
&lt;p>例：&lt;code>ConnectionManager&lt;/code> 收到 error 後是否正確切換到 error 狀態 — 不管 error 來自 mock 還是真實 WebSocket，狀態機邏輯相同。Mock 夠用。&lt;/p>
&lt;h3 id="mock-不夠的場景">Mock 不夠的場景&lt;/h3>
&lt;p>Test 要驗證的行為涉及外部服務的協議行為 — frame type 差異、認證流程、編碼格式、逾時行為。Mock 的 API 層模擬跳過了這些行為，test 通過不代表真實互動也通過。&lt;/p>
&lt;p>判斷問題：&lt;strong>Mock 跳過了外部服務的哪些步驟？這些步驟的行為是否影響 test 要驗證的結果？&lt;/strong> 如果是，需要 protocol integration test（&lt;a href="https://tarrragon.github.io/blog/testing/03-protocol-integration-test/" data-link-title="模組三：協議整合測試" data-link-desc="對真實服務驗證 WebSocket / gRPC / HTTP 協議契約 — unit test 和 E2E test 之間的一層">testing 模組三&lt;/a>）。&lt;/p>
&lt;p>例：&lt;code>sendData()&lt;/code> 發送鍵盤輸入 — mock 的 &lt;code>sink.add(dynamic)&lt;/code> 接受任何型別，但真實 &lt;code>IOWebSocketChannel&lt;/code> 對 &lt;code>String&lt;/code> 和 &lt;code>Uint8List&lt;/code> 產生不同 frame type。Mock 不夠。&lt;/p>
&lt;h2 id="決策表">決策表&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>驗證對象&lt;/th>
 &lt;th>Mock 夠用？&lt;/th>
 &lt;th>理由&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>函式回傳值&lt;/td>
 &lt;td>夠&lt;/td>
 &lt;td>回傳值只依賴程式碼邏輯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>狀態機轉換&lt;/td>
 &lt;td>夠&lt;/td>
 &lt;td>轉換邏輯在程式碼內部&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>錯誤處理分支&lt;/td>
 &lt;td>夠&lt;/td>
 &lt;td>error 來源不影響處理邏輯&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>資料格式轉換&lt;/td>
 &lt;td>夠&lt;/td>
 &lt;td>轉換邏輯在程式碼內部&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>連線建立成功/失敗&lt;/td>
 &lt;td>視情況&lt;/td>
 &lt;td>如果只驗證「收到成功/失敗後做什麼」→ 夠&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>認證流程完整性&lt;/td>
 &lt;td>不夠&lt;/td>
 &lt;td>mock 可能跳過認證步驟&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>資料編碼格式&lt;/td>
 &lt;td>不夠&lt;/td>
 &lt;td>mock 不區分編碼差異（text vs binary）&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>逾時行為&lt;/td>
 &lt;td>不夠&lt;/td>
 &lt;td>mock 的回應時間和真實服務不同&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>多步驟協議流程&lt;/td>
 &lt;td>不夠&lt;/td>
 &lt;td>mock 可能簡化多步驟為單步&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>並行/競爭條件&lt;/td>
 &lt;td>不夠&lt;/td>
 &lt;td>mock 通常同步回應，無法模擬真實的並行行為&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="灰色地帶的判斷">灰色地帶的判斷&lt;/h2>
&lt;p>有些 test 介於「mock 夠用」和「mock 不夠」之間。例如驗證「連線失敗時顯示 error 訊息」— 觸發失敗的方式可以是 mock 回傳 error（驗證顯示邏輯），也可以是真實服務拒絕連線（驗證真實失敗場景的處理）。&lt;/p>
&lt;p>灰色地帶的判斷策略是：用 mock test 驗證「收到 error 後的處理邏輯」，用 protocol integration test 驗證「真實服務在什麼情況下回傳 error」。兩層 test 各自回答不同問題，不互相替代（&lt;a href="https://tarrragon.github.io/blog/testing/01-test-strategy-layers/three-layer-definition/" data-link-title="三層定義與職責表" data-link-desc="Unit Test / Protocol Integration Test / Screen State Test 各層職責、驗證目標與盲區的完整論述">testing 模組一 三層定義&lt;/a>）。&lt;/p>
&lt;p>Mock 邊界確定後，另一個影響 test 有效性的因素是&lt;a href="https://tarrragon.github.io/blog/testing/05-test-design-judgment/test-data-representativeness/" data-link-title="Test data 代表性" data-link-desc="手寫 vs 錄製 vs 生成三種測試資料來源 — 測試資料的代表性是一個隱性假設，決定了 test 能發現什麼問題">測試資料的代表性&lt;/a> — 測試輸入能否反映真實環境。Mock 遮蔽的結構性原因在 &lt;a href="https://tarrragon.github.io/blog/testing/01-test-strategy-layers/mock-masking-mechanism/" data-link-title="Mock 遮蔽機制分析" data-link-desc="Mock 在 API 層、協議層、環境層之間製造的結構性盲區 — 斷裂點在哪、為什麼 mock 無法也不應該模擬協議行為">testing 模組一 Mock 遮蔽機制分析&lt;/a>中完整展開，判定需要真實服務後的成本評估見 &lt;a href="https://tarrragon.github.io/blog/testing/03-protocol-integration-test/cost-judgment/" data-link-title="成本判斷表" data-link-desc="什麼時候值得寫 protocol integration test、什麼時候用 contract test 或實機測試替代 — 根據服務啟動成本和協議複雜度判斷">testing 模組三 成本判斷表&lt;/a>。&lt;/p></description><content:encoded><![CDATA[<p>Mock 的適用範圍由它模擬的層級決定。Mock 忠實模擬 API 層的契約（方法簽名、參數型別），但無法模擬協議層的語意差異和環境層的行為差異。判斷「這個 test 用 mock 夠不夠」的依據是：test 要驗證的行為發生在哪一層。</p>
<h2 id="決策依據">決策依據</h2>
<h3 id="mock-夠用的場景">Mock 夠用的場景</h3>
<p>Test 驗證的行為完全在程式碼內部 — 函式邏輯、狀態機轉換、資料轉換、錯誤處理分支。這些行為不依賴外部服務的協議細節，mock 提供的 API 層模擬已經足夠。</p>
<p>判斷問題：<strong>如果把 mock 替換成真實服務，test 的斷言結果會不會改變？</strong> 如果不會改變，mock 夠用。</p>
<p>例：<code>ConnectionManager</code> 收到 error 後是否正確切換到 error 狀態 — 不管 error 來自 mock 還是真實 WebSocket，狀態機邏輯相同。Mock 夠用。</p>
<h3 id="mock-不夠的場景">Mock 不夠的場景</h3>
<p>Test 要驗證的行為涉及外部服務的協議行為 — frame type 差異、認證流程、編碼格式、逾時行為。Mock 的 API 層模擬跳過了這些行為，test 通過不代表真實互動也通過。</p>
<p>判斷問題：<strong>Mock 跳過了外部服務的哪些步驟？這些步驟的行為是否影響 test 要驗證的結果？</strong> 如果是，需要 protocol integration test（<a href="/blog/testing/03-protocol-integration-test/" data-link-title="模組三：協議整合測試" data-link-desc="對真實服務驗證 WebSocket / gRPC / HTTP 協議契約 — unit test 和 E2E test 之間的一層">testing 模組三</a>）。</p>
<p>例：<code>sendData()</code> 發送鍵盤輸入 — mock 的 <code>sink.add(dynamic)</code> 接受任何型別，但真實 <code>IOWebSocketChannel</code> 對 <code>String</code> 和 <code>Uint8List</code> 產生不同 frame type。Mock 不夠。</p>
<h2 id="決策表">決策表</h2>
<table>
  <thead>
      <tr>
          <th>驗證對象</th>
          <th>Mock 夠用？</th>
          <th>理由</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>函式回傳值</td>
          <td>夠</td>
          <td>回傳值只依賴程式碼邏輯</td>
      </tr>
      <tr>
          <td>狀態機轉換</td>
          <td>夠</td>
          <td>轉換邏輯在程式碼內部</td>
      </tr>
      <tr>
          <td>錯誤處理分支</td>
          <td>夠</td>
          <td>error 來源不影響處理邏輯</td>
      </tr>
      <tr>
          <td>資料格式轉換</td>
          <td>夠</td>
          <td>轉換邏輯在程式碼內部</td>
      </tr>
      <tr>
          <td>連線建立成功/失敗</td>
          <td>視情況</td>
          <td>如果只驗證「收到成功/失敗後做什麼」→ 夠</td>
      </tr>
      <tr>
          <td>認證流程完整性</td>
          <td>不夠</td>
          <td>mock 可能跳過認證步驟</td>
      </tr>
      <tr>
          <td>資料編碼格式</td>
          <td>不夠</td>
          <td>mock 不區分編碼差異（text vs binary）</td>
      </tr>
      <tr>
          <td>逾時行為</td>
          <td>不夠</td>
          <td>mock 的回應時間和真實服務不同</td>
      </tr>
      <tr>
          <td>多步驟協議流程</td>
          <td>不夠</td>
          <td>mock 可能簡化多步驟為單步</td>
      </tr>
      <tr>
          <td>並行/競爭條件</td>
          <td>不夠</td>
          <td>mock 通常同步回應，無法模擬真實的並行行為</td>
      </tr>
  </tbody>
</table>
<h2 id="灰色地帶的判斷">灰色地帶的判斷</h2>
<p>有些 test 介於「mock 夠用」和「mock 不夠」之間。例如驗證「連線失敗時顯示 error 訊息」— 觸發失敗的方式可以是 mock 回傳 error（驗證顯示邏輯），也可以是真實服務拒絕連線（驗證真實失敗場景的處理）。</p>
<p>灰色地帶的判斷策略是：用 mock test 驗證「收到 error 後的處理邏輯」，用 protocol integration test 驗證「真實服務在什麼情況下回傳 error」。兩層 test 各自回答不同問題，不互相替代（<a href="/blog/testing/01-test-strategy-layers/three-layer-definition/" data-link-title="三層定義與職責表" data-link-desc="Unit Test / Protocol Integration Test / Screen State Test 各層職責、驗證目標與盲區的完整論述">testing 模組一 三層定義</a>）。</p>
<p>Mock 邊界確定後，另一個影響 test 有效性的因素是<a href="/blog/testing/05-test-design-judgment/test-data-representativeness/" data-link-title="Test data 代表性" data-link-desc="手寫 vs 錄製 vs 生成三種測試資料來源 — 測試資料的代表性是一個隱性假設，決定了 test 能發現什麼問題">測試資料的代表性</a> — 測試輸入能否反映真實環境。Mock 遮蔽的結構性原因在 <a href="/blog/testing/01-test-strategy-layers/mock-masking-mechanism/" data-link-title="Mock 遮蔽機制分析" data-link-desc="Mock 在 API 層、協議層、環境層之間製造的結構性盲區 — 斷裂點在哪、為什麼 mock 無法也不應該模擬協議行為">testing 模組一 Mock 遮蔽機制分析</a>中完整展開，判定需要真實服務後的成本評估見 <a href="/blog/testing/03-protocol-integration-test/cost-judgment/" data-link-title="成本判斷表" data-link-desc="什麼時候值得寫 protocol integration test、什麼時候用 contract test 或實機測試替代 — 根據服務啟動成本和協議複雜度判斷">testing 模組三 成本判斷表</a>。</p>
]]></content:encoded></item><item><title>Protocol integration test 定義</title><link>https://tarrragon.github.io/blog/testing/03-protocol-integration-test/definition-and-boundary/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/testing/03-protocol-integration-test/definition-and-boundary/</guid><description>&lt;p>&lt;a href="https://tarrragon.github.io/blog/testing/knowledge-cards/protocol-integration-test/" data-link-title="Protocol Integration Test" data-link-desc="驗證程式碼和真實外部服務之間的協議互動是否正確的 test 層級">Protocol integration test&lt;/a> 驗證的是程式碼和真實外部服務之間的協議互動 — 連線方式、認證流程、資料編碼、回應格式。它和 unit test 的差別是不用 mock，和 E2E test 的差別是不經過 UI。&lt;/p>
&lt;h2 id="三種-test-的邊界">三種 test 的邊界&lt;/h2>
&lt;h3 id="unit-test">Unit test&lt;/h3>
&lt;p>驗證程式碼邏輯。外部依賴全部用 mock 替代。斷言對象是函式的回傳值、狀態變化、例外拋出。&lt;/p>
&lt;p>Unit test 無法驗證的：程式碼和真實外部服務之間的行為差異（mock 遮蔽了這些差異，見 &lt;a href="https://tarrragon.github.io/blog/testing/01-test-strategy-layers/mock-masking-mechanism/" data-link-title="Mock 遮蔽機制分析" data-link-desc="Mock 在 API 層、協議層、環境層之間製造的結構性盲區 — 斷裂點在哪、為什麼 mock 無法也不應該模擬協議行為">Mock 遮蔽機制分析&lt;/a>）。&lt;/p>
&lt;h3 id="protocol-integration-test">Protocol integration test&lt;/h3>
&lt;p>驗證程式碼和真實服務的協議互動。不用 mock — 對真實的服務實例發送請求、觀察真實的回應。不經過 UI — 直接呼叫 client 端的連線函式或 HTTP client。&lt;/p>
&lt;p>Protocol integration test 驗證的是：連線能否建立、認證流程是否正確、發送的資料格式是否被接受、回應是否符合預期。&lt;/p>
&lt;h3 id="e2e-test">E2E test&lt;/h3>
&lt;p>驗證完整的使用者操作流程。從 UI 操作開始（點擊按鈕），經過 client 端邏輯，到達真實服務，再回到 UI 顯示結果。&lt;/p>
&lt;p>E2E test 的覆蓋範圍最廣但成本最高 — 需要啟動 app、操作 UI、等待網路回應、斷言 UI 狀態。E2E test 通常執行慢、不穩定（UI 動畫、網路延遲、裝置狀態影響結果）。&lt;/p>
&lt;h2 id="protocol-integration-test-的定位">Protocol integration test 的定位&lt;/h2>
&lt;p>Protocol integration test 填補 unit test 和 E2E test 之間的空隙。Unit test 覆蓋程式碼邏輯，E2E test 覆蓋端到端流程，protocol integration test 覆蓋「程式碼和外部服務的互動」這個特定層。&lt;/p>
&lt;p>這一層的 test 用程式碼直接呼叫 client 端的連線函式（跳過 UI），對真實的服務實例執行操作（跳過 mock），然後斷言服務的回應是否符合協議規格。&lt;/p>
&lt;p>以 app_tunnel 為例，一個 protocol integration test 的結構：&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">1. 啟動本機 ttyd 服務
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">2. 用 IOWebSocketChannel 連線到 ttyd
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">3. 發送 auth token JSON frame
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">4. 斷言收到 terminal output
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">5. 發送 Uint8List 鍵盤輸入
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">6. 斷言 ttyd 沒有回應（binary frame 被忽略）
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">7. 發送 String 鍵盤輸入
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">8. 斷言 ttyd 有回應（text frame 被處理）&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>這個 test 不需要 Flutter UI、不需要 FakeWebSocketChannel，直接驗證「我的程式碼送出的資料，真實 ttyd 是否正確處理」。&lt;/p>
&lt;p>以 WebSocket 為例的具體實作在 &lt;a href="https://tarrragon.github.io/blog/testing/03-protocol-integration-test/websocket-protocol-test/" data-link-title="WebSocket 協議測試實作" data-link-desc="對真實 ttyd 驗證 frame type 和 auth handshake — 從 T.C1 和 T.C2 的教訓推導出的 protocol integration test 設計">WebSocket 協議測試實作&lt;/a>中展開。在投入建置之前，用&lt;a href="https://tarrragon.github.io/blog/testing/03-protocol-integration-test/cost-judgment/" data-link-title="成本判斷表" data-link-desc="什麼時候值得寫 protocol integration test、什麼時候用 contract test 或實機測試替代 — 根據服務啟動成本和協議複雜度判斷">成本判斷表&lt;/a>評估服務啟動成本和協議複雜度是否值得這一層 test。Protocol integration test 和 mock test 的分工邊界回到 &lt;a href="https://tarrragon.github.io/blog/testing/01-test-strategy-layers/" data-link-title="模組一：測試策略分層" data-link-desc="Unit / Protocol Integration / Screen State 三層測試各自的職責、盲區和判斷原則">testing 模組一 測試策略分層&lt;/a>的三層框架。&lt;/p></description><content:encoded><![CDATA[<p><a href="/blog/testing/knowledge-cards/protocol-integration-test/" data-link-title="Protocol Integration Test" data-link-desc="驗證程式碼和真實外部服務之間的協議互動是否正確的 test 層級">Protocol integration test</a> 驗證的是程式碼和真實外部服務之間的協議互動 — 連線方式、認證流程、資料編碼、回應格式。它和 unit test 的差別是不用 mock，和 E2E test 的差別是不經過 UI。</p>
<h2 id="三種-test-的邊界">三種 test 的邊界</h2>
<h3 id="unit-test">Unit test</h3>
<p>驗證程式碼邏輯。外部依賴全部用 mock 替代。斷言對象是函式的回傳值、狀態變化、例外拋出。</p>
<p>Unit test 無法驗證的：程式碼和真實外部服務之間的行為差異（mock 遮蔽了這些差異，見 <a href="/blog/testing/01-test-strategy-layers/mock-masking-mechanism/" data-link-title="Mock 遮蔽機制分析" data-link-desc="Mock 在 API 層、協議層、環境層之間製造的結構性盲區 — 斷裂點在哪、為什麼 mock 無法也不應該模擬協議行為">Mock 遮蔽機制分析</a>）。</p>
<h3 id="protocol-integration-test">Protocol integration test</h3>
<p>驗證程式碼和真實服務的協議互動。不用 mock — 對真實的服務實例發送請求、觀察真實的回應。不經過 UI — 直接呼叫 client 端的連線函式或 HTTP client。</p>
<p>Protocol integration test 驗證的是：連線能否建立、認證流程是否正確、發送的資料格式是否被接受、回應是否符合預期。</p>
<h3 id="e2e-test">E2E test</h3>
<p>驗證完整的使用者操作流程。從 UI 操作開始（點擊按鈕），經過 client 端邏輯，到達真實服務，再回到 UI 顯示結果。</p>
<p>E2E test 的覆蓋範圍最廣但成本最高 — 需要啟動 app、操作 UI、等待網路回應、斷言 UI 狀態。E2E test 通常執行慢、不穩定（UI 動畫、網路延遲、裝置狀態影響結果）。</p>
<h2 id="protocol-integration-test-的定位">Protocol integration test 的定位</h2>
<p>Protocol integration test 填補 unit test 和 E2E test 之間的空隙。Unit test 覆蓋程式碼邏輯，E2E test 覆蓋端到端流程，protocol integration test 覆蓋「程式碼和外部服務的互動」這個特定層。</p>
<p>這一層的 test 用程式碼直接呼叫 client 端的連線函式（跳過 UI），對真實的服務實例執行操作（跳過 mock），然後斷言服務的回應是否符合協議規格。</p>
<p>以 app_tunnel 為例，一個 protocol integration test 的結構：</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">1. 啟動本機 ttyd 服務
</span></span><span class="line"><span class="ln">2</span><span class="cl">2. 用 IOWebSocketChannel 連線到 ttyd
</span></span><span class="line"><span class="ln">3</span><span class="cl">3. 發送 auth token JSON frame
</span></span><span class="line"><span class="ln">4</span><span class="cl">4. 斷言收到 terminal output
</span></span><span class="line"><span class="ln">5</span><span class="cl">5. 發送 Uint8List 鍵盤輸入
</span></span><span class="line"><span class="ln">6</span><span class="cl">6. 斷言 ttyd 沒有回應（binary frame 被忽略）
</span></span><span class="line"><span class="ln">7</span><span class="cl">7. 發送 String 鍵盤輸入
</span></span><span class="line"><span class="ln">8</span><span class="cl">8. 斷言 ttyd 有回應（text frame 被處理）</span></span></code></pre></div><p>這個 test 不需要 Flutter UI、不需要 FakeWebSocketChannel，直接驗證「我的程式碼送出的資料，真實 ttyd 是否正確處理」。</p>
<p>以 WebSocket 為例的具體實作在 <a href="/blog/testing/03-protocol-integration-test/websocket-protocol-test/" data-link-title="WebSocket 協議測試實作" data-link-desc="對真實 ttyd 驗證 frame type 和 auth handshake — 從 T.C1 和 T.C2 的教訓推導出的 protocol integration test 設計">WebSocket 協議測試實作</a>中展開。在投入建置之前，用<a href="/blog/testing/03-protocol-integration-test/cost-judgment/" data-link-title="成本判斷表" data-link-desc="什麼時候值得寫 protocol integration test、什麼時候用 contract test 或實機測試替代 — 根據服務啟動成本和協議複雜度判斷">成本判斷表</a>評估服務啟動成本和協議複雜度是否值得這一層 test。Protocol integration test 和 mock test 的分工邊界回到 <a href="/blog/testing/01-test-strategy-layers/" data-link-title="模組一：測試策略分層" data-link-desc="Unit / Protocol Integration / Screen State 三層測試各自的職責、盲區和判斷原則">testing 模組一 測試策略分層</a>的三層框架。</p>
]]></content:encoded></item><item><title>HashiCorp Boundary</title><link>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/boundary/</link><pubDate>Mon, 18 May 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/boundary/</guid><description>&lt;p>HashiCorp Boundary 是 &lt;em>identity-based access broker&lt;/em>、把「使用者要連到某個內部資源」這件事拆成 &lt;em>identity 驗證&lt;/em> + &lt;em>target 授權&lt;/em> + &lt;em>動態 credential 注入&lt;/em> 三段、由 Boundary 統一仲介。它跟 &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 控制面">HashiCorp Vault&lt;/a> 同生態、設計上預期兩者組合：&lt;em>Boundary 控制誰能連到哪個資源、Vault 提供連線當下的 short-lived credential&lt;/em>。單獨用 Boundary 而不接 Vault、會失去它最大的價值。&lt;/p>
&lt;h2 id="服務定位">服務定位&lt;/h2>
&lt;p>Boundary 的核心定位是 &lt;em>連線層級的存取仲介&lt;/em>、不是傳統的 bastion host、也不是 identity-aware proxy。它把 &lt;em>連線發起權&lt;/em> 收回控制面、user 不需要直接拿到 SSH key / DB password / cloud token、只需要對 Boundary 認證、由 Boundary 把 &lt;em>target 資源的網路位置&lt;/em> + &lt;em>Vault 動態簽發的 credential&lt;/em> 在 session 開始時注入連線。&lt;/p>
&lt;p>跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &amp;#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &amp;#43; session recording &amp;#43; JIT、跟 Okta / Vault 互補">Teleport&lt;/a> 比、Boundary 走 &lt;em>network broker + dynamic credential injection&lt;/em>、Teleport 走 &lt;em>identity-aware proxy + session recording&lt;/em>。Teleport 是 &lt;em>看見每一個指令、可重播&lt;/em> 的 PAM；Boundary 是 &lt;em>不存 credential、不錄影、靠 Vault short-lived token 來控制 blast radius&lt;/em>。兩者解的是同一類問題（內部資源存取治理）、但工程取捨完全不同 — Boundary 把「攻擊者拿到 credential 也只有 minutes-level 有效期」當主要防線、Teleport 把「全部 session 留下不可否認證據」當主要防線。&lt;/p>
&lt;p>跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/tailscale-ssh/" data-link-title="Tailscale SSH" data-link-desc="WireGuard-based zero-trust mesh &amp;#43; identity-bound SSH、ACL JSON policy、developer-friendly、跟 IdP integration 取代 SSH key">Tailscale SSH&lt;/a> 比、Tailscale 走 mesh network + SSH-only、無 credential 仲介、無 dynamic injection；Boundary 走 broker 模式、支援 SSH / RDP / DB / TCP / HTTP 等多協議、且 credential 從 Vault 拉。跟 &lt;a href="https://tarrragon.github.io/blog/backend/07-security-data-protection/vendors/cloudflare-access/" data-link-title="Cloudflare Access" data-link-desc="Zero Trust Network Access (ZTNA)、取代 VPN 的 application-layer access、Argo Tunnel &amp;#43; Device Posture &amp;#43; IdP integration">Cloudflare Access&lt;/a> 比、Cloudflare 走 &lt;em>Zero Trust portal + identity-aware reverse proxy&lt;/em>、是 HTTP-first；Boundary 是 &lt;em>protocol-agnostic broker&lt;/em>、原生支援非 HTTP 協議（DB / SSH / RDP）。&lt;/p></description><content:encoded><![CDATA[<p>HashiCorp Boundary 是 <em>identity-based access broker</em>、把「使用者要連到某個內部資源」這件事拆成 <em>identity 驗證</em> + <em>target 授權</em> + <em>動態 credential 注入</em> 三段、由 Boundary 統一仲介。它跟 <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> 同生態、設計上預期兩者組合：<em>Boundary 控制誰能連到哪個資源、Vault 提供連線當下的 short-lived credential</em>。單獨用 Boundary 而不接 Vault、會失去它最大的價值。</p>
<h2 id="服務定位">服務定位</h2>
<p>Boundary 的核心定位是 <em>連線層級的存取仲介</em>、不是傳統的 bastion host、也不是 identity-aware proxy。它把 <em>連線發起權</em> 收回控制面、user 不需要直接拿到 SSH key / DB password / cloud token、只需要對 Boundary 認證、由 Boundary 把 <em>target 資源的網路位置</em> + <em>Vault 動態簽發的 credential</em> 在 session 開始時注入連線。</p>
<p>跟 <a href="/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &#43; session recording &#43; JIT、跟 Okta / Vault 互補">Teleport</a> 比、Boundary 走 <em>network broker + dynamic credential injection</em>、Teleport 走 <em>identity-aware proxy + session recording</em>。Teleport 是 <em>看見每一個指令、可重播</em> 的 PAM；Boundary 是 <em>不存 credential、不錄影、靠 Vault short-lived token 來控制 blast radius</em>。兩者解的是同一類問題（內部資源存取治理）、但工程取捨完全不同 — Boundary 把「攻擊者拿到 credential 也只有 minutes-level 有效期」當主要防線、Teleport 把「全部 session 留下不可否認證據」當主要防線。</p>
<p>跟 <a href="/blog/backend/07-security-data-protection/vendors/tailscale-ssh/" data-link-title="Tailscale SSH" data-link-desc="WireGuard-based zero-trust mesh &#43; identity-bound SSH、ACL JSON policy、developer-friendly、跟 IdP integration 取代 SSH key">Tailscale SSH</a> 比、Tailscale 走 mesh network + SSH-only、無 credential 仲介、無 dynamic injection；Boundary 走 broker 模式、支援 SSH / RDP / DB / TCP / HTTP 等多協議、且 credential 從 Vault 拉。跟 <a href="/blog/backend/07-security-data-protection/vendors/cloudflare-access/" data-link-title="Cloudflare Access" data-link-desc="Zero Trust Network Access (ZTNA)、取代 VPN 的 application-layer access、Argo Tunnel &#43; Device Posture &#43; IdP integration">Cloudflare Access</a> 比、Cloudflare 走 <em>Zero Trust portal + identity-aware reverse proxy</em>、是 HTTP-first；Boundary 是 <em>protocol-agnostic broker</em>、原生支援非 HTTP 協議（DB / SSH / RDP）。</p>
<p>關鍵張力：<em>Boundary + Vault 組合的工程複雜度</em> ↔ <em>不靠 session recording 的審計可信度</em>。已用 HashiCorp 生態（Terraform + Vault + Consul）的組織、Boundary 是 <em>最後一塊拼圖</em>；沒用 Vault 的組織用 Boundary 等於只剩一個 bastion 的弱化版、不如直接走 Teleport。合規強要求 keystroke audit 的場域、Boundary 預設不錄 session、要走 Enterprise add-on 才有、不如 Teleport first-class。</p>
<h2 id="本章目標">本章目標</h2>
<p>讀完本頁、讀者能判斷：</p>
<ol>
<li>Boundary 在 PAM stack 中承擔哪一段（broker / target / session）、哪些要外接（Vault 給 credential、IdP 給 auth、Enterprise add-on 給 session recording）</li>
<li>Controller + Worker + Multi-hop 拓樸怎麼對應實際網路分段（DMZ / internal / restricted subnet）</li>
<li>Vault Credential Library 怎麼設計、誰負責 host catalog、role / scope 怎麼劃</li>
<li>何時用 Boundary、何時改走 Teleport / Tailscale SSH / Cloudflare Access 的取捨</li>
</ol>
<h2 id="最短判讀路徑">最短判讀路徑</h2>
<p>判斷 Boundary deployment 是否健康、最少看四件事：</p>
<ul>
<li><strong>是否真的接 Vault</strong>：Credential Library 是否從 Vault 拉 dynamic credential（DB / SSH cert / cloud token）、session 結束是否自動 revoke、還是仍有 static credential 存在 Boundary 或人手裡</li>
<li><strong>Scope 結構是否反映組織邊界</strong>：Global → Org → Project 的三層 scope、Org 對應 BU / tenant、Project 對應應用或環境；role / grant 是否按 Project 切、還是全部塞 Global scope 變共享密碼</li>
<li><strong>Worker 拓樸是否反映網路分段</strong>：Controller 在 control plane、Worker 在每個網路 segment（DMZ / internal / restricted DB subnet）、Multi-hop 是否走 segment-aware routing、還是把所有 worker 塞同一個 VPC</li>
<li><strong>Auth Method 是不是 IdP-backed</strong>：OIDC（<a href="/blog/backend/07-security-data-protection/vendors/okta/" data-link-title="Okta" data-link-desc="SaaS Identity Provider 主流選項、SSO / MFA / lifecycle 整合、第三方信任邊界的代價">Okta</a> / Azure AD / Google）/ LDAP / Password — production 應該走 OIDC、Password auth method 只該存在於 break-glass</li>
</ul>
<p>四件事任一缺失、就是 <a href="/blog/backend/07-security-data-protection/blue-team/" data-link-title="7.B 防守者視角（藍隊）與控制面驗證" data-link-desc="從防守者角度整理控制面、偵測路由、驗證策略與演練回寫">Privileged Access and Just-in-Time Authority</a> 邊界的待補項目。</p>
<h2 id="日常操作與決策形狀">日常操作與決策形狀</h2>
<p><strong>Controller + Worker 拓樸</strong>：Controller 負責 control plane（auth、policy、session 管理、API endpoint）、Worker 負責 data plane（實際代理連線到 target）。Controller 通常 cluster 部署（3 個以上、HA）、Worker 按網路 segment 分散部署。Controller 從不直接連 target — user 跟 Controller 認證、Controller 告訴 user 走哪個 Worker、Worker 才實際代理連線。</p>
<p><strong>Target + Host Set + Host Catalog</strong>：Target 是 user 看到的「可連對象」抽象（例如 <code>prod-db-cluster</code>）、Host Set 是 Target 對應的實際 host 集合、Host Catalog 是 host 的來源（static list 或從 cloud auto-discover）。Dynamic Host Catalog 可以從 AWS / Azure / GCP 用 tag 自動 enroll host、不需要手動維護 host list — 例如 <code>tag:role=prod-db</code> 的 EC2 自動進 <code>prod-db-cluster</code> Target。</p>
<p><strong>Credential Library（Vault 整合）</strong>：Boundary 不存 credential、靠 Credential Library 從 Vault 拉。設計支援三種：<em>Vault Generic</em>（拉任意 Vault secret path）、<em>Vault SSH Certificate</em>（拉 Vault SSH CA 簽發的 short-lived cert）、<em>Vault Database</em>（拉 Vault Database Secret Engine 簽發的 DB user / password）。session 開始時 Boundary 拉 credential、注入連線、session 結束時 Vault 自動 revoke。這是 Boundary 的核心價值 — 沒接 Vault 等於丟掉 dynamic credential rotation 這個最大賣點。</p>
<p><strong>Auth Method</strong>：支援 OIDC（OAuth2 / OpenID Connect、給 <a href="/blog/backend/07-security-data-protection/vendors/okta/" data-link-title="Okta" data-link-desc="SaaS Identity Provider 主流選項、SSO / MFA / lifecycle 整合、第三方信任邊界的代價">Okta</a> / Azure AD / Google）、LDAP（給 internal directory）、Password（給 break-glass）。Production 預設走 OIDC、跟 IdP 同源、user lifecycle 隨 IdP 變動（離職 IdP 鎖、Boundary 自動失效）。Password auth method 只該存在於 break-glass account、密碼進 Vault、單獨 audit。</p>
<p><strong>Role + Grant + Scope</strong>：Boundary 的權限模型是 <em>scope-bound role</em>、role 屬於某個 scope（Global / Org / Project）、grant 是 role 內的具體權限（例如 <code>target=&lt;id&gt;;actions=authorize-session</code>）。Scope 三層分別對應：<em>Global</em> — platform-level admin、<em>Org</em> — 某 BU 或 tenant、<em>Project</em> — 應用或環境（prod / staging / dev）。設計時把 role 按 Project 切、不要全部塞 Global scope 變共享密碼。</p>
<p><strong>Session 生命週期</strong>：user 對 Boundary 認證（OIDC）→ list authorized target → 對某 target 發起 <code>authorize-session</code>、Boundary 從 Credential Library 拉 credential → user 透過 Boundary CLI / Desktop / SDK 連線、實際走 Worker 代理 → session 有 <em>max duration</em>（預設 8 小時、可調短）、過期自動斷 + Vault credential revoke。session metadata（誰、何時、target、worker、duration）一律 audit log。</p>
<p><strong>Multi-hop Worker</strong>：跨網路 segment（例如 user 在 corp 網、target 在 DMZ → internal → restricted DB subnet）時、Boundary 支援 worker chain — corp Worker 連到 DMZ Worker、DMZ Worker 連到 internal Worker、internal Worker 連到 DB。每段 worker 只看得到下一段、不需要 VPN trunk 把整個網路打通。這是 Boundary 相對 Teleport / Tailscale 的網路工程優勢、特別適合金融 / 政府 / 製造業的多層網路分段。</p>
<h2 id="核心取捨表">核心取捨表</h2>
<table>
  <thead>
      <tr>
          <th>取捨維度</th>
          <th>HashiCorp Boundary</th>
          <th>Teleport</th>
          <th>Tailscale SSH</th>
          <th>Cloudflare Access</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>核心模式</td>
          <td>Network broker + dynamic credential injection</td>
          <td>Identity-aware proxy + session recording</td>
          <td>Mesh VPN + SSH CA</td>
          <td>Zero Trust portal + identity-aware proxy</td>
      </tr>
      <tr>
          <td>Credential 處理</td>
          <td>從 Vault 拉 short-lived、不存</td>
          <td>Teleport CA 簽發 short-lived cert</td>
          <td>Tailscale SSH CA 簽發</td>
          <td>OAuth token、無 SSH credential 處理</td>
      </tr>
      <tr>
          <td>Session recording</td>
          <td>Enterprise add-on（2023+、非 first-class）</td>
          <td>First-class（SSH / kubectl / DB 都錄）</td>
          <td>無</td>
          <td>無</td>
      </tr>
      <tr>
          <td>協議支援</td>
          <td>SSH / RDP / DB（Postgres / MySQL）/ TCP / HTTP</td>
          <td>SSH / kubectl / DB / RDP / Web Apps</td>
          <td>SSH only（mesh 內任意 TCP）</td>
          <td>HTTP / SSH（透過 cloudflared）/ RDP</td>
      </tr>
      <tr>
          <td>部署模型</td>
          <td>Self-hosted (OSS / Enterprise) / HCP (HashiCorp)</td>
          <td>Self-hosted / Teleport Cloud</td>
          <td>SaaS only</td>
          <td>SaaS only</td>
      </tr>
      <tr>
          <td>網路拓樸</td>
          <td>Controller + Worker、Multi-hop 跨 segment 友善</td>
          <td>Proxy + Agent、單層 proxy</td>
          <td>Mesh、所有節點對等</td>
          <td>Cloudflare edge + cloudflared tunnel</td>
      </tr>
      <tr>
          <td>IdP 整合</td>
          <td>OIDC / LDAP / Password</td>
          <td>OIDC / SAML / GitHub</td>
          <td>OIDC（Okta / Google / Azure）</td>
          <td>OIDC / SAML / 內建 IdP</td>
      </tr>
      <tr>
          <td>跟其他 vendor 鎖</td>
          <td>預設假設用 Vault、單獨用價值有限</td>
          <td>獨立完整、不依賴特定 secret store</td>
          <td>獨立、Tailscale 生態</td>
          <td>獨立、Cloudflare 生態</td>
      </tr>
      <tr>
          <td>適合場景</td>
          <td>已用 HashiCorp 生態 + 多協議 + 多層網路分段</td>
          <td>強合規 + session audit + kubectl-heavy</td>
          <td>小團隊 + SSH-only + 不要 PAM 複雜度</td>
          <td>Cloud-native + Zero Trust portal + HTTP-first</td>
      </tr>
      <tr>
          <td>退場成本</td>
          <td>中 — Vault 整合複雜、target / role / scope 量多</td>
          <td>中 — Teleport-specific config + recording</td>
          <td>低 — Tailscale 拆掉就回 plain SSH</td>
          <td>低 — Cloudflare 拆掉就回 origin</td>
      </tr>
  </tbody>
</table>
<p>選 Boundary 的核心訴求：<em>已用 HashiCorp 生態（特別是 Vault）</em> + <em>多協議內部資源（不只 SSH、還有 DB / RDP / TCP）</em> + <em>多層網路分段需要 Multi-hop</em>、可以接受 session recording 不是 first-class。沒用 Vault 的組織、Boundary 失去最大價值、應該直接走 Teleport。</p>
<h2 id="進階主題">進階主題</h2>
<p><strong>Multi-hop Worker 跟網路分段</strong>：金融 / 政府常見三段網路（corp → DMZ → restricted）、傳統做法是打 VPN trunk 把整個網路扁平化、accept 大 blast radius。Boundary 用 worker chain 反向 — 每個 segment 部署一個 worker、worker 之間用 mTLS 認證、user 只進 corp worker、後面 hop 由 Boundary control plane 編排。每段 worker 不知道後一段的 target 細節、只知道下一段 worker 的位置。配對 <a href="/blog/backend/07-security-data-protection/blue-team/" data-link-title="7.B 防守者視角（藍隊）與控制面驗證" data-link-desc="從防守者角度整理控制面、偵測路由、驗證策略與演練回寫">Segmentation and Blast Radius Containment</a> 的章節原則。</p>
<p><strong>Dynamic Host Catalog</strong>：手動維護 host list 在 cloud-native 環境會壞 — auto-scaling group 起一台新 EC2、沒人去 Boundary 加 target。Dynamic Host Catalog 配 cloud provider plugin（AWS / Azure / GCP）、用 tag 自動 enroll：例如 <code>tag:env=prod tag:role=app</code> 的 EC2 自動進 <code>prod-app</code> Target、scale-down 也自動移除。這配 IaC（<a href="/blog/backend/05-deployment-platform/vendors/terraform/" data-link-title="Terraform / OpenTofu" data-link-desc="Infrastructure as Code 主流工具">Terraform</a> 管 tag）是 HashiCorp 生態一致性的核心賣點。</p>
<p><strong>Session Recording（Enterprise 才有）</strong>：2023+ Boundary Enterprise 引入 session recording、支援 SSH 跟 RDP 的 keystroke + screen recording、output 加密存到 S3 / Azure Blob、metadata 走 audit。OSS Community Edition 沒有、只記 session metadata（who / when / what target / how long）。組織要 session recording 但又要 Boundary、要評估 Enterprise license cost vs Teleport license cost — 通常 Teleport 在 session recording 場景成本效益更好。</p>
<p><strong>Vault credential brokering 設計</strong>：Boundary 連 Vault 的設計支援多種 secret engine — Database（Postgres / MySQL / Redis 等、簽 short-lived DB user）、SSH Certificate（簽 short-lived SSH cert）、AWS / Azure / GCP（簽 cloud STS token）、KV v2（拉靜態 secret、不推薦）。Production 預設用 dynamic engine、不要用 KV v2 — 靜態 secret 失去 Boundary 最大價值。Vault namespace / policy 設計要對齊 Boundary scope、否則 cross-scope credential 暴露變大問題。</p>
<p><strong>HCP Boundary（HashiCorp Cloud Platform）</strong>：HashiCorp 託管的 SaaS 版、Controller 由 HashiCorp 管、user 只部署 Worker 到自己網路。優點是省去 Controller HA / upgrade 維運；缺點是 control plane 在 HashiCorp 雲、合規敏感場域要評估 data residency。SMB / 中型團隊適合走 HCP、大型 enterprise 通常 Self-hosted。</p>
<h2 id="排錯與失敗快速判讀">排錯與失敗快速判讀</h2>
<ul>
<li><strong>Session 拿到 credential 但 target 連不上</strong>：Worker 跟 target 之間網路不通、或 Worker 沒部署到 target 所在 segment — 檢查 Worker tag 跟 Target worker_filter、用 <code>boundary workers list</code> 確認 Worker 健康</li>
<li><strong>OIDC login 失敗</strong>：IdP redirect URI 沒對齊、或 IdP signing key 過期 — 對照 <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</a> 的啟示、Boundary OIDC auth method 依賴上游 IdP signing key、IdP 端 key rotation 不對 Boundary 通知會整批 session 認不過</li>
<li><strong>Vault credential 拉不到 / 過期太快</strong>：Boundary 服務帳戶在 Vault 的 policy 沒給 <code>creds/&lt;role&gt;</code> 權限、或 Vault 簽的 credential TTL 短於 session max duration — 對齊 TTL、加 Vault telemetry alert credential issuance 失敗</li>
<li><strong>Multi-hop 連線中斷</strong>：中間 hop 的 Worker 健康但 connection drop — 通常是中間 segment 的 firewall idle timeout 短於 session activity gap、調 firewall 或在 client 端開 keepalive</li>
<li><strong>Target 量爆炸 / role 管不動</strong>：所有 target 塞 Global scope、role 量線性漲 — 重構 scope 結構、按 Org / Project 切、role 從 Global 移到 Project 層</li>
<li><strong>Dynamic Host Catalog 漏 host</strong>：cloud tag 沒打 / IAM 沒給 Boundary 描述權限 — 檢查 cloud plugin 的 service account permission、加 catalog sync error 的 alert</li>
<li><strong>OSS Community 升 Enterprise 才發現缺 feature</strong>：選 OSS 之前沒確認需求 — session recording / SAML / 高級 RBAC / multi-region HA 都是 Enterprise 才有、評估時就要列清楚</li>
</ul>
<h2 id="何時改走其他服務">何時改走其他服務</h2>
<table>
  <thead>
      <tr>
          <th>需求形狀</th>
          <th>改走</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>強合規要 session recording / keystroke audit</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &#43; session recording &#43; JIT、跟 Okta / Vault 互補">Teleport</a></td>
      </tr>
      <tr>
          <td>小團隊 + SSH-only + 不要 PAM 複雜度</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/tailscale-ssh/" data-link-title="Tailscale SSH" data-link-desc="WireGuard-based zero-trust mesh &#43; identity-bound SSH、ACL JSON policy、developer-friendly、跟 IdP integration 取代 SSH key">Tailscale SSH</a></td>
      </tr>
      <tr>
          <td>Cloud-native + Zero Trust portal</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/cloudflare-access/" data-link-title="Cloudflare Access" data-link-desc="Zero Trust Network Access (ZTNA)、取代 VPN 的 application-layer access、Argo Tunnel &#43; Device Posture &#43; IdP integration">Cloudflare Access</a></td>
      </tr>
      <tr>
          <td>Kubernetes kubectl-first PAM</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &#43; session recording &#43; JIT、跟 Okta / Vault 互補">Teleport</a>（kubectl proxy first-class）</td>
      </tr>
      <tr>
          <td>Secret storage / rotation 核心</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>（Boundary 的搭檔）</td>
      </tr>
      <tr>
          <td>IdP / SSO 治理</td>
          <td><a href="/blog/backend/07-security-data-protection/vendors/okta/" data-link-title="Okta" data-link-desc="SaaS Identity Provider 主流選項、SSO / MFA / lifecycle 整合、第三方信任邊界的代價">Okta</a> / Azure AD</td>
      </tr>
      <tr>
          <td>Cloud IAM role assumption</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> / 對應雲</td>
      </tr>
      <tr>
          <td>事故路由</td>
          <td><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></td>
      </tr>
  </tbody>
</table>
<h2 id="不在本頁內的主題">不在本頁內的主題</h2>
<ul>
<li>Boundary CLI / Desktop / Terraform provider 的完整指令 reference</li>
<li>HCP Boundary 跟 Self-hosted 的功能對照細節（HashiCorp 官方有 matrix）</li>
<li>Vault 內部的 secret engine 設計（在 <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>OIDC / SAML 協議本身的攻擊面（<a href="/blog/backend/07-security-data-protection/identity-access-boundary/" data-link-title="7.2 身分與授權邊界" data-link-desc="以問題驅動方式整理身分、授權、會話與供應商身分鏈">2.3 SSO 攻擊面</a>）</li>
<li>Network segmentation 的整體設計（<a href="/blog/backend/07-security-data-protection/blue-team/" data-link-title="7.B 防守者視角（藍隊）與控制面驗證" data-link-desc="從防守者角度整理控制面、偵測路由、驗證策略與演練回寫">Segmentation and Blast Radius Containment</a>）</li>
</ul>
<h2 id="案例回寫">案例回寫</h2>
<p>Boundary 在 07 案例庫沒有直接 vendor-level 事件、但 PAM / credential rotation / IdP 相關 case 都是它的設計取捨對照：</p>
<table>
  <thead>
      <tr>
          <th>案例</th>
          <th>跟 Boundary 的關係（對照啟示）</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>Boundary + Vault Credential Library 直接解此 case 的 scope map 問題 — 每 session 拿 Vault 簽的 short-lived credential、session 結束自動 revoke、不需要 batch rotation、scope map 由 Vault policy + Boundary role 雙向約束</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/identity-access/mgm-2023-identity-lateral-impact/" data-link-title="7.R7.1.4 MGM 2023：身分流程被打穿後的營運中斷" data-link-desc="社交工程造成身分邊界失守後，如何演變成可用性與營運衝擊">MGM 2023 Identity Lateral Impact</a></td>
          <td>helpdesk 走 SE 拿到 reset 後的密碼、但 Boundary 仍要求 session 開始時拿 Vault dynamic credential、attacker 在 Vault policy 端被擋；前提是 Boundary OIDC auth method 不依賴可被 SE 重置的 password、IdP 要走 phishing-resistant MFA</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</a></td>
          <td>Boundary OIDC auth method 依賴上游 IdP signing key、IdP 出事時 Boundary access 也要 rotate；對應啟示是 <em>broker 的 trust chain 取決於上游 IdP</em>、不要把 OIDC 當無責任接口</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/red-team/cases/data-exfiltration/snowflake-2024-credential-abuse/" data-link-title="7.R7.4.2 Snowflake 2024：憑證濫用與資料竊取" data-link-desc="外洩憑證與 MFA 缺口如何在資料平台形成高風險外送事件">Snowflake 2024 Credential Abuse</a></td>
          <td>static credential 在離職 / 外洩後仍可用是核心問題、Boundary + Vault Database Secret Engine 直接消除 static credential 存在、改成每 session 簽 short-lived DB user</td>
      </tr>
      <tr>
          <td><a href="/blog/backend/07-security-data-protection/blue-team/" data-link-title="7.B 防守者視角（藍隊）與控制面驗證" data-link-desc="從防守者角度整理控制面、偵測路由、驗證策略與演練回寫">Privileged Access and JIT Authority (section)</a></td>
          <td>Boundary 的 <em>authorize-session</em> 模型是 JIT authority 的具體實作、session 期限 + Vault TTL 雙重約束 blast radius</td>
      </tr>
  </tbody>
</table>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>上游：<a href="/blog/backend/07-security-data-protection/blue-team/" data-link-title="7.B 防守者視角（藍隊）與控制面驗證" data-link-desc="從防守者角度整理控制面、偵測路由、驗證策略與演練回寫">7.B Privileged Access and JIT Authority</a>、<a href="/blog/backend/07-security-data-protection/blue-team/" data-link-title="7.B 防守者視角（藍隊）與控制面驗證" data-link-desc="從防守者角度整理控制面、偵測路由、驗證策略與演練回寫">7.B Segmentation and Blast Radius Containment</a></li>
<li>平行：<a href="/blog/backend/07-security-data-protection/vendors/teleport/" data-link-title="Teleport" data-link-desc="Identity-Aware Proxy &#43; PAM、SSH / DB / K8s / Desktop session 統一 short-lived cert &#43; session recording &#43; JIT、跟 Okta / Vault 互補">Teleport</a>、<a href="/blog/backend/07-security-data-protection/vendors/tailscale-ssh/" data-link-title="Tailscale SSH" data-link-desc="WireGuard-based zero-trust mesh &#43; identity-bound SSH、ACL JSON policy、developer-friendly、跟 IdP integration 取代 SSH key">Tailscale SSH</a>、<a href="/blog/backend/07-security-data-protection/vendors/cloudflare-access/" data-link-title="Cloudflare Access" data-link-desc="Zero Trust Network Access (ZTNA)、取代 VPN 的 application-layer access、Argo Tunnel &#43; Device Posture &#43; IdP integration">Cloudflare Access</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>（Credential Library 核心）、<a href="/blog/backend/07-security-data-protection/vendors/okta/" data-link-title="Okta" data-link-desc="SaaS Identity Provider 主流選項、SSO / MFA / lifecycle 整合、第三方信任邊界的代價">Okta</a>（OIDC IdP）</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>（cloud target 的 STS token 來源）、<a href="/blog/backend/05-deployment-platform/vendors/terraform/" data-link-title="Terraform / OpenTofu" data-link-desc="Infrastructure as Code 主流工具">Terraform</a>（target / scope / role 進 IaC）</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>（Boundary audit log → SIEM → IR routing）、<a href="/blog/backend/07-security-data-protection/identity-access-boundary/" data-link-title="7.2 身分與授權邊界" data-link-desc="以問題驅動方式整理身分、授權、會話與供應商身分鏈">2.3 SSO 攻擊面</a></li>
<li>官方：<a href="https://developer.hashicorp.com/boundary">Boundary Documentation</a></li>
</ul>
]]></content:encoded></item></channel></rss>