MCP 거버넌스: 프로덕션 환경에서의 실제 의미 (그리고 우리가 구축해야 했던 네 가지 장벽)
요약
MCP(Model Context Protocol) 프로토콜 자체에는 거버넌스 기능이 없으므로, 프로덕션 환경에서는 별도의 제어 계층을 구축해야 합니다. 본 글은 액세스 제어, RBAC, 제한 사항, 감사 추적 등 안전한 에이전트 도구 사용을 위한 네 가지 핵심 거버넌스 영역을 설명합니다.
핵심 포인트
- MCP는 도구 호출 프로토콜일 뿐 정책 엔진이 아님
- 도구 수준의 RBAC를 통한 세밀한 권한 제어 필요
- 중앙 게이트웨이를 통한 액세스 제어 및 도구 목록 필터링 권장
- 속도 제한, 토큰 예산, 감사 추적 등 거버넌스 장벽 구축 필수
요약 (TL;DR): MCP 거버넌스는 어떤 에이전트가 어떤 아이덴티티(Identity)로, 어떤 제한 사항 하에, 어떤 감사 추적(Audit trail)을 남기며 어떤 도구에 접근할 수 있는지를 결정하는 제어 세트입니다. 순수 MCP(Raw MCP)에는 이러한 기능이 전혀 없습니다. 이는 구조화된 도구 호출(Tool calls)을 위한 프로토콜이지, 정책 엔진(Policy engine)이 아니기 때문입니다. 거버넌스 계층은 팀이 의도적으로 구축해야 하는 것이며, 대부분은 무언가 문제가 발생하기 전까지는 시작하지 않습니다. 이 포스트는 제가 우리의 첫 번째 장애가 발생하기 전에 읽었더라면 좋았을 내용입니다.
우리가 처음 MCP 서버를 프로덕션(Production) 환경에 배포했을 때, 우리의 거버넌스 방식은 이랬습니다:
- 누가 (Who) 어떤 MCP 서버에 연결할 수 있는가 (ID + 액세스 제어 (Access Control))
- 무엇을 (What) 연결된 후 수행할 수 있는가 (도구 수준의 RBAC)
- 어떤 제한 하에 (Under which limits) 수행하는가 (속도 제한 (Rate limits), 토큰 예산 (Token budgets), 워크플로우 단계 제한 (Workflow step caps))
- 어떤 기록과 함께 (With what record) 수행하는가 (호출별 감사 추적 (Audit trail))
- **콘텐츠에 대한 어떤 정책 강제 (With what policy enforcement)**를 적용하는가 (입력 및 출력 가드레일 (Guardrails))
MCP 프로토콜 자체는 이 중 어느 것도 제공하지 않습니다. MCP는 에이전트가 도구를 호출하는 방식과 도구가 결과를 반환하는 방식을 정의할 뿐입니다. 거버넌스는 그 위에 구축하느냐 마느냐의 문제이며, 구축하지 않았을 때 왜 구축했어야 했는지를 깨닫게 됩니다.
네 가지 장벽 (The four walls)
세 번의 사고를 겪은 후, 우리는 거버넌스 문제를 네 가지 별개의 제어 영역으로 매핑했습니다. 각 영역은 서로 다른 실패 모드 (Failure modes)와 서로 다른 완화 조치 (Mitigations)를 가집니다.
장벽 1: 액세스 제어 (Access control)
실패 모드: 서버 URL을 가진 에이전트라면 누구나 어떤 도구든 호출할 수 있습니다. 액세스 범위 지정(Access scoping)도, 신원 요구 사항(Identity requirement)도, 팀별 제한 사항도 없습니다.
필요했던 것: 도구 수준의 RBAC (역할 기반 액세스 제어 (Role-Based Access Control)). 단순히 "팀 A가 Jira 서버에 연결할 수 있다"가 아니라, "팀 A는 search_issues와 create_issue는 호출할 수 있지만, delete_issue, delete_project 또는 bulk_update는 호출할 수 없다"와 같은 제어가 필요했습니다.
두 번째 요구 사항은 초기 MCP 설정 대부분이 놓치는 부분입니다. 서버가 읽기 및 쓰기 도구를 모두 노출하고 있고 서로 다른 에이전트에게 서로 다른 권한을 부여하고자 한다면, 연결 수준에서 서버 액세스를 제어하는 것만으로는 도움이 되지 않습니다.
구현 방식: 모든 MCP 액세스는 중앙 게이트웨이 (Central gateway)를 통해 이루어집니다. RBAC 정책은 서버별, 도구별, 역할별로 정의됩니다. 에이전트는 필터링된 도구 목록을 전달받습니다. 즉, tools/list는 에이전트가 호출할 권한이 있는 도구만을 반환합니다. 에이전트는 사용할 수 없는 도구를 아예 볼 수 없으며, 이를 통해 설정 오류 (Misconfiguration)의 공격 표면 (Surface area)을 완전히 제거합니다.
우리는 이를 위해 TrueFoundry의 MCP Gateway를 사용합니다. RBAC (역할 기반 액세스 제어) 설정에는 서버당 약 하루 정도의 시간이 소요되었습니다. 또한 우리는 Virtual MCP Servers를 사용합니다. 이는 특정 팀 페르소나(Persona)가 필요로 하는 도구의 하위 집합만을 노출하는 큐레이션된 논리적 엔드포인트(Logical endpoints)입니다. 이를 통해 연구 에이전트(Research agent)와 고객 지원 에이전트(Customer support agent)가 동일한 기본 서버에 대한 권한을 가지고 있더라도 완전히 다른 도구 표면(Tool surfaces)을 보게 됩니다.
장벽 2: ID 및 자격 증명 거버넌스 (Identity and credential governance)
실패 모드 (The failure mode): 자격 증명(Credentials)이 서버별, 개발자별로 개별적으로 관리됩니다. 누군가 합류하면 자격 증명을 수동으로 설정해야 합니다. 누군가 떠나면, 누군가가 모든 곳에서 해당 자격 증명을 취소하기를 바라야만 합니다.
필요했던 것: 오프보딩 (Offboarding) 시 전파되는 중앙 집중식 자격 증명 관리.
우리의 장애 사례에서 나타난 계약직 자격 증명 문제는 거의 보편적입니다. MCP 서버는 일반적으로 온보딩/오프보딩 워크플로우의 다른 모든 요소와 분리된 별개의 시스템입니다. 의도적으로 연결하지 않는 한, 이들은 관리 범위에 포함되지 않습니다.
구현 방법: 모든 개발자와 서비스 에이전트는 단일 토큰(사람의 경우 PAT, 서비스 에이전트의 경우 VAT)을 사용하여 중앙 게이트웨이에 인증합니다. 게이트웨이는 GitHub OAuth, Jira API 키, Confluence 토큰, 내부 API 서비스 계정 등 모든 다운스트림 자격 증명을 관리하며, 만료 전에 자동으로 갱신합니다.
오프보딩은 단 하나의 동작이 되었습니다: 게이트웨이 토큰을 취소하는 것. 게이트웨이가 관리하는 자격 증명은 개인이 아닌 게이트웨이의 통제 하에 있기 때문에, 모든 다운스트림 MCP 서버의 액세스가 자동으로 차단됩니다.
특정 사용자를 대신하여 동작해야 하는 도구(봇이 아닌 개인으로서 Slack에 게시하는 경우 등)의 경우, Okta 연동을 통한 OAuth 2.0을 사용합니다. 게이트웨이가 토큰 교환 및 갱신을 처리하므로, 에이전트가 OAuth 흐름을 직접 관리할 필요가 없습니다.
장벽 3: 감사 추적 (Audit trail)
실패 모드 (The failure mode): 도구 호출 (Tool calls)은 두 곳에서 로그를 생성합니다. MCP 서버 로그와 다운스트림 API (downstream API) 로그입니다. 하지만 이 중 어느 것도 _어떤 에이전트나 사용자_가 해당 호출을 트리거했는지 알려주지 않습니다.
필요했던 것: 다음 사항을 기록하는 도구 호출 (tool invocation)당 구조화된 감사 추적 (audit trail)이 필요했습니다: 어떤 에이전트, 어떤 인증된 사용자, 어떤 도구, 어떤 입력 파라미터 (input parameters), 어떤 응답이었는지, 그리고 언제였는지.
이것이 컴플라이언스 (compliance) 팀이 실제로 요구하는 사항입니다. "지난달에 도구 X가 400번 호출되었습니다"라는 정보는 유용하지 않습니다. "서비스 계정 Z 하의 에이전트 Y가 14:23:07에 다음과 같은 파라미터로 테이블 T에서 delete_record를 호출했습니다"라고 해야 사고 조사 (incident investigation)가 복구 가능해집니다.
구현 방법: 게이트웨이 (gateway)는 다운스트림 서버로 라우팅하기 전에 모든 도구 호출을 구조화된 메타데이터 (metadata)와 함께 로그로 남깁니다. 로그는 OpenTelemetry를 통해 우리의 Datadog 설정으로 내보내집니다. 쿼리 (query)가 가능합니다. 보안 팀이 "지난 30일 동안 어떤 에이전트가 프로덕션 데이터 API에 접근했는가"라고 물었을 때, 이틀이 걸리던 조사가 10분짜리 쿼리로 단축되었습니다.
장벽 4: 콘텐츠 가드레일 (Content guardrails)
실패 모드 (The failure mode): 에이전트가 MCP 도구를 통해 외부 시스템에서 콘텐츠를 가져옵니다. 그 콘텐츠에 주입된 지시 사항 (injected instructions)이 포함되어 있습니다. 에이전트는 이를 처리하고 주입된 지시 사항을 실행합니다. 이것은 도구 응답 (tool response)을 통한 프롬프트 인젝션 (prompt injection)이며, 우리가 웹 페치 (web-fetch) 에이전트에서 겪었던 문제입니다.
필요했던 것: 도구가 반환한 내용이 에이전트의 컨텍스트 (context)에 들어가기 전, 도구 호출 후의 검사 (post-tool-call inspection)가 필요했습니다.
이는 LLM 호출에 대한 입력 가드레일 (input guardrails, 사용자가 모델에 보내는 내용을 검사함)과는 다릅니다. 도구 응답 가드레일 (tool response guardrails)은 에이전트가 확인하기 전에 MCP 서버가 다시 보내는 내용을 검사합니다. 인젝션은 도구의 출력값에서 발생하므로, 방어는 반드시 해당 레이어 (layer)에서 이루어져야 합니다.
구현 방법: 호출하는 에이전트(agent)에게 반환되기 전, MCP 도구(tool)의 응답을 검사하는 게이트웨이 수준의 실행 후 가드레일(post-execution guardrails)을 구축했습니다. 도구 응답에 대해 개인정보(PII) 탐지 및 프롬프트 인젝션(prompt injection) 패턴 매칭을 실행합니다. 고위험 도구(웹 페치(web fetch), 문서 검색, 외부 API 응답)의 경우, 변형(mutate) 모드로 콘텐츠 정화(content sanitization)를 적용합니다. 즉, 단순히 플래그를 표시하는 것에 그치지 않고 탐지된 인젝션을 제거하도록 응답을 수정합니다.
이것은 대부분의 팀이 인젝션 사고가 발생할 뻔한 아찔한 상황을 겪기 전까지는 건너뛰는 거버넌스 레이어(governance layer)입니다. 저희는 이것을 처음부터 구축했더라면 좋았을 것이라고 생각합니다.
네 가지 장벽 요약 테이블
| 이것이 없을 때 발생하는 문제 | 구현 방법 | |
|---|---|---|
| 액세스 제어 (Access control) | 모든 에이전트가 파괴적인 도구를 포함한 모든 도구를 호출할 수 있음 | 도구 수준의 RBAC, 가상 MCP 서버, 필터링된 tools/list |
| ... |
거버넌스에 반드시 필요하지 않은 것들
MCP 거버넌스에 관한 초기 논의에서 제가 반박하고 싶은 몇 가지 사항이 있습니다:
네 가지 장벽을 한꺼번에 해결할 필요는 없습니다. 장벽 1(액세스 제어)은 가장 흔한 유형의 사고인 과도한 권한을 가진 에이전트(over-permissioned agents)를 방지하기 때문에 투자 대비 수익률(ROI)이 가장 높습니다. 거기서부터 시작하세요. 장벽 4(콘텐츠 가드레일)는 기술적으로 가장 복잡하며, 에이전트가 외부의 신뢰할 수 없는 콘텐츠를 검색할 때 가장 중요합니다. 만약 에이전트가 신뢰할 수 있는 응답을 주는 내부 API만 호출한다면, 장벽 4는 나중에 처리해도 됩니다.
모든 서버에 대해 커스텀 도구를 만들 필요는 없습니다. 확장 가능한 패턴은 각 서버에 개별적으로 거버넌스를 내장하는 것이 아니라, 모든 서버의 거버넌스를 처리하는 중앙 게이트웨이를 두는 것입니다. 정책이 변경될 때 업데이트할 설정이 하나로 통합되고, 문제가 발생했을 때 확인할 곳도 한 곳이 됩니다.
거버넌스가 에이전트의 속도를 늦출 필요는 없습니다. 인증(Auth) 확인, RBAC 평가, 감사 로그(audit log) 기록은 모두 비동기 로그 플러싱(async log flushing)을 통해 핫 패스(hot path) 상에서 인메모리(in-memory)로 처리될 수 있습니다. TrueFound Foundry의 게이트웨이는 부하 상황에서도 3ms 미만의 지연 시간(latency)을 추가합니다. 만약 거버넌스로 인해 도구 호출당 몇 초씩 지연이 발생한다면, 그것은 거버넌스 원칙의 문제가 아니라 아키텍처의 문제입니다.
어떤 거버넌스 제어(governance controls)를 가장 먼저 구축하셨나요? 그리고 어떤 사고(incident)가 이를 우선순위에 두게 만들었나요? "에이전트가 호출해서는 안 될 도구를 호출했다"는 패턴이 가장 흔한 강제 요인(forcing function)인 것으로 보입니다. 댓글로 남겨주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기