Bảo Mật AI Agent: Tại Sao Mô Hình Auth Hiện Tại Sẽ Thất Bại Trong Production
Bạn đã deploy hệ thống multi-agent AI. Một orchestrator ủy quyền cho các sub-agent, sub-agent gọi external API, API trigger database write. Và ở đâu đó trong chuỗi đó, có sự cố xảy ra — và bạn không biết agent nào đã làm, với credentials của ai, và liệu đó có phải là hành động được authorize không.
Đây là vấn đề AI identity. Và hầu hết các team chỉ nhận ra khi đã ở trong production.
Vấn Đề Cốt Lõi
Các mô hình authentication truyền thống được thiết kế cho hai loại principal: người dùng và service. Người dùng login qua OAuth. Service nhận API key tồn tại lâu dài hoặc service account. Hệ thống biết ai đang request và được làm gì.
AI agent phá vỡ mô hình này theo ba cách:
1. Agent hành động thay người dùng, nhưng không phải người dùng. Orchestrator agent gọi API không nên có quyền như người dùng đã trigger nó. Agent có thể đang thực hiện task A — nhưng service account lại có quyền làm tasks A đến Z.
2. Agent ủy quyền cho agent khác. Khi orchestrator spawn sub-agent, sub-agent kế thừa… cái gì? Token của người dùng ban đầu? Service account mới? Không có gì? Hầu hết implementation hiện tại trả lời “không có gì” hoặc “tất cả mọi thứ.”
3. Agent không thể dự đoán. API call của con người theo pattern quen thuộc. LLM agent có thể đi theo path hành động bất ngờ — và nếu access control của bạn quá rộng, bạn chỉ phát hiện ra sau khi thiệt hại đã xảy ra.
Giải Pháp Của Uber: Actor Chain
Team engineering của Uber giải quyết bài toán này với actor chain nhúng trong JWT token. Khái niệm rất tinh tế:
Mỗi khi một principal ủy quyền cho agent khác, principal ủy quyền sẽ thêm mình vào actor chain trong token mới:
# Người dùng yêu cầu một task
JWT: { sub: "user-123", act: [] }
# Orchestrator agent nhận ủy quyền
JWT: { sub: "agent-orchestrator", act: ["user-123"] }
# Sub-agent nhận ủy quyền tiếp theo
JWT: { sub: "agent-summarizer", act: ["user-123", "agent-orchestrator"] }
# Tool/API nhận cuộc gọi cuối
JWT: { sub: "tool-search-api", act: ["user-123", "agent-orchestrator", "agent-summarizer"] }
Mỗi service nhận token này có thể trả lời ba câu hỏi:
- Ai ban đầu đã authorize? (user-123)
- Chuỗi agent nào dẫn đến đây? (orchestrator → summarizer)
- Agent cụ thể này được làm gì? (chỉ những gì được scope cho task này)
Token tồn tại ngắn (tính bằng phút, không phải ngày) và scoped theo task (chỉ permissions cần thiết cho task cụ thể này).
Auth0 Bổ Sung: Capability-Scoped Permissions
Cách tiếp cận của Auth0 mở rộng với capability tokens — thay vì cấp role cho agent, bạn cấp capability cụ thể cho task context cụ thể:
{
"sub": "agent-analyst",
"capabilities": ["read:database-reporting", "write:slack-channel-analytics"],
"scope": "task-id:abc123",
"expires_in": 300,
"act": ["user-456", "agent-orchestrator"]
}
Điều này làm được ba thứ:
- Agent chỉ có thể làm những gì task cần — không phải mọi thứ “role” của nó cho phép
- Token hết hạn sau 5 phút — blast radius khi bị compromise rất nhỏ
- Toàn bộ chuỗi có thể audit — mọi hành động trace về người dùng ban đầu
Ý Nghĩa Kiến Trúc
Nếu bạn đang xây dựng multi-agent system ngay hôm nay, đây là các quyết định cụ thể bạn cần đưa ra:
1. Áp dụng actor chain semantics ngay bây giờ.
RFC 9068 (JWT Profile for Access Tokens) đã hỗ trợ claim act cho delegation chain. Không cần chờ standard mới — nó đã ở đây. Implement ngay kể cả khi agent của bạn vẫn còn đơn giản.
2. Issue token theo task, không phải theo agent.
Identity của agent không giống với task credential. agent-analyst của bạn nhận token fresh, scoped cho mỗi task thực thi. Khi task xong, token hết hạn. Long-term identity credential của agent là riêng biệt và không bao giờ dùng trong API call.
3. Xây dựng Agent Registry trung tâm. Biết agent nào tồn tại, được làm gì, và người dùng nào có thể invoke chúng. Registry này là nguồn sự thật cho authorization system — không phải config file rải rác khắp nơi.
4. Emit structured audit event tại mỗi hop. Mỗi khi agent nhận delegated token và thực hiện hành động, emit structured event: agent ID, actor chain, hành động thực hiện, resource truy cập, kết quả. Không có điều này, debug incident trong multi-agent system gần như không thể.
Implementation Tối Thiểu
Nếu bạn chưa thể build full actor chain model, bắt đầu từ đây:
import jwt
import time
def issue_agent_token(
agent_id: str,
user_id: str,
parent_chain: list[str],
capabilities: list[str],
task_id: str,
ttl_seconds: int = 300
):
now = int(time.time())
return jwt.encode({
"sub": agent_id,
"act": parent_chain + [user_id] if not parent_chain else parent_chain,
"cap": capabilities,
"task": task_id,
"iat": now,
"exp": now + ttl_seconds,
}, SECRET_KEY, algorithm="HS256")
Ngay cả phiên bản tối thiểu này cũng cho bạn: short-lived token, chain có thể audit, và task-scoped capability. Không phải full Uber model — nhưng vô cùng tốt hơn shared service account.
Sự Thật Khó Nói
Hầu hết các team đang xây dựng multi-agent AI hiện tại đang dùng shared service account với quyền rộng và không có delegation chain. Điều này hoạt động trong development. Nó sẽ gây ra incident trong production — và khi xảy ra, bạn sẽ không biết agent nào đã làm gì, vì không có audit trail.
Tin tốt: các pattern đã tồn tại. Actor chain, capability token, short-lived credential — không có gì trong số này là công nghệ mới. Chúng ta đã giải quyết những vấn đề này trong distributed system. Lớp AI agent chỉ yêu cầu chúng ta áp dụng chúng cao hơn một tầng.
Thời điểm để thiết kế agent identity model là trước security incident đầu tiên, không phải sau.
Bài viết này là một phần của series AI Engineering trên luonghongthuan.com — các pattern thực tiễn cho engineers xây dựng AI systems production.