前面已處理身分、資料角色與 secret reference。今天把這些元件放回網路圖,分別看進入 Foundry、平台連接 PaaS,以及 Agent 連接工具的路徑。
假設 Foundry resource 的 Private Endpoint 已經 Approved,接下來還要看 DNS、PNA 與下游連線。下面先把這個部署情境拆開,再用本機資料檢查政策。
本機範例使用合成的 DependencyRoute,不開 socket。我們先驗證程式如何拒絕錯誤 origin 與不符合政策的路徑設定;Private Link、Firewall 與真實封包不在這次測試範圍。
1. Client/BFF → Foundry endpoint (inbound)
2. Foundry/Agent platform → Search/KV/Storage(PaaS dependencies)
3. Agent runtime → private tool/approved API (runtime egress)
需要一起驗:
DNS 回 private IP 只證明名稱解析;TCP 443、TLS、authentication 與 DataActions 仍要各自測。Microsoft 的 troubleshooting 也提醒,403 通常是 authentication/RBAC,而不是 Private Link 自己壞掉。Configure network isolation
Foundry resource 自己有 Private Endpoint,不會替 Search、Storage、Cosmos DB、Key Vault 與 monitoring 自動建好相同路徑。Standard Agent setup 的客戶自管資源要逐項建立 private path、DNS 與 data role:
| Dependency | 要保存的網路證據 | 身分/資料控制 |
|---|---|---|
| Azure AI Search | PE、private DNS、PNA deny | data role + Day 15 tenant filter |
| Key Vault | PE、privatelink.vaultcore.azure.net 解析、PNA deny |
Secrets User + Day 19 rotation |
| Storage | 對應 blob/file PE 與 DNS | container/object data role |
| Cosmos DB | 實際採用 API 的 private path | Agent state 與應用 tenant 分區 |
| Application Insights | 實際 topology 支援的 private path | export 前 redaction、reader RBAC |
這裡要把 inbound 與 Agent outbound 分開讀。Inbound Private Endpoint 會依實際 setup 有不同支援路徑;涉及 customer-owned Search/Storage/Cosmos DB 與 Agent outbound isolation 的文件,目前指向 Standard setup + private networking。Basic 使用 Microsoft-managed backing resources,不能拿它當成「我已私接自己的 Search」的證據。另一方面,另一份 isolation 文件仍列出 Basic private-network template;因此文章不把一句 setup 標籤推廣成整套保證,而是保存實際 template、runtime、dependency ownership,並逐條測 packet path。若 Search indexer 也要穿越 Private Endpoint,還要檢查它的 execution environment;否則可能出現 indexer 沒資料、Agent 查詢卻沒有明顯錯誤的 silent failure。
即使 Azure dependencies 都走 Private Link,poisoned tool description 仍可能誘導 Agent 呼叫未核准 MCP server 或 Internet endpoint。網路可達不代表工具可用,工具可用也不代表這次 action 有權執行。
網路是否真的照設定運作,需要實際連線觀察。這裡的 NetworkBoundaryPolicy.validate() 先負責檢查下列設定:
allowlisted host
+ bare HTTPS origin(僅 host,可省略 /,port 只能是 443)
+ trusted egress-allow outcome
+ identity-auth posture
+ PNA/private-DNS posture
Day 18 的 RBAC 先檢查 principal、plane、action 與 scope。這一層網路 policy 則只接受 bare origin,遇到 path、query 或 fragment 就回 EGRESS_ENDPOINT_DENIED。API path 與業務物件授權交由可信 adapter/PEP 處理;目前沒有 path-level egress authorization。
固定同一組 principal 與 RBAC,比較加入網路檢查前後,public route 是否仍能取得 Receipt。

本機政策檢查的前後結果是 Receipt=1 與 Receipt=0。這條路徑沒有 socket、DNS lookup、Private Endpoint 或 Azure 服務端紀錄,結果只涵蓋設定與政策判斷。
使用者仍然只會問「幫我查一下國內出差住宿費的上限」,不需要知道 DNS 或 PNA。本機測試略過模型,直接把同一項 dependency 需求配上不同路徑設定,觀察政策在哪個欄位拒絕。
這個 Lab 只使用 .invalid endpoint,不開 socket。DependencyRoute 記錄的是合成的路徑設定,egress_allowed 與 identity_auth 也由測試框架提供,並非封包、Firewall 或 Entra 的觀測結果。接到正式 adapter 時,這些值必須來自可信設定與實際檢查,不能接受 prompt 或 request body 自行填入 true。
三個主要 fixture:
compliant:所有欄位正確,作為正向分母。public:在 component matrix 中同時使用未核准 host、PNA 開啟、private DNS 未解析、identity auth 關閉。blocked_egress:host、bare origin、identity 與 private posture 都正確,只把 egress_allowed 改成 false。接著逐欄 mutation:
修補前後 cumulative replay 的 principal 已通過 Day 16 workload identity,也具備 Day 18 Search reader fixture;這一組 public_route 特別把 identity_auth=True 固定住, 只比較 network delta。before 回 LEGACY_NETWORK_ROUTE_UNCHECKED 並留下一張 local executor Receipt;after 的第一個 fail-closed reason 是 DEPENDENCY_ORIGIN_MISMATCH。這不是 component matrix 的 EGRESS_HOST_DENIED:前者表示 trusted registry 已先判定「這個 dependency 不該去這個 origin」,後者才是較底層 allowlisted-host preflight。PNA、private DNS、identity 與 host 的各欄 failure 仍在 component matrix 個別保存,不要把兩組資料混成同一列。
D20-A03 再交換兩個已核准的 host:Search action 被指向 Vault origin。單看 host allowlist 會通過,但 TrustedDependencyRegistry 會一起比對 dependency、origin、plane、action、scope 與 auth mode,因此回傳 DEPENDENCY_ORIGIN_MISMATCH。核准過的網址,仍要用在對應的操作上。
比較 network delta 時,先保持身分與 RBAC 條件相同。否則請求可能先被權限拒絕,無法確認今天的網路政策是否真的執行。
接著核對 dependency、plane、action、scope、identity 與 origin,確認它們屬於同一筆操作。

各種錯誤欄位都有自己的拒絕原因,符合條件的 private route 則保留為合法對照。這份 registry 檢查設定之間的關係,沒有觀測 DNS、socket、TLS 或服務端授權;網路可達、工具可用與當次操作有權,仍要分開驗證。
TrustedDependencyRegistry 是 server-owned configuration。它從已註冊的功能路徑派生 dependency,不接受 prompt 自報 dependency=search。它先把 dependency 綁到核准的 origin、data plane、action、 scope 與 authentication mode;之後才交給 Day 18 RBAC 與 NetworkBoundaryPolicy。順序是刻意的:先擋 confused deputy,再處理「這條路本身是否符合 private/egress posture」。
NetworkBoundaryPolicy.validate() 成功時回傳空 list,失敗時列出一個或多個 reason code。下面用 repository 的實際介面檢查合成 route:
from magic_panda_agent.network import (
DependencyRoute,
NetworkBoundaryPolicy,
)
policy = NetworkBoundaryPolicy(
allowed_hosts=frozenset({"search.private.example.invalid"}),
require_private_path=True,
)
route = DependencyRoute(
name="search",
endpoint="https://search.private.example.invalid",
public_network_access=False,
private_dns_resolved=True,
egress_allowed=True,
identity_auth=True,
)
failures = policy.validate(route)
assert failures == []
目前實作只會回下列 failure code:
EGRESS_HOST_DENIED
EGRESS_ENDPOINT_DENIED
EGRESS_POLICY_DENIED
IDENTITY_AUTH_REQUIRED
PUBLIC_NETWORK_ACCESS_ENABLED
PRIVATE_DNS_NOT_RESOLVED
bare-origin contract 接受 https://host、尾端 /,以及顯式 :443 的兩種形式;scheme 大小寫與 host 大小寫會正規化。HTTP、FTP、userinfo、非 443 port、path、query、fragment、前後空白與 malformed URL 全部得到 EGRESS_ENDPOINT_DENIED。這份 contract 沒有真的查 DNS,也沒有打開 socket。
Foundry managed virtual network 提供 allow Internet outbound 與 allow only approved outbound 等模式,也能從 managed network 建立到 Search、Key Vault、Storage 等支援服務的 managed Private Endpoint。官方文件目前說明這些 managed PE 需使用 CLI 建立,Portal UI 尚未提供;Foundry resource managed identity 還要具備建立/核准 connection 所需權限。Managed virtual network
這裡有幾個會影響成本與復原的限制:
networkInjections 等屬性要在 resource 建立時設定,不能事後補上。這些條件會影響拓撲、費用、觀測與重建方式,因此 network mode 要在建立資源前決定,並保存選擇理由。後續若要切換,也得先確認哪些資源需要重建。
Microsoft 的 GA overview 將 Foundry core platform、RBAC 與 virtual network integration 列入 GA enterprise capabilities,但同一份 readiness 表仍將 Tracing VNet 標為 Preview,並提醒不是所有 GA 功能都完整支援 network isolation。Foundry GA overview
此外,network isolation 文件仍以 hosted (preview) agents 描述部分 outbound injection 路徑;hosting 總覽把 managed Hosted Agents 標為 GA,Agent Framework 的 Hosted Agents 子頁卻仍標 Preview,部分 session/API 也要求 preview surface。第一方文件的粒度與更新節奏沒有完全對齊,文章因此不寫「Foundry networking 全面 GA」,而是逐項記錄:
功能狀態要記到實際路徑:某個 hosted integration 是 Preview,不代表所有 RBAC 或 Private Link 都是 Preview;平台核心 GA,也不能用來推定所有 networking 組合。
最後比較五種 endpoint 格式,確認只有符合條件的 bare HTTPS origin 通過。

前四筆都回傳 EGRESS_HOST_DENIED 與 EGRESS_ENDPOINT_DENIED;bare_https_origin 的 failure_codes 為空,allowed=true。這只驗 URL 格式,擋不住 DNS rebinding、redirect 或實際路由改變。若允許 redirect,每一跳仍要重新檢查。
進入 day20/ 後執行:
uv run pytest tests/stages/day20/test_acceptance.py -q
這組驗收要確認:
validate() 回傳空 list。plain_http、credential_in_origin、non_default_port、path_suffix 與 bare_https_origin 五筆;前四筆同時回 EGRESS_HOST_DENIED/EGRESS_ENDPOINT_DENIED,最後一筆 failure list 為空且 allow。egress_allowed=False 單獨得到 EGRESS_POLICY_DENIED。DEPENDENCY_ORIGIN_MISMATCH。.invalid,network_io_performed=false。Day 20 的驗收記錄為 5 passed。Cumulative replay 有兩張本機 Receipt,分別來自 before public route 與 after compliant route,side effect 都是 0。External 與 cloud calls 為 null,因為 preflight 沒有網路 observer;REAL_NETWORK_PATH_NOT_EXERCISED 仍保留。
用下面兩條命令,分別查看 public route 與 registry 的比對結果:
PYTHONPATH=src:. uv run python -c \
'import json; from magic_panda_agent.stages.day20 import cumulative_stage_replay; print(json.dumps(cumulative_stage_replay(), sort_keys=True))'
PYTHONPATH=src:. uv run python -c \
'import json; from magic_panda_agent.stages.day20 import dependency_registry_evidence; print(json.dumps(dependency_registry_evidence(), sort_keys=True))'
最後看 endpoint 格式矩陣:HTTP、userinfo、非 443 port 與 path suffix 都回 EGRESS_HOST_DENIED/EGRESS_ENDPOINT_DENIED,只有符合條件的 bare HTTPS origin 通過。這組檢查沒有呼叫工具,Receipt 與副作用都是 0;外部與雲端呼叫則沒有量測:
PYTHONPATH=src:. uv run python -c \
'import json; from magic_panda_agent.stages.day20 import endpoint_shape_evidence; print(json.dumps(endpoint_shape_evidence(), sort_keys=True))'
今天的本機 policy 只能拒絕不合規的 endpoint 字串。真正的 Foundry 網路驗收,要從同一個來源環境依序查 DNS、測 TCP/TLS、呼叫服務,再用正確與錯誤的 Entra 身分比較結果。這個順序能把「找不到私有位址」、「連不上服務」和「服務拒絕權限」拆開;Search、Key Vault 與 Agent egress 都要各自留一列。
實際連線時,可以依下面的矩陣逐項觀察。這是部署後應檢查的結果,和前面的本機政策測試分開:
inside VNet:服務 hostname → private IP;443 可達;正確 identity 成功
outside VNet:public endpoint 被拒絕
remove PE/DNS link:dependency fail closed,不走 public fallback
unapproved FQDN/non-bare endpoint:留下 egress deny evidence
wrong identity:網路可達,但服務端回 401/403
Search/KV/Storage:每個 dependency 分別完成同一組測試
NetworkBoundaryPolicy.validate() 檢查設定,這份矩陣則要靠 DNS query、socket、服務端回應與 Firewall log 來確認。這次本機 lab 只執行了前者。
Private Endpoint 不會阻止合法 identity 被濫用,也不會修正錯誤的 Search tenant filter。已核准 MCP server 仍可能被供應鏈攻擊;redirect 也可能把第一次通過 allowlist 的 request 帶往另一個 origin。正式 adapter 應對 redirect fail closed 或重新授權每一跳,並由 trusted tool registry 派生 dependency/operation。
allow-only-approved outbound 會增加 Firewall、Private Link、DNS 與離線供應鏈的成本。完全關閉 Internet 也可能讓套件下載、映像更新或 incident-response 工具失效;要事前準備 private registry、更新流程與 break-glass,而不是事故時臨時把 PNA 打開。
NIST SP 800-207 不把網路位置當成信任。private IP 只能證明一部分路徑;正確/錯誤 identity、目標 resource、operation 與 401/403 仍要一起測。
明天會在這些確定性邊界前面加入 Prompt Shields。它可以提供 attack signal,卻不會替 identity、RBAC、tenant filter 或 egress policy 做授權決定。