iT邦幫忙

2026 iThome 鐵人賽

DAY 18
0
AI Security

Microsoft Foundry 的 AI Agent 攻防實戰:建立高資安與可治理的 Agent 系統系列 第 18

Day 18|Microsoft Foundry 的 AI Agent 攻防實戰:Azure Owner 不是宇宙萬能管理員,Foundry RBAC 到底管哪一層?

  • 分享至 

  • xImage
  •  

Day 16 確認呼叫者是誰,Day 17 再確認 Agent 替誰做事。今天才輪到角色與 scope 上場,因為 RBAC 若綁錯 principal,再漂亮的 least-privilege 表格也只是一張擺錯座位的名牌。

大魔術熊貓工程司的 platform admin 可以建立 Foundry resource、部署模型、設定網路;這不代表該 principal 能直接呼叫 Agent endpoint、查 Azure AI Search、讀 Key Vault secret,更不代表他能核准使用者的採購單。Azure Owner 很大,但還沒有大到能兼任宇宙萬能管理員。

為了不把 Day 17 的業務使用者 Alice 和平台管理角色攪在一起,本文稱這個 persona 為 platform admin;cumulative replay 裡的實際 principal alias 是 platform-owner

先備名詞:RBAC 管的是哪個身分、哪個範圍、哪一種操作

  • RBAC:以角色決定某個 principal 在特定 scope 能做什麼;角色名稱很大,不代表能跨越所有 scope 與資料平面。
  • Control plane/Data plane:前者管理資源設定,後者讀寫資源內的資料。能建立 Key Vault,不代表能讀取 vault 裡的 secret。
  • Actions/DataActions:Azure role definition 分別描述控制平面與資料平面的操作。
  • Scope:角色生效的資源邊界,例如 subscription、resource group、project 或單一資源。授權鍵還必須綁 immutable tenant 與 object ID,不能只比對容易碰撞的顯示名稱。

Threat:四張「可以做什麼」的表被疊成一張

Control plane assignment

畫面判讀目標: 核對platform-owner 在 control/foundry/search/keyvault 四種 request 上的矩陣的 canonical runtime fields。

platform-owner 在 control/foundry/search/keyvault 四種 request 上的矩陣。

Control-plane Owner 不自動取得 data-plane actions。 可觀察狀態:control assignment 只允許 deploy;跨三個 data plane 均 RBAC_DATA_ACTION_DENIED,summary 與 call counts 可見。 Claim boundary:只證明本機 synthetic contract;不是 Azure RBAC emulator,也不代表真實 effective permissions。 此子畫面只涵蓋platform-owner 在 control/foundry/search/keyvault 四種 request 上的矩陣。

Foundry data-plane assignment

畫面判讀目標: 核對Foundry User 對 deploy、invoke、search、secret 的四格矩陣的 canonical runtime fields。

Foundry User 對 deploy、invoke、search、secret 的四格矩陣。

Foundry User 的資料動作不外溢到控制、Search 或 Key Vault。 可觀察狀態:foundry-data assignment 只允許 invoke_agent,其餘 requested plane 均拒絕。 Claim boundary:只證明本機 synthetic contract;不是 Azure RBAC emulator,也不代表真實 effective permissions。 此子畫面只涵蓋Foundry User 對 deploy、invoke、search、secret 的四格矩陣。

Search data-plane assignment

畫面判讀目標: 核對Search Index Data Reader 的四格 cross-plane matrix的 canonical runtime fields。

Search Index Data Reader 的四格 cross-plane matrix。

Search role 只涵蓋 Search data plane。 可觀察狀態:search-data assignment 只允許 search;deploy、invoke_agent、read_secret 均拒絕。 Claim boundary:只證明本機 synthetic contract;不是 Azure RBAC emulator,也不代表真實 effective permissions。 此子畫面只涵蓋Search Index Data Reader 的四格 cross-plane matrix。

Key Vault data-plane assignment

畫面判讀目標: 核對Key Vault Secrets User 的四格 cross-plane matrix的 canonical runtime fields。

Key Vault Secrets User 的四格 cross-plane matrix。

Key Vault role 不取得其他平面的權限。 可觀察狀態:keyvault-data assignment 只允許 read_secret;其他三個 action 均拒絕。 Claim boundary:只證明本機 synthetic contract;不是 Azure RBAC emulator,也不代表真實 effective permissions。 此子畫面只涵蓋Key Vault Secrets User 的四格 cross-plane matrix。

這張 UI 的資料直接來自 authorization_plane_matrix_evidence():四個 synthetic principal 分別帶著 control、Foundry、Search、Key Vault assignment,對四種 request 跑出 16 個 executor outcomes。它沒有 application-object policy;後文的 Magic Panda business PEP 是架構上還要再通過的一層,不能冒充成這次 Day 18 runtime 已執行的第五種授權。

Microsoft Foundry 的 authentication 文件把 control plane 與 data plane 明確分開:resource、project、model deployment 與 connection 建立屬於控制平面;建立 Agent、evaluation、tracing 等工作則屬資料平面。Azure RBAC role definition 以 Actions 表達 control-plane 操作,以 DataActions 表達 data-plane 操作。Foundry authentication and authorization(查閱:2026-08-03)

在工程司案例中,還要再加上 connected resources 與業務政策:

Azure control plane
├─ 建立 Foundry resource/project
├─ 部署模型與建立 connection
└─ 建立 role assignment、network resource

Foundry data plane
├─ 建立/更新 Agent
└─ 呼叫指定 Agent endpoint

Connected-resource data plane
├─ Search query
└─ Key Vault secret get

Magic Panda business PEP
└─ subject × tenant × canonical object × action × state

四層都可能使用 Azure/Entra 身分,但回答的問題不同。Foundry Agent Consumer 沒有 Alice 的費用 owner、Bob 的核准上限或採購單狀態;Foundry endpoint 回 200 不能代替業務授權。

Attack:把一個平面的 Owner 攤平成所有平面的 allow

Flat Owner:Search data attack

畫面判讀目標: 核對flat Owner 修補前後的 Search data-plane 比較的 canonical runtime fields。

flat Owner 修補前後的 Search data-plane 比較。

先隔離 flat Owner 對 Search 的越權。 可觀察狀態:search before=allowed/LEGACY_OWNER_SPANS_DATA_PLANE,after=denied/RBAC_DATA_ACTION_DENIED,external_calls=0。 Claim boundary:synthetic role semantics 不描述 Azure Owner 的完整實際權限。 此子畫面只涵蓋flat Owner 修補前後的 Search data-plane 比較。

Flat Owner:Key Vault attack

畫面判讀目標: 核對flat Owner 修補前後的 secret read 比較的 canonical runtime fields。

flat Owner 修補前後的 secret read 比較。

再驗證 flat Owner 不再跨入 Key Vault data plane。 可觀察狀態:read_secret before=allowed,after=denied;Receipt count 由 1 降為 0,cloud_calls=0。 Claim boundary:synthetic role semantics 不描述 Azure Owner 的完整實際權限。 此子畫面只涵蓋flat Owner 修補前後的 secret read 比較。

如果這個管理功能前面有聊天介面,platform admin 頂多會說:「剛部署完,幫我跑一下供應商連線檢查。」他不需要知道 Key Vault 的函式名稱,也不會在句尾指定要回哪個 reason code。

本篇故意不拿模型能否把這句話翻成工具呼叫來評分,而是直接測 executor 的授權邊界。vulnerable profile 的錯誤不在 Azure 服務端,也不在 user message,而在本機 executor:只要 assignments 中看到同一 principal 在 control plane 擁有 Owner,舊版 _rbac_decision() 就把它推成其他 plane 的 allow。於是 platform-owner 原本只在合成 subscription control plane 擁有 deploy,卻被舊 executor 放行去讀 Key Vault secret。read_secret、target scope 與預期結果都由測試框架提供,不塞回對話裡提示答案。

文章直接呼叫真正的 stage API,不另寫一個不存在的 legacy_allows()

from magic_panda_agent.stages.day18 import flat_owner_attack_evidence

evidence = flat_owner_attack_evidence()
search, keyvault = evidence["comparisons"]

assert search["before"]["reason_code"] == "LEGACY_OWNER_SPANS_DATA_PLANE"
assert keyvault["before"]["reason_code"] == "LEGACY_OWNER_SPANS_DATA_PLANE"
assert search["after"]["reason_code"] == "RBAC_DATA_ACTION_DENIED"
assert keyvault["after"]["reason_code"] == "RBAC_DATA_ACTION_DENIED"

其中 Key Vault 的 before outcome 是:

{
  "action": "read_secret",
  "actor": "platform-owner",
  "allowed": true,
  "resource_id": "/vault/magic-panda/secrets/vendor-token",
  "reason_code": "LEGACY_OWNER_SPANS_DATA_PLANE",
  "receipt_count": 1,
  "side_effect_count": 0,
  "details": {
    "plane": "keyvault-data",
    "rbac_enforced": false
  }
}

這裡沒有真的連 Azure Key Vault。它要固定的 failure 是「程式把角色名稱當成跨平面超能力」,而不是宣稱 Azure Owner 服務端會允許讀 secret。

同一類錯誤也會發生在 Foundry:Microsoft 官方角色表顯示,Azure OwnerContributor 具有大量控制平面能力,卻不因此取得 Foundry project 的 build/develop DataActions 或 Agent endpoint interaction。只需呼叫 Agent 的 consumer,應使用 Foundry Agent Consumer,不必升成 Foundry UserFoundry RBAC(查閱:2026-08-03)

Fix:角色、平面、動作與 scope 必須同時符合

Scope:child 與 lookalike

畫面判讀目標: 核對合法 child scope 與 lookalike prefix 的對照的 canonical runtime fields。

合法 child scope 與 lookalike prefix 的對照。

合法子資源與字串前綴偽裝必須分開。 可觀察狀態:child_scope=allow;lookalike_scope=RBAC_DATA_ACTION_DENIED,external_calls=0。 Claim boundary:不涵蓋 Azure deny assignments、PIM、propagation 或 condition expressions。 此子畫面只涵蓋合法 child scope 與 lookalike prefix 的對照。

Scope:traversal 與 foreign tenant

畫面判讀目標: 核對path traversal 與跨 tenant scope 的拒絕的 canonical runtime fields。

path traversal 與跨 tenant scope 的拒絕。

canonical scope containment 同時拒絕 traversal 與跨 tenant。 可觀察狀態:traversal_scope、foreign_tenant 均 denied,Receipt count=0,cloud_calls=0。 Claim boundary:不涵蓋 Azure deny assignments、PIM、propagation 或 condition expressions。 此子畫面只涵蓋path traversal 與跨 tenant scope 的拒絕。

本機 RoleAssignment 不以角色名字直接決定一切,而是把授權輸入固定為:

tenant + principal + plane + role + scope

執行時再帶入 action + target_scope

from magic_panda_agent.stages.day18 import RoleAssignment, rbac_allows

assignments = (
    RoleAssignment(
        principal="platform-owner",
        plane="control",
        role="Owner",
        scope="/subscriptions/synth",
        tenant_id="bamboo-hq",
    ),
    RoleAssignment(
        principal="vault-agent",
        plane="keyvault-data",
        role="Key Vault Secrets User",
        scope="/vault/magic-panda",
        tenant_id="bamboo-hq",
    ),
)

assert rbac_allows(
    assignments,
    principal="platform-owner",
    tenant_id="bamboo-hq",
    plane="control",
    action="deploy",
    scope="/subscriptions/synth/resourceGroups/lab",
)

assert not rbac_allows(
    assignments,
    principal="platform-owner",
    tenant_id="bamboo-hq",
    plane="keyvault-data",
    action="read_secret",
    scope="/vault/magic-panda/secrets/vendor-token",
)

scope 比對使用完整 path segment,而不是字串 prefix。/vault/magic-panda 可以涵蓋真正的 child resource,但不能讓 /vault/magic-panda-evil 或含 .. 的 traversal-like path 通過。assignment、decision、Receipt 與 audit event 也都保留 tenant;另一租戶即使剛好有相同的 principal="vault-agent",仍必須被拒絕。

這仍只是 deterministic policy fixture,不是 Azure RBAC emulator。它的用途是讓「不能跨 plane 推導」成為 regression contract;真實 Azure allow/deny 必須另外執行。

Foundry built-in role 怎麼選

截至 2026-08-03,核心角色可先依 persona 拆成:

Persona 建議 Foundry role/scope 仍需另外處理
只呼叫 Agent 的 FastAPI/使用者 Foundry Agent Consumer,project 或個別 Agent scope 使用者業務授權、下游 OBO
建立與測試 Agent 的開發者 Foundry User,project scope;resource 另給必要 Reader 外部 Search/KV data role
管理 project 與發布工作的負責人 Foundry Project Manager,依官方要求選 scope 不自動取得業務核准權
resource/account 管理者 Foundry Account Owner/經審查的管理角色 不自動讀下游資料
production Agent runtime 發布後 distinct Agent identity 目標資源最小 DataActions

Owner 沒有因此直接取得所有 DataActions,但擁有廣泛 role-assignment 能力的人可能替自己或他人加上 data role。正式環境仍要用 PIM、條件/deny assignment、權限定期覆核與 separation of duties 控制這條間接升權路徑。

Microsoft 正在把舊的 Azure AI User/Owner/Account Owner/Project Manager 名稱改為 Foundry ...。官方建議 IaC 使用 role definition ID,避免 rollout 期間顯示名稱不一致;目前兩個常用 ID 為:

Foundry Agent Consumer  eed3b665-ab3a-47b6-8f48-c9382fb1dad6
Foundry User            53ca6127-db72-4b80-b1b0-d745d6d5456d

GUID 能避開 rename,不能保證 permissions 永遠不變。built-in role 仍由 Microsoft 管理,release gate 應保存 role ID、查閱日期、effective scope 與實際 allow/deny。

查核時還遇到一個不能用漂亮表格掩飾的文件落差:2026 年 5 月版 authentication 說明與較新的 2026 年 7 月 RBAC 矩陣,對 Foundry Project Manager 是否能管理模型的描述不完全一致。本篇採較新的 RBAC 矩陣作為規畫基準,但不把文件選邊站當成執行證據;雲端測試仍須依 model deployment type、實際 operation 與 assignment scope 各做一次正負向驗證。

Agent scope 只證明 endpoint access

Foundry 支援在個別 Agent scope 指派角色,適合表達「consumer 能呼叫 Agent A,不能呼叫 Agent B」。但官方文件目前明確限制:agent-scope assignment 只針對 agent endpoint access 評估,不會授予 broader control-plane 或 management permission。Agent-scope role assignments(查閱:2026-08-03)

雲端 matrix 因此至少要有:

Principal Operation Target 預期
Consumer A endpoint interaction Agent A allow
Consumer A endpoint interaction Agent B deny
no-role principal endpoint interaction Agent A deny
Consumer A Agent write/publish operation Agent A deny
developer principal 同一 write operation/payload Agent A allow

最後一列不能省。只有 Consumer 403,卻沒有同一 request contract 的 developer positive control,無法排除 endpoint、API version 或 payload 本身錯誤。

如果要在實際環境指派 Agent-scope Consumer,可依官方 scope pattern 使用 CLI;以下只是一份待填參數的操作規格,不會在本篇自動執行:

az role assignment create \
  --assignee-object-id "$PRINCIPAL_OBJECT_ID" \
  --assignee-principal-type ServicePrincipal \
  --role "eed3b665-ab3a-47b6-8f48-c9382fb1dad6" \
  --scope "$AGENT_RESOURCE_SCOPE"

不要把 subscription ID、tenant ID、object ID 或完整 resource scope 放進文章截圖。

外部 Search 與 Key Vault 不會跟著 connection 自動授權

Search + Key Vault combined assignment

畫面判讀目標: 核對同時具備兩個 data-plane assignment 時的 search/read-secret allow的 canonical runtime fields。

同時具備兩個 data-plane assignment 時的 search/read-secret allow。

雙角色案例只證明明確的聯集,不是隱含權限。 可觀察狀態:assignment_set=both 的 search 與 read_secret 均 RBAC_ALLOW;connection_object_exercised=false。 Claim boundary:沒有建立或呼叫 Foundry connection;assignment 是 deterministic fixture,不是 Azure effective access。 此子畫面只涵蓋同時具備兩個 data-plane assignment 時的 search/read-secret allow。

Search-only assignment

畫面判讀目標: 核對Search-only principal 對 search 與 read_secret 的分離的 canonical runtime fields。

Search-only principal 對 search 與 read_secret 的分離。

Search-only principal 無法讀取 Key Vault secret。 可觀察狀態:search_only 對 search=allow、read_secret=deny,external_calls=0。 Claim boundary:沒有建立或呼叫 Foundry connection;assignment 是 deterministic fixture,不是 Azure effective access。 此子畫面只涵蓋Search-only principal 對 search 與 read_secret 的分離。

Key-Vault-only assignment

畫面判讀目標: 核對Key-Vault-only principal 對 search 與 read_secret 的分離的 canonical runtime fields。

Key-Vault-only principal 對 search 與 read_secret 的分離。

Key Vault principal 無法反向取得 Search data access。 可觀察狀態:keyvault_only 對 search=deny、read_secret=allow,cloud_calls=0。 Claim boundary:沒有建立或呼叫 Foundry connection;assignment 是 deterministic fixture,不是 Azure effective access。 此子畫面只涵蓋Key-Vault-only principal 對 search 與 read_secret 的分離。

downstream_role_separation_evidence() 以同一個 downstream-runtime 依序執行 bothsearch_onlykeyvault_only 三組 assignments,共得到六個 runtime outcomes。這能證明本機 executor 沒有把 Search role 當成 Key Vault role,反之亦然;它不能證明 connection 自己沒有授權效果,因為這次 replay 根本沒有建立 connection object。

Foundry connection 解決的是平台如何找到與連接資源;Azure AI Search 與 Key Vault 仍有自己的 data plane、角色、網路與稽核。至少要分開測:

  • Search query:對應的 Search data role,加上 Day 15 的 server-derived tenant filter。
  • Key Vault secret read:runtime principal 使用 Key Vault Secrets User
  • Key Vault Contributor:控制平面管理,不等於可以讀 secret value。
  • Agent 下游存取:角色指派到實際使用的 Agent identity 或明確 connection identity,不用 Agent 名稱猜 principal。

最後還要進大魔術熊貓工程司的 PEP。Alice 即使可呼叫 Agent endpoint,也只能操作自己被授權的 canonical object;Azure 200 只表示這一層通過。

Foundry Project 是開發資產與 RBAC scope,不是完整的 SaaS tenant boundary。bamboo-hqmoon-rabbit-lab 若共用 project,Day 15 的 server-derived tenant filter、cache partition、by-ID read check 與業務 PEP 一項都不能拿掉。

Test:每個 allow 都要帶著相鄰的 deny

本節不另放第五張 UI 圖。原規畫的 Agent A/B、no-role consumer、consumer write 與 developer write 是尚未執行的雲端 matrix;若拿 Day 18 的本機 scope deny 重複包裝,畫面只會重複前兩張矩陣,仍無法證明那五個 principal 的真實 endpoint access。截圖數量因此依可觀察內容收斂為四張,而不是為了湊固定張數保留一張不存在的狀態。

進入 day18/ 後執行:

uv run pytest tests/stages/day18/test_acceptance.py -q

V2 acceptance 必須確認:

  • 四個已實作 plane 的 4×4 runtime matrix 只有四個 matching tuple allow。
  • legacy Owner 對 Search 與 Key Vault 都錯誤 allow,fixed executor 對兩者都 deny。
  • platform-owner 可以在 control plane deploy
  • 同一個 Owner 不能被推導成 Search reader 或 Key Vault secret reader。
  • 只有 scope 相符的 vault reader 能讀指定 secret reference。
  • lookalike 與 traversal-like scope 都 fail closed。
  • 同一 workload 的 Search-only 與 Key-Vault-only assignments 只允許各自的 plane。
  • before profile 的跨 plane allow 產生 receipt;after profile 得到 RBAC_DATA_ACTION_DENIED 且 receipt 為 0。
  • cumulative replay 中 Day 16 workload identity 與 Day 17 delegated context 仍在,Day 19 secret rotation 尚未偷跑。

本次本機 QA 為 7 passed。四張 required app UI 分別投影 authorization_plane_matrix_evidence()flat_owner_attack_evidence()scope_matrix_evidence()downstream_role_separation_evidence() 的實際回傳值;不從函式原始碼、角色名稱或文章文字推導畫面。所有 helper 都固定回報 external_calls=0cloud_calls=0,所以這仍是本機 RBAC fixture,不是 Azure/Foundry role-assignment、connection 或 data-plane request evidence。

雲端驗證邊界:PENDING-CLOUD

V2 尚未建立或重跑 Agent A/B、Consumer/developer principal 與 Agent-scope role assignment,也沒有對真實 Search、Key Vault 執行 allow/deny。角色傳播、繼承、group membership、published Agent identity 與 connection auth mode 都還沒有雲端 evidence。

因此本篇可以說明官方角色與本機契約,不能寫成「Foundry RBAC 已於 V2 驗證完成」。Foundry portal 與 Agents core 的 GA 狀態也不會自動替尚未執行的 role matrix 變綠。Foundry GA overview(查閱:2026-08-03)

Residual Risk:RBAC 是會變動的狀態,不是一次性貼紙

group 成員、role definition、scope inheritance、緊急指派、Agent 發布後的新 identity,以及 migration 都可能改變 effective permission。剛建立 assignment 後得到的 403 也可能只是 propagation delay;CI 應使用 bounded retry 並標記 timeout,不能固定睡幾秒就把它當成穩定 deny。

NIST SP 800-207/800-207A 關心的是 principal 對特定 resource 與 operation 的當次決策。對大魔術熊貓工程司來說,角色名稱只是輸入之一;plane、scope、operation、business object 與實際副作用要一起留下 evidence。

明天會把同一組 principal 放到 Key Vault,看看 secret 搬進 vault 後,舊版本、cache 與五個輸出 sink 會不會還握著影印本不放。

第一方參考資料


上一篇
Day 17|Microsoft Foundry 的 AI Agent 攻防實戰:三張識別證都是真的,Agent 為什麼仍替 Alice 越權?
系列文
Microsoft Foundry 的 AI Agent 攻防實戰:建立高資安與可治理的 Agent 系統18
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言