<?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>Access-Control on Tarragon</title><link>https://tarrragon.github.io/blog/tags/access-control/</link><description>Recent content in Access-Control on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 26 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/access-control/index.xml" rel="self" type="application/rss+xml"/><item><title>Collector Access Control 實作</title><link>https://tarrragon.github.io/blog/monitoring/07-security-privacy/collector-access-control/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/monitoring/07-security-privacy/collector-access-control/</guid><description>&lt;p>Collector access control 管理「誰可以對 collector 做什麼操作」。三層控制各自回答不同的問題：認證回答「來源是誰」，授權回答「這個來源被允許做什麼」，access log 回答「誰在什麼時候實際做了什麼」。&lt;/p>
&lt;h2 id="認證來源是誰">認證：來源是誰&lt;/h2>
&lt;p>認證驗證送出資料的 client 是否合法。未認證的 request 應該被拒絕，避免任意來源向 collector 寫入資料。&lt;/p>
&lt;h3 id="api-key-認證">API Key 認證&lt;/h3>
&lt;p>每個合法的 SDK client 有一個 API key。Collector 檢查 request header 中的 API key 是否在合法清單中。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-go" data-lang="go">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="kd">func&lt;/span> &lt;span class="nf">authMiddleware&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">next&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Handler&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Handler&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">HandlerFunc&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="kd">func&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">w&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">ResponseWriter&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">r&lt;/span> &lt;span class="o">*&lt;/span>&lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Request&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl"> &lt;span class="nx">key&lt;/span> &lt;span class="o">:=&lt;/span> &lt;span class="nx">r&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">Header&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Get&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="s">&amp;#34;X-API-Key&amp;#34;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl"> &lt;span class="k">if&lt;/span> &lt;span class="p">!&lt;/span>&lt;span class="nf">isValidKey&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">key&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl"> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">Error&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="s">&amp;#34;unauthorized&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">http&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">StatusUnauthorized&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl"> &lt;span class="k">return&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl"> &lt;span class="nx">next&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">ServeHTTP&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nx">w&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nx">r&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl"> &lt;span class="p">})&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="p">}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>自用工具場景下，一個 API key 對應一個 client 通常就足夠。多個 client（例如同一個 app 的 iOS 和 Android 版本）可以用同一個 key，或每個平台一個 key 以便在 access log 中區分來源。&lt;/p>
&lt;h3 id="mtlsmutual-tls">mTLS（Mutual TLS）&lt;/h3>
&lt;p>Client 和 server 互相驗證對方的憑證。安全性比 API key 高 — 攻擊者即使取得 API key，沒有 client 憑證也無法連線。&lt;/p>
&lt;p>mTLS 的設定成本較高（每個 client 需要產生和管理憑證），適合對安全性要求較高的環境。自用工具通常不需要 mTLS。&lt;/p>
&lt;h2 id="授權允許做什麼">授權：允許做什麼&lt;/h2>
&lt;p>授權控制已認證的 client 可以執行哪些操作。Collector 的操作通常分為兩類：寫入事件和查詢事件。&lt;/p>
&lt;h3 id="角色分離">角色分離&lt;/h3>
&lt;p>最簡單的授權模型是兩個角色：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Writer&lt;/strong>：只能寫入事件（POST /events）。SDK client 使用這個角色。&lt;/li>
&lt;li>&lt;strong>Reader&lt;/strong>：只能查詢事件（GET /events、GET /query）。開發者的 CLI 工具使用這個角色。&lt;/li>
&lt;/ul>
&lt;p>角色分離的價值在於限制洩漏的影響範圍。如果 SDK 的 API key 被洩漏，攻擊者只能寫入（產生垃圾事件），不能讀取（看到歷史事件中的敏感資訊）。&lt;/p>
&lt;h3 id="寫入限制">寫入限制&lt;/h3>
&lt;p>即使認證通過、角色正確，collector 也可以對寫入加上限制：&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Rate limit&lt;/strong>：每個 API key 每分鐘最多 N 個 request。防止 client 端 bug 導致事件風暴。&lt;/li>
&lt;li>&lt;strong>Payload size limit&lt;/strong>：每個事件最大 M KB。防止異常大的 event data 消耗儲存。&lt;/li>
&lt;li>&lt;strong>Schema validation&lt;/strong>：事件必須符合定義的 JSON schema。格式不正確的事件拒絕存入。&lt;/li>
&lt;/ul>
&lt;h2 id="access-log誰做了什麼">Access Log：誰做了什麼&lt;/h2>
&lt;p>Access log 記錄每個到達 collector 的 request — 來源 IP、API key（或 key 的 hash）、操作類型、時間戳、response status。&lt;/p>
&lt;p>Access log 的用途：&lt;/p>
&lt;p>&lt;strong>安全審計&lt;/strong>：發現異常行為 — 未知 IP 的大量寫入、非工作時間的讀取、連續的認證失敗。&lt;/p>
&lt;p>&lt;strong>問題排查&lt;/strong>：SDK 說事件送出成功但 collector 沒有收到 — access log 可以確認 request 是否到達、response 是什麼。&lt;/p>
&lt;p>&lt;strong>用量統計&lt;/strong>：每個 client 送了多少事件、佔多少儲存。&lt;/p>
&lt;p>Access log 本身也是監控資料，但和業務事件分開儲存。Access log 存在 collector 本機的 log 檔中，用系統的 logrotate 管理輪替。&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">2026-06-19T10:30:00Z POST /events key=sk_mon_ab...cd ip=192.168.1.50 status=200 size=1234
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">2026-06-19T10:30:01Z POST /events key=INVALID ip=10.0.0.99 status=401 size=0
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">2026-06-19T10:31:00Z GET /query key=sk_read_ef...gh ip=192.168.1.1 status=200 size=8901&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>SDK 端的 redaction → &lt;a href="https://tarrragon.github.io/blog/monitoring/07-security-privacy/sdk-redaction-api/" data-link-title="SDK Redaction API 設計" data-link-desc="預設 redaction rule 過濾已知敏感欄位、自訂 pattern 擴展應用特有的 secret 格式 — redaction 在 SDK 端執行，敏感資料不離開 client">SDK Redaction API 設計&lt;/a>&lt;/li>
&lt;li>Transport 層的加密 → &lt;a href="https://tarrragon.github.io/blog/monitoring/07-security-privacy/transport-security/" data-link-title="Transport 安全" data-link-desc="HTTPS / basic auth / 同區網也要加密的理由 — 監控資料在傳輸途中的保護機制">Transport 安全&lt;/a>&lt;/li>
&lt;li>資料儲存後的去識別化 → &lt;a href="https://tarrragon.github.io/blog/monitoring/07-security-privacy/anonymization-strategy/" data-link-title="去識別化策略" data-link-desc="IP 截斷 / user agent 簡化 / stack trace 路徑清理 / session UUID — 四種去識別化技術的適用場景和實作方式">去識別化策略&lt;/a>&lt;/li>
&lt;li>Client-side credential 暴露的根本限制 → &lt;a href="https://tarrragon.github.io/blog/monitoring/07-security-privacy/client-sdk-authentication/" data-link-title="Client-side SDK 認證的根本限制" data-link-desc="嵌在 client 端的 credential 必然可被提取 — 認清 architecture 天花板後的多層緩解策略，從 origin 驗證到 device attestation">Client-side SDK 認證&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Collector access control 管理「誰可以對 collector 做什麼操作」。三層控制各自回答不同的問題：認證回答「來源是誰」，授權回答「這個來源被允許做什麼」，access log 回答「誰在什麼時候實際做了什麼」。</p>
<h2 id="認證來源是誰">認證：來源是誰</h2>
<p>認證驗證送出資料的 client 是否合法。未認證的 request 應該被拒絕，避免任意來源向 collector 寫入資料。</p>
<h3 id="api-key-認證">API Key 認證</h3>
<p>每個合法的 SDK client 有一個 API key。Collector 檢查 request header 中的 API key 是否在合法清單中。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kd">func</span> <span class="nf">authMiddleware</span><span class="p">(</span><span class="nx">next</span> <span class="nx">http</span><span class="p">.</span><span class="nx">Handler</span><span class="p">)</span> <span class="nx">http</span><span class="p">.</span><span class="nx">Handler</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">    <span class="k">return</span> <span class="nx">http</span><span class="p">.</span><span class="nf">HandlerFunc</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span> <span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span> <span class="nx">r</span> <span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">        <span class="nx">key</span> <span class="o">:=</span> <span class="nx">r</span><span class="p">.</span><span class="nx">Header</span><span class="p">.</span><span class="nf">Get</span><span class="p">(</span><span class="s">&#34;X-API-Key&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">        <span class="k">if</span> <span class="p">!</span><span class="nf">isValidKey</span><span class="p">(</span><span class="nx">key</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">            <span class="nx">http</span><span class="p">.</span><span class="nf">Error</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="s">&#34;unauthorized&#34;</span><span class="p">,</span> <span class="nx">http</span><span class="p">.</span><span class="nx">StatusUnauthorized</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">            <span class="k">return</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">        <span class="nx">next</span><span class="p">.</span><span class="nf">ServeHTTP</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span> <span class="nx">r</span><span class="p">)</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><p>自用工具場景下，一個 API key 對應一個 client 通常就足夠。多個 client（例如同一個 app 的 iOS 和 Android 版本）可以用同一個 key，或每個平台一個 key 以便在 access log 中區分來源。</p>
<h3 id="mtlsmutual-tls">mTLS（Mutual TLS）</h3>
<p>Client 和 server 互相驗證對方的憑證。安全性比 API key 高 — 攻擊者即使取得 API key，沒有 client 憑證也無法連線。</p>
<p>mTLS 的設定成本較高（每個 client 需要產生和管理憑證），適合對安全性要求較高的環境。自用工具通常不需要 mTLS。</p>
<h2 id="授權允許做什麼">授權：允許做什麼</h2>
<p>授權控制已認證的 client 可以執行哪些操作。Collector 的操作通常分為兩類：寫入事件和查詢事件。</p>
<h3 id="角色分離">角色分離</h3>
<p>最簡單的授權模型是兩個角色：</p>
<ul>
<li><strong>Writer</strong>：只能寫入事件（POST /events）。SDK client 使用這個角色。</li>
<li><strong>Reader</strong>：只能查詢事件（GET /events、GET /query）。開發者的 CLI 工具使用這個角色。</li>
</ul>
<p>角色分離的價值在於限制洩漏的影響範圍。如果 SDK 的 API key 被洩漏，攻擊者只能寫入（產生垃圾事件），不能讀取（看到歷史事件中的敏感資訊）。</p>
<h3 id="寫入限制">寫入限制</h3>
<p>即使認證通過、角色正確，collector 也可以對寫入加上限制：</p>
<ul>
<li><strong>Rate limit</strong>：每個 API key 每分鐘最多 N 個 request。防止 client 端 bug 導致事件風暴。</li>
<li><strong>Payload size limit</strong>：每個事件最大 M KB。防止異常大的 event data 消耗儲存。</li>
<li><strong>Schema validation</strong>：事件必須符合定義的 JSON schema。格式不正確的事件拒絕存入。</li>
</ul>
<h2 id="access-log誰做了什麼">Access Log：誰做了什麼</h2>
<p>Access log 記錄每個到達 collector 的 request — 來源 IP、API key（或 key 的 hash）、操作類型、時間戳、response status。</p>
<p>Access log 的用途：</p>
<p><strong>安全審計</strong>：發現異常行為 — 未知 IP 的大量寫入、非工作時間的讀取、連續的認證失敗。</p>
<p><strong>問題排查</strong>：SDK 說事件送出成功但 collector 沒有收到 — access log 可以確認 request 是否到達、response 是什麼。</p>
<p><strong>用量統計</strong>：每個 client 送了多少事件、佔多少儲存。</p>
<p>Access log 本身也是監控資料，但和業務事件分開儲存。Access log 存在 collector 本機的 log 檔中，用系統的 logrotate 管理輪替。</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">2026-06-19T10:30:00Z POST /events key=sk_mon_ab...cd ip=192.168.1.50 status=200 size=1234
</span></span><span class="line"><span class="ln">2</span><span class="cl">2026-06-19T10:30:01Z POST /events key=INVALID ip=10.0.0.99 status=401 size=0
</span></span><span class="line"><span class="ln">3</span><span class="cl">2026-06-19T10:31:00Z GET /query key=sk_read_ef...gh ip=192.168.1.1 status=200 size=8901</span></span></code></pre></div><h2 id="下一步路由">下一步路由</h2>
<ul>
<li>SDK 端的 redaction → <a href="/blog/monitoring/07-security-privacy/sdk-redaction-api/" data-link-title="SDK Redaction API 設計" data-link-desc="預設 redaction rule 過濾已知敏感欄位、自訂 pattern 擴展應用特有的 secret 格式 — redaction 在 SDK 端執行，敏感資料不離開 client">SDK Redaction API 設計</a></li>
<li>Transport 層的加密 → <a href="/blog/monitoring/07-security-privacy/transport-security/" data-link-title="Transport 安全" data-link-desc="HTTPS / basic auth / 同區網也要加密的理由 — 監控資料在傳輸途中的保護機制">Transport 安全</a></li>
<li>資料儲存後的去識別化 → <a href="/blog/monitoring/07-security-privacy/anonymization-strategy/" data-link-title="去識別化策略" data-link-desc="IP 截斷 / user agent 簡化 / stack trace 路徑清理 / session UUID — 四種去識別化技術的適用場景和實作方式">去識別化策略</a></li>
<li>Client-side credential 暴露的根本限制 → <a href="/blog/monitoring/07-security-privacy/client-sdk-authentication/" data-link-title="Client-side SDK 認證的根本限制" data-link-desc="嵌在 client 端的 credential 必然可被提取 — 認清 architecture 天花板後的多層緩解策略，從 origin 驗證到 device attestation">Client-side SDK 認證</a></li>
</ul>
]]></content:encoded></item><item><title>斷網環境的資安與權限控管</title><link>https://tarrragon.github.io/blog/infra/air-gapped/air-gapped-security-access/</link><pubDate>Fri, 26 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/infra/air-gapped/air-gapped-security-access/</guid><description>&lt;p>斷網環境的安全假設跟連網環境相反。連網環境的主要威脅是外部攻擊者透過網路入侵——防火牆、WAF、IDS 構成防禦層。斷網環境的實體隔離幾乎消除了遠端攻擊的可能，但威脅沒有消失，而是轉向兩個方向：有權限存取內部系統的人員（insider threat），以及透過合法管道跨越隔離邊界的內容（supply chain）。每一個刻意建立的橋樑——USB 隨身碟、資料搬運站、data diode——都是攻擊面。&lt;/p>
&lt;h2 id="威脅模型的轉變">威脅模型的轉變&lt;/h2>
&lt;p>連網環境的安全投資集中在邊界防禦：防火牆規則、DDoS 防護、入侵偵測、漏洞修補的速度。斷網環境的邊界是物理的——網路線沒有接上去，防火牆規則不是問題。威脅從「外面的人怎麼進來」變成「裡面的人怎麼把東西帶出去、或把有害的東西帶進來」。&lt;/p>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>威脅類型&lt;/th>
 &lt;th>連網環境的可能性&lt;/th>
 &lt;th>斷網環境的可能性&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;td>—&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>釣魚 / 社交工程&lt;/td>
 &lt;td>高&lt;/td>
 &lt;td>低（無外部 email）&lt;/td>
 &lt;td>但內部通訊仍可能被利用&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>USB / 可移除媒體&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>高&lt;/td>
 &lt;td>人員帶入的 USB、外接硬碟&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>供應鏈污染&lt;/td>
 &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;td>有實體存取權的操作人員&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>資料外洩&lt;/td>
 &lt;td>高（網路）&lt;/td>
 &lt;td>中（實體）&lt;/td>
 &lt;td>USB 複製、列印、手機拍照&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>橫向移動&lt;/td>
 &lt;td>高&lt;/td>
 &lt;td>中&lt;/td>
 &lt;td>內部網路扁平時仍然可能&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;p>斷網環境的安全投資因此集中在三個面向：控制誰能碰什麼（存取控制）、記錄誰碰了什麼（稽核日誌）、審查什麼東西跨越邊界（傳輸審查）。&lt;/p>
&lt;h2 id="實體安全是-infra-的責任">實體安全是 infra 的責任&lt;/h2>
&lt;p>連網環境的實體安全通常歸 facility team——機房門禁、監視器、電力冗餘。infra 團隊負責的是邏輯層的安全（IAM、security group、加密）。斷網環境裡這條分界線消失了：「誰能帶 USB 進機房」直接等於「誰能把任意程式碼注入生產環境」，這是 infra 的安全邊界，不是 facility 的。&lt;/p>
&lt;p>需要 infra 團隊參與制定的實體安全政策：&lt;/p>
&lt;p>&lt;strong>可移除媒體管控&lt;/strong>：哪些人被授權攜帶 USB / 外接硬碟進入安全區域。媒體是否需要預先登記和加密。進入前是否要在掃描站過掃。政策的嚴格度依環境敏感度而定——最嚴格的環境禁止所有個人裝置、只使用登記在冊的專用搬運媒體。&lt;/p>
&lt;p>&lt;strong>機房存取控制&lt;/strong>：門禁卡 / 生物辨識的日誌要進入 infra 的稽核系統。每一次實體進出都要有記錄——誰、什麼時候、待了多久。伺服器機櫃如果有獨立的鎖，鎖的鑰匙管理也歸 infra。&lt;/p>
&lt;p>&lt;strong>Console 存取&lt;/strong>：能直接操作伺服器 console（KVM、IPMI、iLO）的人等於擁有最高權限——可以繞過所有 OS 層的認證。console 存取要限制到最小人數，每次使用要記錄。&lt;/p>
&lt;p>&lt;strong>螢幕與攝影裝置&lt;/strong>：敏感環境可能限制在安全區域內使用手機（防止拍攝螢幕上的資料）。這個政策的執行通常是 facility 負責，但政策的制定依據（什麼資料在螢幕上算敏感）是 infra 定義的。&lt;/p>
&lt;h2 id="身分與認證沒有雲端-iam">身分與認證（沒有雲端 IAM）&lt;/h2>
&lt;p>連網環境用 OIDC / SSO / 雲端 &lt;a href="https://tarrragon.github.io/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM&lt;/a> 管理身分。斷網環境沒有這些——需要自建身分基礎設施。&lt;/p>
&lt;p>&lt;strong>集中身分管理&lt;/strong>：FreeIPA（整合 LDAP + Kerberos + DNS + CA）或 OpenLDAP 作為統一的使用者目錄。所有內部服務（GitLab、Nexus、Harbor、Vault、Grafana）都配置 LDAP 認證，避免每個服務各自管一套使用者帳號。FreeIPA 的優勢是把 LDAP、Kerberos、DNS 和 CA 整合在一個管理介面——在資源有限的斷網環境裡減少維運面。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># FreeIPA 安裝（CentOS/Rocky）&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">sudo yum install -y ipa-server ipa-server-dns
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">sudo ipa-server-install --setup-dns --no-forwarders&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>MFA（沒有網路的情況下）&lt;/strong>：TOTP（如 Google Authenticator）完全在本地運作、不需要網路連線。硬體 token（YubiKey）支援 FIDO2 / PIV / TOTP，在高安全環境是標準做法。智慧卡（CAC / PIV card）在政府和軍事環境最常見。&lt;/p>
&lt;p>&lt;strong>服務帳號&lt;/strong>：機器對機器的認證用 Vault 的 AppRole（role_id + secret_id 換取短期 token）或本地 SSL client certificate。不使用長期密碼或寫死的 token。&lt;/p>
&lt;h2 id="稽核日誌沒有-cloudtrail">稽核日誌（沒有 CloudTrail）&lt;/h2>
&lt;p>連網環境用 CloudTrail / GCP Audit Log 自動記錄所有 API 操作。斷網環境要自建整條稽核鏈：收集 → 傳輸 → 儲存 → 查詢 → 告警。&lt;/p>
&lt;p>&lt;strong>OS 層級&lt;/strong>：Linux auditd 記錄 kernel 層的操作——誰執行了什麼指令、誰存取了什麼檔案、誰修改了什麼系統設定。規則用 &lt;code>auditctl&lt;/code> 或 &lt;code>/etc/audit/rules.d/&lt;/code> 設定。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 監控所有 sudo 操作&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">-a always,exit -F &lt;span class="nv">arch&lt;/span>&lt;span class="o">=&lt;/span>b64 -S execve -F &lt;span class="nv">euid&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="m">0&lt;/span> -k root-commands
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="c1"># 監控 /etc/ 目錄的修改&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">-w /etc/ -p wa -k etc-changes&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;strong>服務層級&lt;/strong>：每個自建服務都有自己的 audit log——GitLab 的 audit events、Vault 的 audit device（可設成 file 或 syslog）、Harbor 的 activity log。這些日誌要匯聚到中央 log server。&lt;/p></description><content:encoded><![CDATA[<p>斷網環境的安全假設跟連網環境相反。連網環境的主要威脅是外部攻擊者透過網路入侵——防火牆、WAF、IDS 構成防禦層。斷網環境的實體隔離幾乎消除了遠端攻擊的可能，但威脅沒有消失，而是轉向兩個方向：有權限存取內部系統的人員（insider threat），以及透過合法管道跨越隔離邊界的內容（supply chain）。每一個刻意建立的橋樑——USB 隨身碟、資料搬運站、data diode——都是攻擊面。</p>
<h2 id="威脅模型的轉變">威脅模型的轉變</h2>
<p>連網環境的安全投資集中在邊界防禦：防火牆規則、DDoS 防護、入侵偵測、漏洞修補的速度。斷網環境的邊界是物理的——網路線沒有接上去，防火牆規則不是問題。威脅從「外面的人怎麼進來」變成「裡面的人怎麼把東西帶出去、或把有害的東西帶進來」。</p>
<table>
  <thead>
      <tr>
          <th>威脅類型</th>
          <th>連網環境的可能性</th>
          <th>斷網環境的可能性</th>
          <th>斷網環境的主要載體</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>遠端漏洞利用</td>
          <td>高</td>
          <td>極低</td>
          <td>—</td>
      </tr>
      <tr>
          <td>釣魚 / 社交工程</td>
          <td>高</td>
          <td>低（無外部 email）</td>
          <td>但內部通訊仍可能被利用</td>
      </tr>
      <tr>
          <td>USB / 可移除媒體</td>
          <td>中</td>
          <td>高</td>
          <td>人員帶入的 USB、外接硬碟</td>
      </tr>
      <tr>
          <td>供應鏈污染</td>
          <td>中</td>
          <td>高</td>
          <td>搬運進來的套件、映像、更新檔</td>
      </tr>
      <tr>
          <td>內部人員濫用權限</td>
          <td>中</td>
          <td>高</td>
          <td>有實體存取權的操作人員</td>
      </tr>
      <tr>
          <td>資料外洩</td>
          <td>高（網路）</td>
          <td>中（實體）</td>
          <td>USB 複製、列印、手機拍照</td>
      </tr>
      <tr>
          <td>橫向移動</td>
          <td>高</td>
          <td>中</td>
          <td>內部網路扁平時仍然可能</td>
      </tr>
  </tbody>
</table>
<p>斷網環境的安全投資因此集中在三個面向：控制誰能碰什麼（存取控制）、記錄誰碰了什麼（稽核日誌）、審查什麼東西跨越邊界（傳輸審查）。</p>
<h2 id="實體安全是-infra-的責任">實體安全是 infra 的責任</h2>
<p>連網環境的實體安全通常歸 facility team——機房門禁、監視器、電力冗餘。infra 團隊負責的是邏輯層的安全（IAM、security group、加密）。斷網環境裡這條分界線消失了：「誰能帶 USB 進機房」直接等於「誰能把任意程式碼注入生產環境」，這是 infra 的安全邊界，不是 facility 的。</p>
<p>需要 infra 團隊參與制定的實體安全政策：</p>
<p><strong>可移除媒體管控</strong>：哪些人被授權攜帶 USB / 外接硬碟進入安全區域。媒體是否需要預先登記和加密。進入前是否要在掃描站過掃。政策的嚴格度依環境敏感度而定——最嚴格的環境禁止所有個人裝置、只使用登記在冊的專用搬運媒體。</p>
<p><strong>機房存取控制</strong>：門禁卡 / 生物辨識的日誌要進入 infra 的稽核系統。每一次實體進出都要有記錄——誰、什麼時候、待了多久。伺服器機櫃如果有獨立的鎖，鎖的鑰匙管理也歸 infra。</p>
<p><strong>Console 存取</strong>：能直接操作伺服器 console（KVM、IPMI、iLO）的人等於擁有最高權限——可以繞過所有 OS 層的認證。console 存取要限制到最小人數，每次使用要記錄。</p>
<p><strong>螢幕與攝影裝置</strong>：敏感環境可能限制在安全區域內使用手機（防止拍攝螢幕上的資料）。這個政策的執行通常是 facility 負責，但政策的制定依據（什麼資料在螢幕上算敏感）是 infra 定義的。</p>
<h2 id="身分與認證沒有雲端-iam">身分與認證（沒有雲端 IAM）</h2>
<p>連網環境用 OIDC / SSO / 雲端 <a href="/blog/infra/knowledge-cards/iam/" data-link-title="IAM（Identity and Access Management）" data-link-desc="雲端平台的授權系統，回答「某個身分能不能對某個資源做某件事」">IAM</a> 管理身分。斷網環境沒有這些——需要自建身分基礎設施。</p>
<p><strong>集中身分管理</strong>：FreeIPA（整合 LDAP + Kerberos + DNS + CA）或 OpenLDAP 作為統一的使用者目錄。所有內部服務（GitLab、Nexus、Harbor、Vault、Grafana）都配置 LDAP 認證，避免每個服務各自管一套使用者帳號。FreeIPA 的優勢是把 LDAP、Kerberos、DNS 和 CA 整合在一個管理介面——在資源有限的斷網環境裡減少維運面。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># FreeIPA 安裝（CentOS/Rocky）</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">sudo yum install -y ipa-server ipa-server-dns
</span></span><span class="line"><span class="ln">3</span><span class="cl">sudo ipa-server-install --setup-dns --no-forwarders</span></span></code></pre></div><p><strong>MFA（沒有網路的情況下）</strong>：TOTP（如 Google Authenticator）完全在本地運作、不需要網路連線。硬體 token（YubiKey）支援 FIDO2 / PIV / TOTP，在高安全環境是標準做法。智慧卡（CAC / PIV card）在政府和軍事環境最常見。</p>
<p><strong>服務帳號</strong>：機器對機器的認證用 Vault 的 AppRole（role_id + secret_id 換取短期 token）或本地 SSL client certificate。不使用長期密碼或寫死的 token。</p>
<h2 id="稽核日誌沒有-cloudtrail">稽核日誌（沒有 CloudTrail）</h2>
<p>連網環境用 CloudTrail / GCP Audit Log 自動記錄所有 API 操作。斷網環境要自建整條稽核鏈：收集 → 傳輸 → 儲存 → 查詢 → 告警。</p>
<p><strong>OS 層級</strong>：Linux auditd 記錄 kernel 層的操作——誰執行了什麼指令、誰存取了什麼檔案、誰修改了什麼系統設定。規則用 <code>auditctl</code> 或 <code>/etc/audit/rules.d/</code> 設定。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 監控所有 sudo 操作</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">-a always,exit -F <span class="nv">arch</span><span class="o">=</span>b64 -S execve -F <span class="nv">euid</span><span class="o">=</span><span class="m">0</span> -k root-commands
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1"># 監控 /etc/ 目錄的修改</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">-w /etc/ -p wa -k etc-changes</span></span></code></pre></div><p><strong>服務層級</strong>：每個自建服務都有自己的 audit log——GitLab 的 audit events、Vault 的 audit device（可設成 file 或 syslog）、Harbor 的 activity log。這些日誌要匯聚到中央 log server。</p>
<p><strong>集中收集</strong>：rsyslog 或 syslog-ng 把各主機的 audit log 轉送到一台專用的 log server。log server 的儲存用 append-only 或 write-once 媒體（防止日誌被竄改）。</p>
<p><strong>日誌完整性</strong>：定期對日誌檔做 hash（<code>sha256sum</code>）並把 hash 存到獨立的位置。如果日誌內容被修改，hash 不匹配會被發現。在最高安全等級的環境裡，日誌會同時寫到光碟或 WORM（Write Once Read Many）儲存。</p>
<p><strong>審閱與告警</strong>：日誌收集了但沒人看等於沒有。定義哪些事件觸發主動通知（root 登入、非工作時段的操作、大量檔案存取）、哪些事件定期審閱（每週掃描異常模式）。</p>
<h2 id="更新的延遲窗口">更新的延遲窗口</h2>
<p>連網環境的 CVE 修補可以在小時到天的層級完成——<code>apt update &amp;&amp; apt upgrade</code>。斷網環境的修補從「得知漏洞」到「修補上線」之間有結構性的延遲。</p>
<p>典型的延遲鏈：外部公告 CVE → 安全團隊評估影響（1-2 天）→ 在外部環境下載修補（同日）→ 掃描修補本身的安全性（1 天）→ 審批跨邊界傳輸（1-3 天）→ 在斷網測試環境驗證（1-2 天）→ 部署到生產環境（同日）。總延遲 5-10 個工作天。</p>
<p>這個延遲窗口是已知的、可管理的風險。管理方式：</p>
<p><strong>風險接受文件</strong>：記錄哪些 CVE 在「已知但尚未修補」的窗口內，每條標註預計修補時間和暫時的補償控制。</p>
<p><strong>補償控制</strong>：在修補到位之前降低漏洞的可利用性——禁用受影響的服務功能、收緊網路分段、限制受影響服務的存取權限。</p>
<p><strong>分級修補</strong>：不是所有 CVE 都需要緊急處理。Critical（CVSS 9+）走加速通道（目標 3 天內修補）、High（CVSS 7-8.9）走正常通道（目標 10 天）、Medium 以下排進常規更新週期。</p>
<h2 id="跨邊界傳輸的安全審查">跨邊界傳輸的安全審查</h2>
<p>每一個跨越隔離邊界的物件都需要審查——套件、映像、設定檔、資料匯出。搬運的操作流程在<a href="/blog/infra/air-gapped/air-gapped-principles/" data-link-title="斷網環境的通用原則" data-link-desc="離線套件管理、內容搬運、變更追蹤的共通操作模式 — 所有斷網情境都要先建立的基礎能力">通用原則篇</a>描述，這裡聚焦安全審查的部分。</p>
<p><strong>掃描站</strong>：在邊界設置一台專用的掃描機器，所有入境的媒體先在這裡過掃——防毒掃描、檔案類型驗證、hash 比對（確認下載的套件跟官方發布的 hash 一致）。掃描站本身的病毒定義也需要定期更新（走相同的搬運流程）。</p>
<p><strong>傳輸審批日誌</strong>：每次跨邊界傳輸記錄：搬運的內容清單、搬運者、審批者、搬運日期、每個檔案的 hash。這份日誌是稽核的依據——如果內部發現惡意軟體，可以回溯「它是什麼時候、由誰搬進來的」。</p>
<p><strong>Data diode（單向網路裝置）</strong>：在最高安全等級的環境裡，跨邊界的網路連線用 data diode——物理上只允許資料往一個方向流動（外部→內部，或反過來）。這比軟體防火牆更難繞過，因為它是硬體限制。data diode 的限制是不支援雙向協定（如 TCP handshake），需要用 UDP-based 的傳輸工具。</p>
<h2 id="主機層入侵偵測">主機層入侵偵測</h2>
<p>斷網環境的網路流量監控（NIDS）效果有限——內部網路通常扁平、流量加密後難以檢查。主機層入侵偵測（HIDS）是更適合斷網環境的選擇：在每台主機上監控檔案完整性、程序行為、登入模式，而非在網路層攔截。OSSEC 和 Wazuh（OSSEC 的積極維護分支）是開源的 HIDS 方案，agent 裝在每台主機、manager 集中收集告警，不需要連外。</p>
<h2 id="時程與管理層溝通">時程與管理層溝通</h2>
<p>斷網環境的安全管控初始建置時程：FreeIPA 部署 + 跟所有內部服務（GitLab、Nexus、Harbor、Vault）的 LDAP 整合約需 2-3 天。auditd 規則設定 + syslog 聚合到中央 log server 約需 1 天。掃描站建置（防毒 + hash 驗證 + 傳輸日誌）約需半天。HIDS 部署（Wazuh manager + 各主機 agent）約需 1-2 天。整體安全管控從零到運作約需 5-7 個工作天。</p>
<p>持續維護的主要工作是病毒定義更新搬運（跟隨套件更新週期）、稽核日誌的定期審閱（每週）、以及 CVE 修補的分級處理（依 CVSS 嚴重度排程）。</p>
<h2 id="跨分類引用">跨分類引用</h2>
<ul>
<li>→ <a href="/blog/infra/02-identity-credentials/" data-link-title="模組二：身分與憑證地基 — IAM 與 OIDC" data-link-desc="IAM role / policy 設計、最小權限，以及用 OIDC 短期憑證取代長期 access key">模組二：身分與憑證地基</a>：連網環境的 IAM 設計，跟本篇的離線身分方案互補</li>
<li>→ <a href="/blog/infra/air-gapped/air-gapped-principles/" data-link-title="斷網環境的通用原則" data-link-desc="離線套件管理、內容搬運、變更追蹤的共通操作模式 — 所有斷網情境都要先建立的基礎能力">斷網環境的通用原則</a>：content ferry 模式的操作流程</li>
<li>→ <a href="/blog/infra/air-gapped/air-gapped-infrastructure-services/" data-link-title="斷網環境的基礎服務：DNS、NTP、CA 與 Secret Management" data-link-desc="斷網環境裡其他所有服務的前提——內部 DNS 做名稱解析、NTP 做時間同步、內部 CA 簽發 TLS 憑證、Vault 管理機密值。這四個服務先部署、其他才能跟上。">斷網環境的基礎服務</a>：CA 和 Vault 是本篇認證和機密管理的技術基礎</li>
<li>→ <a href="/blog/backend/07-security-data-protection/" data-link-title="模組七：資安與資料保護" data-link-desc="以問題驅動方式擴充資安知識網：先定義服務環節問題，再以案例作為觸發式參考">backend 模組七：資安與資料保護</a>：應用層的安全措施</li>
</ul>
]]></content:encoded></item></channel></rss>