靜態 API Key 能否證明是哪個 Agent instance、代表誰,以及此刻為何執行?
一個客服 Agent 使用 AGENT_API_KEY 呼叫工單 Tool。Key 被放在 image 的環境變數,後來被錯誤 log 帶出。攻擊者拿到它後,可以從另一台機器重放請求;Tool 仍只看見「有效 key」,無法分辨原本的 instance、User 或 Task。即使每個 Agent 一把 key,也只改善 attribution,沒有 expiry、audience 或 sender binding。
API Key 通常回答「持有秘密者能否進入 API」。Agent authorization 還要回答「哪個 runtime 代表哪個 subject,在什麼 Task、對哪個 resource 執行」。靜態 bearer secret 把這些 context 壓成一個可複製字串,不能把模型提出的 Action 綁在委派上。
所有 Agent 共用一個長效 key;Tool 以 key 對應 role,且不檢查 destination 或 Task。洩漏後,攻擊者可查資料、偽造 User attribution、持續重試,撤銷只能影響所有 Agent。
把 API Key 限定為 bootstrap 或低風險、內網、可快速輪替的 credential。真正呼叫 Tool 時,以受信任 workload identity 取得短效、audience-bound、至少 scope/task-bound 的 token;高價值 Action 再要求 sender-constrained proof。Key 仍可作緊急相容層,但不能是唯一的 Agent identity。
| Property | shared API key | per-Agent key | short-lived bound token |
|---|---|---|---|
| instance attribution | 無 | 部分 | 可精確 |
| expiry / blast radius | 通常無 / 大 | 可做但常被忽略 | 預設短 |
| audience | 通常無 | 可自訂 | 可驗證 |
| replay resistance | 無 | 無 | 可配合 sender constraint |
| delegated subject/task | 外部另傳,易偽造 | 外部另傳 | 可由 issuer 綁定 |

Trust boundary 在 runtime、broker/Gateway 與 Tool 之間;Tool 不應接受未經 PEP 的長效 key。Authorization Decision Point 在 PDP,不能把 key 的存在當成 allow。RFC 6750 定義 bearer token 的核心風險是持有者即可使用;RFC 9700 建議 sender-constrained 與 audience restriction 來降低重放和 redirect。
import time, hmac, hashlib
STATIC = "shared-secret"
now = 1_000
def static_call(key, action):
return hmac.compare_digest(key, STATIC) # 重放沒有時間或 audience
def short_token(actor, aud, exp, nonce):
body = f"{actor}|{aud}|{exp}|{nonce}"
sig = hmac.new(b"issuer", body.encode(), hashlib.sha256).hexdigest()
return body + "|" + sig
def verify(raw, expected_aud, t):
actor, aud, exp, nonce, sig = raw.split("|")
body = "|".join(raw.split("|")[:-1])
good = hmac.compare_digest(sig, hmac.new(b"issuer", body.encode(), hashlib.sha256).hexdigest())
return good and aud == expected_aud and int(exp) > t
assert static_call(STATIC, "delete") and static_call(STATIC, "delete")
tok = short_token("agent/i-2", "tool://tickets", now + 30, "n1")
assert verify(tok, "tool://tickets", now + 1)
assert not verify(tok, "tool://tickets", now + 31) # 舊 token 過期
assert not verify(tok, "tool://billing", now + 1) # audience 不符
print("static replay: accepted; short-lived expired/audience checks: rejected")
這是 HMAC 示意,不是生產 JWT 實作;生產環境要用標準 token profile、金鑰保護與 issuer rotation。PoC 實際驗證了靜態 key 可重放,短效 token 在過期與錯誤 audience 被拒絕。
成功與拒絕都應留下 actor、credential id、audience、expiry、Task、Action digest、policy version 和 deny reason;不要把 API Key 本身寫入 log。
既然長效 key 不理想,下一篇處理生命週期:Agent 每次啟動,是否應取得不同的 credential?