iT邦幫忙

2026 iThome 鐵人賽

DAY 2
0
AI Security

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

Day 02|Microsoft Foundry 的 AI Agent 攻防實戰:15 分鐘跑通 Project、模型與 Keyless Python

  • 分享至 

  • xImage
  •  

昨天我們故意沒碰雲端,先把「模型想做什麼」和「工具真的做了什麼」分開。今天
把 Microsoft Foundry 接上來,但目標很窄:讓一段 Python 程式透過 Project
endpoint
Microsoft Entra ID 呼叫已部署模型,取得一段非空回應。

不建立工具、不開 MCP、不接 Search,也不把 API key 貼進 .env。第一天進新
環境先只跑最小連線,讓後續問題能落在明確的一層。

標題寫 15 分鐘,指的是訂閱、權限、quota 與目標 region 都已經可用時的快速路徑。
如果 model quota 不足、角色剛指派尚未生效,或組織政策不允許建立資源,等待時間
不算是讀者手速問題。本文會把這些阻礙分開診斷,不用「請稍後再試」收掉整段。

今天完成後,手上應該有四樣東西

  1. 一個新式 Microsoft Foundry Project,或你已獲授權使用的既有 Project。
  2. 一個已完成部署的模型,以及部署名稱
  3. 一個形狀正確的 Project endpoint。
  4. 一次由 AzureCliCredential 取得 Entra token 的 Python smoke call。

截至 2026-08-03,官方文件把新平台稱為 Microsoft FoundryAzure AI StudioAzure AI Foundry 與 hub-based project 屬於舊名稱或 classic 資源
模型;舊套件、resource provider 與網址仍可能保留 azure-ai 字樣。本文只走新
Foundry portal 的 Foundry Project,不混用 classic hub project 或舊 connection
string。

小學堂:Resource、Project、Deployment 與 Endpoint

這四個名詞常在同一個畫面出現。Portal 裡名字很多,先別把 Project 和 deployment
認成雙胞胎;把它們放回各自的位置:

名稱 本文用途 容易搞混的地方
Foundry resource Azure 管理與治理的上層資源 不是終端使用者的業務 tenant
Foundry Project 組織模型、Agent 與 project-scoped assets 不是模型本身
Model deployment 把選定模型部署成可呼叫名稱 FOUNDRY_MODEL 要填 deployment name
Project endpoint 程式進入 Project API 的位址 不是 resource-level OpenAI endpoint

官方 REST reference 給的 Project endpoint 形狀是:

https://<foundry-resource>.services.ai.azure.com/api/projects/<project-name>

Responses API quickstart 明確指出,Project endpoint 才會進入 project-scoped data、
工具、觀測與治理路徑。若只需要 OpenAI model 與標準工具,resource-level endpoint
可能有不同適用情境;本文選 Project endpoint,是因為後面 28 天要一路追蹤
Foundry Project、Agent、評測與治理邊界。

步驟一:先確認 CLI 登入的是正確訂閱

需要 Azure CLI 2.67.0 以上。先檢查版本,再登入:

az version
az login
az account show --query '{name:name,tenantId:tenantId,user:user.name}' --output table

最後一行只供本人核對,不要直接拿它截圖;tenant ID 與帳號都應遮蔽。若登入
了多個訂閱,使用名稱或 ID 明確切換:

az account set --subscription '<your-subscription-name-or-id>'

本文的本機程式只使用 AzureCliCredential。它把「目前 az login 的使用者」
帶到 Python,適合開發者 smoke test;正式 workload 到 Day 16 才改用受管身分,
不在今天用 DefaultAzureCredential 的多重 fallback 掩蓋憑證來源。

步驟二:建立或選擇 Foundry Project

Portal 快速路徑

  1. 開啟 https://ai.azure.com 並登入。
  2. 確認 New Foundry 切換已開啟。
  3. 第一次使用時,在 Project 選單選 Create a new project;若已載入其他
    Project,按左上角 Project 名稱,再選 Create new project
  4. Project name 可使用 magic-panda-security-lab
  5. 展開 Advanced options,選擇 resource group 與 region。
  6. Create project,等到 Project overview/welcome screen 出現。

Portal 圖說明:作者/owner 已明確核准以完整產品 viewport 公開其 Microsoft MVP profile avatar、author display name 與 public project alias;MVP 身分尚未由本 repository 獨立驗證。畫面不含 email、tenant/subscription/object ID、URL/browser chrome、endpoint/key 或其他秘密。這張圖只用來說明 Project 層級與導覽位置,不代表 Microsoft 對本文或其安全結論背書。

畫面判讀目標: 確認讀者位於 Microsoft Foundry 的 Project home/overview,而不是 classic hub 或其他 Azure 資源頁。

Microsoft Foundry Project home/overview 顯示 Project 層級導覽、Build 入口,以及 owner-attested 作者頭像、公開顯示名稱與 project alias。

Owner-attested 作者頭像、公開顯示名稱與 project alias 是刻意公開項目;Project overview 仍只確認 portal 層級,不是權限或執行證據。 可觀察狀態:Microsoft Foundry Project home/overview 標題、Project 層級導覽與 Build 入口可見;owner-attested author profile avatar、author display name 與 public project alias 可見,其餘 email、tenant/subscription/object ID、URL/browser chrome、endpoint/key 與其他識別資訊不可見。 Claim boundary:這張設定畫面不證明 Project 建立者、角色範圍、data-plane 存取、模型部署、推論成功、費用或任何安全控制有效。

Used with permission from Microsoft.

Microsoft Foundry 的 AI Agent 攻防實戰 is an independent publication and is neither affiliated with, nor authorized, sponsored, or approved by, Microsoft Corporation.

region 不是隨手挑離自己最近的就結束。模型與功能支援、quota、資料落地與網路
需求都可能不同;正式建立前先查 Region support。本系列不指定一個對所有人都可用
的 region,也不宣稱任何模型在每個 region 都能部署。

若你已經有可用 Project,直接選擇即可,不必為文章再建立一份;多出的資源仍可能
產生額外費用。

若 Project 是平台管理員先建好的,請依實際 operation 在最小 scope 指派 Foundry
內建角色。Project 內的 build/test 與模型推論路徑可先由現行 Foundry User
權限表核對;若 consumer 只需要和已註冊的 Agent endpoint 互動,則應評估權限較窄的
Foundry Agent Consumer,不要順手給成能建立資產的角色。建立/管理 Project 或
deployment 還要另外看 control-plane operation。Microsoft 目前明確區分 control
plane 與 data plane,ARM 的 Contributor/Owner 不保證自動具備 Foundry data
actions;角色指派也可能需要數分鐘傳播。遇到 403 時記錄 principal、scope、
operation 與測試時間,比一直加大角色更容易找到真正缺的權限。

CLI 對照路徑

需要自動化時,可依官方 quickstart 使用以下命令。名稱請換成自己的,
--custom-domain 必須全域唯一:

az group create \
  --name '<resource-group>' \
  --location '<region>'

az cognitiveservices account create \
  --name '<globally-unique-foundry-resource>' \
  --resource-group '<resource-group>' \
  --kind AIServices \
  --sku S0 \
  --location '<region>' \
  --custom-domain '<globally-unique-foundry-resource>' \
  --allow-project-management

az cognitiveservices account project create \
  --name '<globally-unique-foundry-resource>' \
  --resource-group '<resource-group>' \
  --project-name 'magic-panda-security-lab' \
  --location '<region>'

--allow-project-management 必須在建立 resource 時設定,官方文件指出之後不能更改。
驗證 resource 與 Project 都完成:

az cognitiveservices account show \
  --name '<globally-unique-foundry-resource>' \
  --resource-group '<resource-group>' \
  --query properties.provisioningState --output tsv

az cognitiveservices account project show \
  --name '<globally-unique-foundry-resource>' \
  --resource-group '<resource-group>' \
  --project-name 'magic-panda-security-lab' \
  --query properties.provisioningState --output tsv

兩次預期都輸出:

Succeeded

若不是 Succeeded,先查角色、region 與 quota,再依 error detail 處理;重複送出
相同建立命令不會修正前置條件。

步驟三:部署模型,記住 deployment name

在新 Foundry portal:

  1. 右上方選 Discover
  2. 左側選 Models
  3. 選擇你所在 region 與訂閱可用、而且符合組織政策的模型。
  4. Deploy,完成部署設定。
  5. 記下 deployment name。

Portal 圖說明:作者/owner 已核准使用以下完整產品 viewport。畫面保留產品當下顯示的第三方模型名稱與鄰接 Models Preview 標籤作為介面脈絡;它們不代表本文把 Preview 功能說成 GA,也不代表第三方供應商或 Microsoft 對本文背書。畫面不含 URL、email、tenant/subscription/object ID、endpoint 或 key 值。

畫面判讀目標: 辨認 Build > Deployments 的模型部署清單,並把 deployment name 與 catalog model name 分開。

Microsoft Foundry 的 Build &gt; Deployments 顯示模型部署清單,未顯示 URL、租戶或 endpoint 識別資訊。

畫面中的第三方模型名稱與鄰接 Preview 標籤只保留作介面脈絡;deployment inventory 只證明畫面當下列出的部署,不是 data-plane smoke test。 可觀察狀態:Build 導覽、Deployments 頁面與至少一列模型 deployment inventory 可見;URL、tenant、subscription、帳號與 endpoint 識別資訊不可見。 Claim boundary:清單存在不證明 deployment 可由本文 principal 呼叫、推論成功、quota 足夠、endpoint 正確、最小 RBAC 或安全控制有效。

Used with permission from Microsoft.

Microsoft Foundry 的 AI Agent 攻防實戰 is an independent publication and is neither affiliated with, nor authorized, sponsored, or approved by, Microsoft Corporation.

官方資源 quickstart 在 2026-08-03 使用 gpt-5.1-mini 作為範例,但可用型號、
版本、quota 與部署方式會變動。本文不把該名稱硬寫成系列必要條件。後面的程式只
讀取 FOUNDRY_MODEL,其值是你畫面上的 deployment name,不一定等於 model
catalog 顯示名稱。

如果畫面提供 Instant Access Models,請注意官方 readiness table 目前仍標示
Preview。這條系列基線採已部署模型,不把 Preview 當成 15 分鐘捷徑的一部分。

步驟四:複製 Project endpoint,不要複製 key

回到 Project welcome screen,找到 Project endpoint 並複製。接著建立本機
環境變數:

export FOUNDRY_PROJECT_ENDPOINT='https://<resource>.services.ai.azure.com/api/projects/<project>'
export FOUNDRY_MODEL='<your-deployment-name>'

Endpoint 不是密碼,但會暴露資源與 Project 識別資訊,因此公開截圖仍應遮蔽。
Access token 更不能輸出、寫檔或貼進文章。Repository 的 .env.example 只能放
placeholder:

FOUNDRY_PROJECT_ENDPOINT=https://<resource>.services.ai.azure.com/api/projects/<project>
FOUNDRY_MODEL=<deployment-name>

本系列刻意不定義 FOUNDRY_API_KEY。Microsoft 的 GA readiness 頁面寫的是 API key
支援 Foundry 的「多數功能面(most areas)」,不是「部分地理區域」;同一頁也把
evaluations、dataset tab、Content Understanding、agents 與 workflows 等例外列為需要
Entra ID。治理敏感 workload 仍應使用 Entra ID 與 RBAC 取得較細的權限控制。更實際
的理由是:後面要測 principal、RBAC 與 workload identity,第一天就把大家綁在一把
共享 key 上,只會替自己埋伏筆。模型與功能能否在某個 region 使用,則是另一張
availability/quota 表,不能和 authentication support 混成同一件事。

先攻擊設定,不急著攻擊模型(Threat/Attack)

畫面判讀目標: 看見缺少 Project endpoint、非 Project endpoint 與禁用 key 在認證前 fail closed。

設定診斷 UI 以三個 reason code 拒絕缺少 endpoint、非 Project endpoint 與 key。

先攻擊設定:錯誤 cloud surface 必須在認證前停止。 可觀察狀態:三列分別回 FOUNDRY_PROJECT_ENDPOINT_REQUIRED、FOUNDRY_PROJECT_ENDPOINT_INVALID、FOUNDRY_KEY_AUTH_FORBIDDEN。 Claim boundary:未建立 network observer;不能由此推論實際雲端呼叫為零。

Day 02 的受控攻擊不是去碰雲端,而是把三份彼此獨立的錯誤環境設定餵給 preflight:

# fixture 1:缺少 FOUNDRY_PROJECT_ENDPOINT
FOUNDRY_MODEL=gpt-security-lab

# fixture 2:不是 Project endpoint
FOUNDRY_PROJECT_ENDPOINT=https://example.openai.azure.com/
FOUNDRY_MODEL=gpt-security-lab

# fixture 3:合法 shape 旁出現禁用 key
FOUNDRY_PROJECT_ENDPOINT=https://magic-panda.services.ai.azure.com/api/projects/security-lab
FOUNDRY_MODEL=gpt-security-lab
FOUNDRY_API_KEY=SYNTH_MAGIC_PANDA_NOT_A_REAL_KEY

三份 fixture 分別固定三個問題:

  • endpoint 不是 Project endpoint。
  • Project endpoint 缺少。
  • 出現本系列禁止的 key 變數。

若程式默默接受它,常見後果不是只有 401:呼叫可能繞到不同 API surface、測試
可能跳過 Project scope,或者合成 key 名稱日後被真 key 取代並進入 log。設定錯誤
不會拿武士刀衝進機房,它比較喜歡穿著「quickstart」外套混進 repository。

單次 preflight 只回第一個 bounded failure code,不會把一份混合錯誤設定展開成三個
診斷。scripts/check_foundry_env.py 必須 fail closed:驗證 scheme、host、
/api/projects/ path、deployment name 與禁止的 key 變數,輸出時只保留去識別化
endpoint shape。

cd day2
uv sync --frozen --extra dev --extra foundry
uv run python -m scripts.check_foundry_env

正確設定的預期輸出是去識別化 JSON:

{
  "authentication": "AzureCliCredential",
  "cloud_calls": 0,
  "endpoint_redacted": true,
  "model_redacted": true,
  "status": "configuration_valid"
}

欄位順序以實際 JSON 為準;驗收比對欄位,不比對印刷排版。這個 preflight 不建立
credential、不取得 token,也不呼叫模型,所以可以在本機測試中穩定重放。

最小雲端路徑:只做一個沒有工具的 ephemeral Agent(Fix)

安裝已寫入 uv.lock 的套件後,仍由同一個
python -m scripts.check_foundry_env 入口控制;加上 --cloud-smoke 才會進入
examples/cloud/foundry_quickstart.py 的雲端路徑。核心程式沿用 Microsoft 官方
Responses API quickstart 的 FoundryChatClientAzureCliCredential

import asyncio

from agent_framework import Agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential


def run_cloud_smoke(config) -> dict[str, object]:
    async def invoke_once() -> bool:
        credential = AzureCliCredential()
        try:
            agent = Agent(
                client=FoundryChatClient(
                    project_endpoint=config.project_endpoint,
                    model=config.model,
                    credential=credential,
                ),
                instructions=(
                    "你是大魔術熊貓工程司的連線測試助理。"
                    "本次不提供任何工具,請直接回答使用者問題。"
                ),
            )
            result = await agent.run(
                "我有一張台北工作坊的高鐵票,報帳前要準備哪些資料?"
            )
            text = result if isinstance(result, str) else getattr(result, "text", None)
            return isinstance(text, str) and bool(text.strip())
        finally:
            credential.close()

    nonempty_text_received = asyncio.run(invoke_once())
    if not nonempty_text_received:
        raise FoundryQuickstartError("FOUNDRY_MODEL_TEXT_EMPTY")

    return {
        "status": "cloud_smoke_completed",
        "cloud_calls": 1,
        "logical_agent_calls": 1,
        "http_attempts_observed": None,
        "nonempty_text_received": nonempty_text_received,
        "endpoint_redacted": True,
        "model_redacted": True,
    }

這是 repository 實作的雲端核心;環境變數驗證、例外收斂與 JSON 輸出留在同檔案
的 CLI wrapper。credential 用完即關閉,result、endpoint 與 deployment 原文都不
進入公開 receipt。

這次 smoke 不再叫模型照抄 Foundry keyless smoke succeeded。把成功答案塞在
user_message 裡,只能證明模型會複誦,不能證明我們真的收到可用回應。三層資料
各自放在正確位置:

資料層 內容 驗收用途
system_policy 這是一個沒有工具的連線測試助理,直接回答使用者問題 約束模型角色,不是測試答案
user_message 我有一張台北工作坊的高鐵票,報帳前要準備哪些資料? 一般費用問題;smoke oracle 不依賴特定答案
test_oracle 回應必須是 trim 後非空字串;tools_registered=0 由 Python 檢查,不傳給模型

執行:

uv run python -m scripts.check_foundry_env --cloud-smoke

--cloud-smoke 是刻意設計的雲端寫入閘門;省略它時,程式只輸出前一節的 offline
receipt,不會呼叫 Foundry。雲端成功輸出形狀如下:

{
  "cloud_calls": 1,
  "endpoint_redacted": true,
  "http_attempts_observed": null,
  "logical_agent_calls": 1,
  "model_redacted": true,
  "nonempty_text_received": true,
  "status": "cloud_smoke_completed"
}

模型文字可能不同,因此驗收不比對整句。程式只接受明確的字串或 response 的
text 欄位,而且 strip() 後必須非空;opaque object、ID、metadata 或漂亮的
repr() 都不能充當模型回覆。它不保存 raw response,也不把非空文字誇大成內容
品質或安全性驗證。成功只能證明 Entra authentication、Project endpoint 與
指定 deployment 這條最小 inference path 可走通。程式不列印 token、完整 endpoint
或 raw account information,也沒有註冊任何 function tool。

這裡的 cloud_calls=1logical_agent_calls=1 都只表示程式呼叫了一次
Agent.run();沒有 transport instrumentation,所以
http_attempts_observed=null。不能把這個 1 寫成底層 HTTP attempt 或 retry 次數。

官方把這種 agent 稱為 ephemeral:instructions、tools 與 model definition 存在
本機 process,呼叫時使用 Responses API,並沒有在 Agent Service 建立一個持久化
Agent resource。這個差異會影響生命週期與證據位置,不能看到 Agent(...) 就寫成
「已部署 Agent Service」。

截至 2026-08-03,Microsoft 官方 GitHub 的 umbrella/core Python release 是
python-1.13.0;本 lab 鎖定另一個 distribution
agent-framework-foundry==1.10.3,並由 lock 解出
agent-framework-core==1.12.1。兩個套件各有發布節奏,不能只因數字不同就把
provider pin 判成過期,也不能把 core 的 1.13.0 寫成 provider 已安裝版本。

我們也在乾淨的 62-package 環境試過 provider 1.10.4:沒有呼叫 Azure,但
FoundryChatClient import 會因缺少
agent_framework_openai._feature_usage 而失敗;回到 lock 的 1.10.3/core
1.12.1 後,乾淨環境 import 通過。這是相依套件相容性結果,不是模型或雲端功能
評測。本次重現因此保留已驗證的版本組合;若發文前調整任一 pin,import smoke、
離線 contract 與 cloud smoke 都要重跑。

不需要 Azure credential 就能先驗證 import 與 lock:

uv run --frozen --extra foundry python -c \
  "from importlib.metadata import version; from agent_framework.foundry import FoundryChatClient; print(version('agent-framework-core'), version('agent-framework-foundry'), FoundryChatClient.__name__)"

本文鎖版的預期輸出:

1.12.1 1.10.3 FoundryChatClient

另外,Microsoft 已公告 Azure AI Inference beta SDK 將於 2026-08-26 退役,應改用
GA 的 OpenAI/v1 API 與穩定 SDK。本文程式沒有直接 import azure-ai-inference
agent-framework-foundry==1.10.3 的當前 lock 仍把它列為 transitive
dependency,因此不能宣稱整個 dependency graph 已經脫離 beta SDK。發文與
2026-08-26 前都要重新核對 provider release/lock 及實際 call path。Core
framework、Foundry provider 與 hosting integration 也要分開查狀態,不能由其中
一項 GA 推論所有 hosting 外掛都 GA。

離線 contract 與一次雲端呼叫分開算(Test)

畫面判讀目標: 確認合法 Project shape 與 AzureCliCredential 的離線契約。

設定診斷 UI 顯示合法 Project endpoint shape 與 keyless redaction flags。

離線設定綠燈和一次真實 cloud smoke 必須分開。 可觀察狀態:configuration_valid、AzureCliCredential 與 endpoint/model redacted flags 可見。 Claim boundary:offline contract 沒有取得 token,也不證明 Foundry 連線成功。

先執行離線驗收:

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

當日 acceptance test 具體驗證:

  • 合法 Project endpoint 與 deployment name 產生 cloud_calls=0 的 offline receipt。
  • 缺少 Project endpoint 時,在 authentication 以前 fail closed。
  • resource-level/非 Project endpoint 以固定 reason code 被拒絕。
  • FOUNDRY_API_KEY 含有非空值時,在建立 credential 以前被拒絕;空字串不形成
    key authentication,也不應被寫成已偵測到 secret。
  • 合成的 403 與 credential failure 只映射成 bounded code,不洩漏服務訊息。
  • None、opaque object、非字串 text 與全空白 text 都不能被誤算成成功;只有
    可安全抽取且 trim 後非空的模型文字才通過。
  • 文件所列的 python -m scripts.check_foundry_env 入口能直接輸出 offline JSON,
    而且仍是 cloud_calls=0

離線測試通過仍不能宣稱 Azure 已連線。雲端 smoke 必須另外執行前面的 Python
程式,並保存 cloud_calls=1nonempty_text_received=true 與 redaction flags;endpoint
與身分只存雜湊或遮蔽值。若未加 --cloud-smokecloud_calls=0 才是正確結果。
這裡的 cloud_calls=0 是 offline contract 的宣告欄位,不是 instrumented network
counter;app UI screenshot 仍會顯示 external/cloud call 為 null/not observed

常見錯誤可先這樣判斷:

症狀 優先檢查
CredentialUnavailableError 是否已執行 az login,終端機是否使用同一個使用者環境
401 token audience、登入 tenant、CLI session 是否有效
403 使用者是否有 Project/模型推論所需角色,角色指派是否已傳播
404 是否誤用 resource endpoint、Project 名稱或 API surface
400/Responses 不受支援 此 deployment 是否支援 Responses API;若改用 Chat Completions,要記錄為不同 API 路徑
deployment not found FOUNDRY_MODEL 是否填 deployment name,而非 catalog 名稱
429/quota/capacity error region、model quota、deployment capacity 與重試節奏

為避免把 token、endpoint 或服務回應帶進公開證據,範例程式只把例外映射成固定
code:credential、401、403、404、429 各自有類別,其餘才收斂成
FOUNDRY_CLOUD_SMOKE_FAILED。它刻意不輸出 SDK exception body;除錯時以固定 code
選擇上表的檢查層次,再看 Portal deployment 狀態、RBAC 與 Azure CLI 當前帳號,
不要把完整 exception 直接貼進 issue 或截圖。

Microsoft 在 2026-08-03 的文件中提醒 Foundry 內建角色最近改名:Foundry User、
Foundry Owner、Foundry Account Owner、Foundry Project Manager 先前使用 Azure AI
開頭的名稱;role ID 與核心權限未變。若 portal 與 CLI 顯示不同名字,先依官方
RBAC 文件核對,不要猜哪個比較新潮。

D02-APP-CONFIG-REJECTED scene 要證明三份獨立 preflight 對缺少 endpoint、錯誤 endpoint 與禁止 key fail closed。

成功標準:三個錯誤各有固定 reason code,輸出不包含合成 key 值。Stage JSON 宣告
cloud_calls=0,但 app UI screenshot 要顯示 external/cloud call 為 null/not observed
沒有 observer 或 receipt,就不能從 preflight 圖推論實際網路呼叫次數。

D02-APP-KEYLESS-CONTRACT scene 要證明正確設定經去識別化後通過 contract test。

成功標準:status=configuration_validauthentication=AzureCliCredential 與兩個
redaction flags 都能判讀;app UI screenshot 的 external/cloud call 是
null/not observed。這張本機圖沒有雲端 observer 或 receipt,不能冒充連線成功。

上方 Project endpoint scene 只保留欄位標籤與 URL 形狀,並遮蔽 resource、project、
subscription、tenant 與帳號。它只觀察設定畫面,沒有觀察 inference/external call,
也不是 cloud smoke receipt。

目前已有一張去識別化的 deployment 列表,支持「受控雲端環境當時顯示該
deployment」這項有限觀察;它不是服務端 attestation,也不是 keyless 成功證據,
更沒有觀察 inference/external call。下一段 sanitized receipt 提供另一份、同樣
有明確證據邊界的 operator-produced 紀錄。

PARTIAL-CLOUD:讀取 2026-08-04 sanitized receipt

畫面判讀目標: 讀懂一份已保存的 keyless smoke receipt 能證明與不能證明的範圍。

已保存的 cloud smoke receipt UI 顯示記錄時間、AzureCliCredential、一次 logical Agent call、非空文字與零工具。

Operator-produced receipt 不是 service attestation。 可觀察狀態:checked_at=2026-08-04T05:16:35Z、authentication=AzureCliCredential、logical_agent_calls=1、nonempty_text_received=true、tools_registered=0。 Claim boundary:本次 UI 只讀取已保存檔案,未重播雲端呼叫;它不是服務端 attestation,也不證明 HTTP attempt 數、最小 RBAC 或安全控制。

Repository 保存了一份檔名日期為 2026-08-04 的 operator receipt;其
checked_at=2026-08-04T05:16:35Z,換算台北時間為 2026-08-04 13:16:35。這份紀錄
描述操作者當時以 AzureCliCredential 與 Foundry Project endpoint 執行一次無工具
smoke,並已通過本 repo 的 schema/redaction regression。檔案 SHA-256 為
be01c349070f2bfa942ec0b4dc423b6d615f6d5807ae7423e9b30ce87c150556

Receipt 保存 logical_agent_calls=1nonempty_text_received=true
tools_registered=0、SDK 版本與 redaction flags;模型文字、完整 endpoint、deployment
name、credential、response ID 與 token 都沒有保存。http_attempts_observed=null
所以不能寫成「只有一個 HTTP request」,也沒有可靠 token usage 可報。

這份 receipt 是操作者執行腳本後保存、通過本 repo schema 與 redaction 檢查的
紀錄;它記載「一次 logical Agent call 收到非空模型文字」,但不是 Azure 服務端
簽發的 attestation,也不能由公開檔案獨立驗證當時 principal 或服務端執行。公開 artifact 沒有 response/
correlation ID、Activity Log reference 或簽章,第三方不能只靠它獨立驗真。它也沒有驗最小 RBAC、Managed Identity、Agent/tool path、
Prompt Shields/Content Safety、private network 或任何安全控制的正負向行為,也沒有
建立持久化 Agent Service resource。Evidence manifest 的 current receipt/source/lock hashes
目前可以重算通過,但 commit_id=null,immutable baseline commit 尚未建立,不能宣稱
recorded-baseline 或 release attestation。因此本篇維持 PARTIAL-CLOUD,不是
PASSED-CLOUD;降級原因是驗證範圍,不是圖片數量。

D02-APP-CLOUD-SMOKE-RECEIPT 只讀取並投影 SHA-256 綁定的已保存 sanitized receipt,
不發出新的 cloud call,也不顯示 raw response、token 或完整 endpoint。它可觀察 receipt
所記載的一次 logical Agent call;但 http_attempts_observed=null,圖片不得再推論底層
HTTP request 次數。

GA、Preview、費用與清理

截至 2026-08-03,官方 readiness table 將 Foundry Project、Models core 與
Agents core 列為 GA;Instant Access Models 是 Preview,managed compute 是
Preview deployment type。每個模型、工具、region 與 evaluator 仍要個別查閱,
不能用「Foundry GA」四個字包辦。

模型推論可能依 token 與部署類型計費,建立前要確認定價、quota 與組織預算。
本文沒有宣稱 15 分鐘 smoke 的固定美元成本,因為模型、region、輸入輸出與價格
日期都會改變。完成後若整個 resource group 只服務這個 lab,可依官方 quickstart
刪除 resource group;若其中有共用資源,不能照抄整組刪除命令。

# 先確認這個 resource group 只包含可刪除的 lab 資源,再執行。
az resource list --resource-group '<resource-group>' --output table

本篇不替讀者自動執行刪除。清理是有風險的管理動作,應由資源 owner 核對後完成。

Keyless 仍然有權限邊界(Residual Risk)

不使用 API key,仍然有 token、角色與 session。AzureCliCredential 代表目前登入
CLI 的人;若共用開發機、登入錯 tenant,或角色範圍太大,keyless 也不會自動變成
least privilege。今天的 operator-produced smoke receipt 只支持這個 principal
當時可走通指定 deployment 的最小路徑;它不能證明其他 principal 會被拒絕,也不能
證明下游工具權限正確。

另外,模型回了一句話,只證明最小 inference path 可用。它沒有驗證 tracing、
Prompt Shields、Search、MCP、private networking 或 Agent Service deployment。
接下來 Day 03 會刻意把 Agent 做壞,但先把它關在 localhost 與 synthetic sinks
裡;今天取得的 Project endpoint 會保留給後續 bounded cloud adapter 使用。

NIST SP 800-207 的原則是不因 network location 或 asset ownership 給予 implicit
trust,並以資源保護及持續的身分、政策判斷為核心。本文把它工程化成明確 credential
source、Project scope 與逐項 operation 測試。ISO/IEC 27001:2022 在此只提供
identity、access control 與 credential management 的治理語言;這些是作者的
crosswalk,跑通一次 keyless smoke 仍不等於完成 Zero Trust。

官方參考資料

以下資料均於 2026-08-03 查閱:


上一篇
Day 01|Microsoft Foundry 的 AI Agent 攻防實戰:AI Security 不是 AI Safety
下一篇
Day 03|Microsoft Foundry 的 AI Agent 攻防實戰:故意開漏洞
系列文
Microsoft Foundry 的 AI Agent 攻防實戰:建立高資安與可治理的 Agent 系統5
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言