플랫폼 팀이 십여 명의 엔지니어에게 Claude Code를 배포합니다. 유용하게 쓰기 위해 몇 개의 MCP 서버를 연결합니다. 하나는 모노레포를 읽고, 하나는 리포팅 레플리카를 조회하며, 하나는 티켓을 등록합니다. 일주일도 안 되어 한 에이전트가 소스를 읽고, 데이터베이스를 건드리고, 내부 도구를 호출하지만, 결국 감사관이 던질 질문에 아무도 답하지 못합니다. 어떤 에이전트가 어떤 리소스에 대해 무엇을 했는지, 그리고 그것이 사후에 변경되지 않았음을 증명할 수 있는가?
이것은 가상의 공백이 아닙니다. 독립적인 업계 조사(CSA/Token, n=418)에 따르면 약 82%의 조직이 자신들도 모르는 AI 에이전트를 운영하고 있으며, 실시간 인벤토리를 유지하는 곳은 약 21%에 불과합니다. Claude Code와 MCP는 빠르게 자리 잡으면서 감사 체계를 앞질러 버리는 바로 그런 종류의 역량입니다. 다행인 점은, 어떤 페이로드나 비밀 정보도 경계망을 벗어나지 않고 전적으로 자체 경계망 안에서 방어 가능한 추적 기록을 구축할 수 있다는 것입니다.
뻔한 구성이 감사를 통과하지 못하는 이유
흔한 초기 배포는 하나의 자격 증명을 공유합니다. 모든 Claude Code 인스턴스는 MCP 계층과 다운스트림 데이터베이스에 대해 동일한 서비스 계정(mcp-runner, ci-bot 같은 일반적인 이름)으로 인증합니다. 동작은 하지만, 조용히 귀속성을 파괴합니다.
열 개의 에이전트가 하나의 주체로 행동하면, 데이터베이스 감사 로그에는 mcp-runner가 일으킨 열 건의 쓰기만 보일 뿐 그 이상은 없습니다. 어느 엔지니어의 세션이 그 UPDATE를 발생시켰는지, 그것이 대화형 Claude Code 프롬프트에서 왔는지 아니면 무인 작업에서 왔는지, 경로상에 어떤 MCP 도구가 있었는지 알 수 없습니다. 독립적인 조사(Optro)는 에이전트의 작업을 사람에게까지 추적할 수 있는 조직의 비율을 약 28%로 추정합니다. 공유 서비스 계정은 귀속성이 무너지는 구조적 원인 중 하나입니다. 감사 로그는 무슨 일이 일어났는지는 보여줄 수 있지만, 어떤 에이전트가 했는지는 결코 보여주지 못합니다.
두 번째 실패는 무결성입니다. 작업별로 로그를 남기는 팀조차도 대개 변경 가능한 저장소에 기록합니다. 공격자(또는 결함이 있는 에이전트)가 접근할 수 있는 동일한 시스템에 로그가 존재한다면, “로그가 있다”는 것은 “증거가 있다”는 것과 같지 않습니다. 감사관은 이 둘을 명확하게 구분합니다.
에이전트별 신원이 토대입니다
다운스트림의 모든 것은 귀속성에 달려 있으므로, 신원부터 바로잡으십시오. 하나의 공유 토큰 대신, 에이전트별로(이상적으로는 세션별로) 고유하고 수명이 짧은 신원을 발급하십시오. 그 신원은 요청과 함께 MCP 서버로, 그리고 에이전트가 도달하는 모든 리소스로 전달되므로, 데이터베이스에 기록되는 주체는 일반적인 러너가 아니라 그 에이전트가 됩니다.
이것이 최소 권한을 의미 있게 만드는 요소입니다. 리포팅 에이전트는 리포팅 레플리카에 대해 읽기 전용으로 고정될 수 있고, 릴리스 에이전트는 자신이 소유한 아티팩트에 대해서만 쓰기 권한을 얻습니다. 이제 그 범위를 벗어난 단 한 건의 관측된 쓰기는 공유 계정의 잡음이 아니라 정밀하고 귀속 가능한 신호가 됩니다. 정책으로 표현하면 그 의도는 단도직입적입니다.
agent "reporting-assistant" {
# Claude Code session via the reporting MCP server
resource "prod-postgres/reporting_replica" {
access = "read" # SELECT only
deny = ["write", "ddl"]
}
resource "s3://billing-exports" {
access = "read"
}
on_violation {
action = "block_and_alert" # refuse at access time, not just log
}
}
핵심은 구문이 아닙니다. 정책이 에이전트를 명명하고, 리소스를 명명하며, 읽기와 읽기/쓰기를 분리한다는 점입니다. 그 분리가 전부입니다.
MCP 주석은 신뢰할 수 없는 신호로 취급하십시오
MCP 도구는 readOnlyHint나 destructiveHint 같은 주석으로 자신을 설명할 수 있습니다. 이런 주석은 분류 작업에 분명히 유용합니다. 스스로를 파괴적이라고 선언하는 도구는 더 엄격한 정책을 받을 만합니다. 하지만 MCP 명세는 이것이 힌트이며, 클라이언트는 보안 결정을 이에 의존해서는 안 된다고 명시합니다. 이 주석은 서버에서 비롯되며, 서버는 바로 여러분이 감사하고 있는 대상입니다. 도구는 readOnlyHint: true를 선언하고도, 버그든 잘못된 구성이든 의도적인 회피든 간에 여전히 쓰기를 실행할 수 있습니다.
따라서 올바른 자세는 신뢰가 아니라 교차 검증입니다. 주석을 하나의 주장으로 받아들인 다음, 도구가 통제하지 못하는 계층에서 나온 그라운드 트루스와 대조하십시오.
- 데이터베이스 감사 로그(예: PostgreSQL pgAudit)는
SELECT나UPDATE가 실제로 실행되었는지 알려줍니다. - MCP 서버와 다운스트림 서비스에서 나온 OpenTelemetry 스팬은 호출 그래프와 수행된 작업을 보여줍니다.
- eBPF 커널 신호는 회피를 막는 최후의 보루입니다. 파일이나 소켓에 대한 쓰기 시스템 콜은 도구가 사용자 공간에서 무엇을 주장했든 상관없이 커널 수준에서 관측됩니다.
주석은 읽기 전용이라고 말하는데 커널은 쓰기를 목격했다면, 그 모순이 바로 핵심 발견 사항입니다. prod-postgres에 쓰기를 한 readOnlyHint 도구는 누군가를 깨워서라도 대응할 만한 최소 권한 이탈입니다. 정책이 허용한 것과 수집기가 관측한 것 사이의 차이, 바로 그곳에 실제 위험이 존재합니다.
감사관이 인정할 원장
추적 기록은 변조 방지가 되어야만 증거가 됩니다. 각 이벤트를 추가 전용(append-only) 해시 체인 원장에 기록하십시오. 모든 레코드는 직전 레코드의 해시를 포함하므로, 다운스트림에서 어떤 편집이나 삭제가 일어나든 체인이 끊어져 탐지됩니다. 각 줄은 작업을 특정 에이전트에게 귀속시키고, 리소스를 명명하며, 읽기와 읽기/쓰기를 기록하고, 신뢰도 수준을 담습니다. 신원과 결과가 모두 교차 검증된 경우 attributed, 무언가를 추론해야 했던 경우 approximate입니다. 신뢰도는 정직하게 표시됩니다. 근사적인 매칭이 증명된 것처럼 포장되는 일은 결코 없습니다.
ts=2026-06-08T09:14:02Z agent=reporting-assistant@s3f1 tool=sql-read resource=prod-postgres/reporting_replica op=R outcome=allow conf=attributed prev=8a1c…
ts=2026-06-08T09:14:05Z agent=reporting-assistant@s3f1 tool=export-writer resource=s3://billing-exports op=R outcome=allow conf=attributed prev=2f90…
ts=2026-06-08T09:17:48Z agent=data-export-job@b22e tool=sql-write resource=prod-postgres/customers op=RW outcome=DENY conf=attributed prev=c7d3… policy=read_only_violation
세 번째 줄이 바로 감사관이 주목하는 부분입니다. 에이전트에게 쓰기 권한이 없던 테이블에 대한 쓰기 시도가 접근 시점에 거부되었고, 명명된 에이전트에게 귀속되었으며, 체인에 고정되어 있습니다. 정책이 사후에 단지 로그로 남는 것이 아니라 접근이 일어나는 순간에 시행되기 때문에, 이 거부는 사후 분석이 아니라 하나의 통제 수단입니다.
두 가지 속성이 추적 기록의 견고함을 더합니다. 특권 조회 자체도 감사됩니다. 액세스 맵을 들여다보는 행위가 기록되므로 “누가 무엇을 보았는가”에 답할 수 있습니다. 그리고 증거 내보내기도 변조 방지가 됩니다. 감사관에게 그냥 믿어야 하는 CSV가 아니라, 독립적으로 검증할 수 있는 서명된 체인 일부를 건넵니다.
| 속성 | 공유 서비스 계정 | 에이전트별 신원 + 해시 체인 원장 |
|---|---|---|
| 귀속성 | 모든 에이전트에 대한 하나의 주체 | 특정 에이전트/세션에 묶인 작업 |
| 읽기 vs 쓰기 | 뭉뚱그려짐 | 구분되고 정책 검증됨 |
| 무결성 | 변경 가능한 로그 | 추가 전용, 편집 시 체인 끊어짐 |
| 감사 대비 내보내기 | 그냥 믿어야 하는 CSV | 서명되고 독립적으로 검증 가능한 일부 |
여기서 자체 호스팅이 중요한 이유
이 모든 것은 어떤 것도 여러분의 네트워크를 벗어나지 않고 동작합니다. 수집기는 에이전트의 데이터 경로에 끼어드는 대신 관측합니다(로그, OpenTelemetry, 그리고 커널 수준의 최후 보루로서 eBPF). 따라서 수집기가 실패하더라도 에이전트나 그 뒤의 프로덕션 요청을 결코 망가뜨리지 않습니다. 원장은 페이로드가 아니라 액세스 관계를 저장합니다. reporting-assistant가 reporting_replica를 읽었다는 사실을 기록하지, 그것이 반환한 행은 기록하지 않습니다. 비밀 정보나 PII를 담고 있을 수 있는 입력은 무엇이든 기록되기 전에 마스킹되고 비밀 정보 스캔을 거칩니다. 에어갭 환경, GDPR 적용 대상, 또는 데이터 거주지 제약이 있는 인프라에서는, 이것이 방어할 수 있는 감사 체계와 그렇지 못한 체계를 가르는 차이입니다. 여러분의 Claude Code와 MCP 사용에 관한 그 무엇도 외부로 전송되지 않습니다. 애초에 시스템이 데이터 자체를 보지 않기 때문입니다.
Claude Code와 MCP는 배포할 가치가 있습니다. 다만 다른 모든 특권 자동화에 대해 구축하듯이 감사 추적 기록이 필요할 뿐입니다. 신원이 먼저이고, 결과는 교차 검증되며, 증거는 고정됩니다. 액세스 맵과 변조 방지 원장이 어떻게 맞물리는지 보고 싶다면, 보안 모델과 제품 개요에서 각각을 더 깊이 다룹니다.