본문 바로가기
C.W.K.
Stream
Lesson 04 of 05 · published

사람 승인과 Audit Trail

~22 min · approval, audit, destructive, logging

Level 0호기심 많은 독자
0 XP0/48 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

Security 를 말뿐이 아니게 만들어주는 운영 습관이 둘 있어. 위험한 가장자리에 사람을 세우는 것덧붙이기만 하는 audit log. 화려하진 않지만, 내보낼 수 있는 agent 와 못 내보내는 agent 를 가르는 선이야.

승인 은 side-effect lesson 에서 본 그 패턴이야. 되돌릴 수 없는 write 를 propose_Xexecute_X 로 쪼개고, 그 사이에서 host 가 user 의 명시적인 '예' 를 받아. MCP 는 이걸 tool annotation (destructiveHint, readOnlyHint) 으로 기계가 읽을 수 있게 만들어놨고, 잘 만든 host 는 파괴적이라고 표시된 tool 에 다른 확인 창을 띄워. Protocol 이 annotation 의 정직함을 강제하진 못하지만 host 는 할 수 있어. 그리고 server 들 사이에서는 결국 평판이 그 역할을 해.

Audit log 는 모든 tool 호출을 덧붙이기만 하는 방식으로 남긴 기록이야. 어느 client 가, 어느 tool 을, 어떤 인자로, 어떤 결과를 냈고, 언제였고, (알 수 있다면) 누구였는지. Server 쪽에 살고, client 는 다시 쓸 수 없어야 해. 반년 뒤에 뭔가 잘못됐을 때 ('정말로 그 주문에 400 달러를 환불했나?') 답을 주는 건 audit log 뿐이야. 디스크에 JSON 한 줄씩, 날짜별 파일로, 이미 쓰던 log 인프라에 얹으면 돼. 비용은 작고 남는 값은 어마어마해.

Audit log 는 남용을 알아채는 자리이기도 해. 특정 tool 호출이 갑자기 치솟거나, 긁어가는 낌새가 나는 인자 패턴이 보이거나, 수상한 IP 에서 온 OAuth token 이 있거나 — 전부 log 에 먼저 나타나. Audit log 를 규정 준수용 서류가 아니라 보안용 망원경으로 다뤄.

Code

승인-gate 된 execute tool·python
@app.tool(annotations={"destructiveHint": True})
async def execute_refund(proposal_id: str, approved_by_user: bool):
    if not approved_by_user:
        return [TextContent(type="text",
                  text="Refund execution requires explicit user approval (approved_by_user=true).")]
    audit.log("execute_refund", proposal_id=proposal_id, user=current_user())
    receipt = await stripe.refund(...)
    audit.log("execute_refund.done", receipt_id=receipt.id)
    return [TextContent(type="text", text=f"Refunded. Receipt: {receipt.id}")]
Append-only audit log helper·python
import json, time, pathlib

LOG = pathlib.Path("/var/log/mcp-server/audit.jsonl")

def audit(event: str, **fields):
    rec = {"ts": time.time(), "event": event, **fields}
    with LOG.open("a") as f:
        f.write(json.dumps(rec, separators=(',', ':')) + "\n")

External links

Exercise

네가 관리하는 server 하나를 골라서 tool 을 전부 적고, 각각 R/W/D 로 표시해. 모든 D 에 propose/execute 분리를 설계하고, 모든 W 와 D 에 audit 한 줄을 추가해. PR 로 올려. Diff 는 작은데 보안 자세는 진짜로 좋아져.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.