Khi agent hành động sai — hoàn nhầm tiền, gửi nhầm email, xóa nhầm dữ liệu — câu hỏi đầu tiên là: Chuyện gì đã xảy ra, do đâu, ai chịu trách nhiệm? Nếu không có audit log đầy đủ, bạn mù hoàn toàn. Audit log không chỉ để điều tra sự cố mà còn để phát hiện tấn công đang diễn ra và chứng minh tuân thủ.
Audit log của agent khác log thường thế nào?
Log ứng dụng thường chỉ ghi "gọi API X, trả 200". Với agent, bạn cần ghi thêm ngữ cảnh quyết định:
- Input đã kích hoạt hành động (prompt/user message — đã redact secret).
- Danh tính: agent nào, thay mặt người dùng nào.
- Tool được gọi + tham số + kết quả.
- Quyết định của policy: cho phép hay từ chối, vì sao.
Một bản ghi audit tốt trông thế nào
{
"ts": "2026-07-10T09:14:02Z",
"event_id": "evt_8f21",
"agent_identity": "agent-cskh-prod",
"on_behalf_of": "user_10293",
"session_id": "sess_77a",
"tool": "issue_refund",
"params": { "order_id": 55012, "amount": 450000 },
"decision": "allowed",
"policy_rule": "refund<500k_business_hours",
"result": "success",
"trace_id": "trc_bc41"
}
Có trace_id để nối cả chuỗi agent→tool→API. Có decision và policy_rule để biết vì sao được phép.
Các bước xây dựng audit log
- Chọn điểm chèn log tập trung: bọc lớp gọi tool bằng một wrapper duy nhất, mọi tool đều đi qua đó.
- Định nghĩa schema cố định (như JSON trên) để log máy đọc được, tìm kiếm được.
- Redact secret & PII trước khi ghi.
- Ghi ra kho append-only (WORM/immutable): S3 Object Lock, log tập trung có bảo vệ chống sửa.
- Gắn trace_id xuyên suốt để nối các bước.
- Bật cảnh báo trên mẫu bất thường (nhiều refund liên tiếp, export dữ liệu lớn).
def audited_call(tool, params, ctx):
entry = {
"ts": now_iso(), "agent_identity": ctx.agent,
"on_behalf_of": ctx.user, "tool": tool.name,
"params": redact(params), "trace_id": ctx.trace_id,
}
decision = policy.check(tool, params, ctx)
entry["decision"] = decision.verdict
try:
result = tool.run(params) if decision.allowed else None
entry["result"] = "success" if decision.allowed else "blocked"
return result
except Exception as e:
entry["result"] = f"error:{type(e).__name__}"
raise
finally:
audit_sink.write(entry) # luôn ghi, kể cả khi lỗi
finally đảm bảo log được ghi ngay cả khi tool ném lỗi — bằng chứng không bị mất.
Vì sao log phải append-only (bất biến)
Giả sử agent bị chiếm quyền. Nếu log nằm ở nơi chính agent đó có quyền ghi/xóa, việc đầu tiên kẻ tấn công làm là xóa dấu vết. Vì thế audit log phải ghi vào kho chỉ-thêm (append-only), tách khỏi quyền của agent:
Agent (ghi log) ──► Audit Sink (S3 Object Lock / WORM)
• chỉ cho phép PUT, không DELETE/UPDATE
• agent KHÔNG có quyền xóa
• giữ tối thiểu N ngày theo tuân thủ
Nguyên tắc: người/agent tạo ra log không được phép sửa log của chính mình. Điều này biến audit log thành bằng chứng không thể chối bỏ (non-repudiation) — đúng thứ bạn cần khi điều tra sự cố hoặc chứng minh tuân thủ trước kiểm toán.
Khung tư duy: 5 chữ W của audit
Mỗi bản ghi phải trả lời: Who (agent nào), on behalf of Whom (thay ai), What (làm gì), When (lúc nào), Why allowed/denied (policy nào quyết định).
Checklist audit log
- [ ] Mọi lời gọi tool đi qua một wrapper ghi log chung.
- [ ] Ghi đủ danh tính agent + người dùng + tool + tham số + quyết định policy.
- [ ] Secret/PII được redact trước khi ghi.
- [ ] Log ghi vào kho append-only, không sửa/xóa được.
- [ ] Có
trace_idnối toàn chuỗi. - [ ] Có cảnh báo tự động trên hành vi bất thường.
- [ ] Log được giữ đủ lâu theo yêu cầu tuân thủ.
Sai lầm thường gặp
- Chỉ log khi thành công, bỏ qua lần bị chặn hoặc lỗi — mà chính lần bị chặn mới báo hiệu tấn công.
- Log ghi vào chỗ agent có quyền xóa/sửa — kẻ tấn công (hoặc agent bị chiếm) xóa dấu vết.
- Ghi cả secret/PII vào log rồi log lại là bề mặt rò rỉ mới.
- Log không có danh tính người dùng cuối — không phân biệt được ai thực sự yêu cầu hành động.
- Có log nhưng không ai xem: không cảnh báo, không dashboard — log chỉ hữu ích khi được giám sát.