MCP 인증: 12개의 MCP 서버를 정신 건강을 해치지 않고 보안 처리한 방법
요약
MCP(Model Context Protocol) 환경에서 여러 서버, 에이전트, 사용자 ID의 자격 증명을 안전하게 관리하는 방법을 다룹니다. 정적 API 키의 위험성을 지적하며, 복잡한 인증 관계를 해결하기 위한 단계별 접근 방식과 보안 고려 사항을 설명합니다.
핵심 포인트
- MCP 인증은 클라이언트, 게이트웨이, 사용자 위임이라는 세 가지 복잡한 관계를 가짐
- 정적 API 키 방식은 토큰 로테이션과 감사 추적(Audit trail) 측면에서 보안에 취약함
- 에이전트가 사용자를 대신해 행동할 때 신원을 전달하는 사용자 위임 설계가 중요함
- 단순한 암호학적 문제를 넘어 시스템 간의 조정(Coordination)이 핵심 과제임
요약 (TL;DR): MCP 인증은 여러 서버, 여러 에이전트, 그리고 여러 사용자 ID에 걸쳐 자격 증명(credentials)을 동시에 관리해야 하기 때문에 일반적인 API 인증보다 훨씬 더 복잡합니다. 접근 방식은 정적 API 키(빠르지만 규모가 커지면 보안에 취약함)부터 PKCE를 포함한 OAuth 2.1(표준 준수, 설정 복잡함), 그리고 모든 하위 인증을 대신 처리해 주는 중앙 집중식 게이트웨이까지 다양합니다. 저희는 이 세 가지 단계를 모두 거쳤습니다. 이 포스트에서는 저희가 배운 점들을 다룹니다.
8개월 전 저희의 MCP 인증 방식은 이랬습니다: .env 파일에 공유 API 키를 넣어두고, 모든 개발자가 모든 것에 접근할 수 있게 하며, 나쁜 일이 일어나지 않기만을 기도하는 방식이었죠.
두 번의 아찔한 상황(설정이 잘못된 쓰기 도구를 통해 프로덕션 데이터를 거의 삭제할 뻔한 에이전트 한 대, 퇴사 후에도 MCP 접근 권한이 회수되지 않은 계약직 한 명)을 겪은 후, 저희는 이 문제를 진지하게 다루기 시작했습니다.
저희가 최종적으로 도달한 설정 방식과 각 부분이 해결한 문제, 그리고 설정에 소요된 비용은 다음과 같습니다.
MCP 인증이 일반적인 API 인증보다 어려운 이유
일반적인 API 인증은 하나의 자격 증명 관계를 가집니다: 귀하의 애플리케이션이 서비스에 인증하는 방식입니다. 반면 MCP 인증은 세 가지 관계를 가집니다:
클라이언트(Client) → 게이트웨이/서버(Gateway/Server): 에이전트가 MCP 인프라에 자신의 신원을 증명하는 방식
게이트웨이(Gateway) → 하위 서비스(Downstream service): MCP 서버가 GitHub, Jira, Slack 또는 해당 서버가 래핑(wrap)하고 있는 백엔드에 인증하는 방식
사용자 위임(User delegation): 에이전트가 특정 인간을 대신하여 행동할 때(봇이 아닌 사용자로 Slack에 게시), 해당 사용자의 신원이 호출 체인을 통해 흐르는 방식
이 세 가지를 서버별, 개발자별, 에이전트별로 수동 관리하는 과정에서 복잡성이 폭발합니다. 대부분의 MCP 인증 문제는 암호학(cryptography)의 문제가 아니라 조정(coordination)의 문제입니다.
복잡도 순으로 본 인증 방법들
정적 API 키 / 베어러 토큰 (Static API keys / Bearer tokens)
가장 간단한 옵션입니다. MCP 서버는 Authorization 헤더에 정적 베어러 토큰(Bearer token)이 있기를 기대합니다. 서버 설정과 클라이언트 설정에 각각 한 번씩 설정하면 끝납니다.
{
"mcpServers": {
"my-server": {
...
적합한 경우: 단일 운영자가 있는 내부 서버, 개발 환경, 빠른 프로토타입 제작.
한계점: 로테이션 (Rotation). 토큰이 변경될 때마다 해당 토큰을 사용하는 모든 클라이언트를 업데이트해야 합니다. 개발자 15명과 8개의 서버가 있는 환경에서 토큰 로테이션은 조율하기 매우 힘든 악몽이 됩니다. 또한, 토큰이 리포지토리의 .env 파일에 들어있다면 결국 Git 히스토리에 남게 됩니다.
실질적인 위험: 정적 토큰 (Static tokens)에는 사용자 신원 (User identity)이 연결되어 있지 않습니다. 에이전트가 정적 토큰을 사용하여 도구 (Tool)를 호출할 때, 어떤 개발자나 워크플로우가 이를 트리거했는지 알 수 있는 방법이 없습니다. 감사 추적 (Audit trails)은 "토큰 X가 시간 Z에 도구 Y를 호출함"과 같이 남게 되며, 이는 컴플라이언스 (Compliance)나 사고 대응 (Incident response)에 있어 무용지물입니다.
stdio 서버를 위한 환경 변수 (Environment variables)
Stdio 기반 MCP 서버는 로컬 프로세스로 실행됩니다. 인증은 MCP 프로토콜 외부에서 이루어집니다. 즉, 서버가 시작될 때 읽을 수 있도록 환경 변수 (Environment variables)로 자격 증명 (Credentials)을 전달합니다.
{
"mcpServers": {
"github": {
...
Claude Code와 Cursor의 ${env:VAR} 구문은 설정 파일에 값을 하드코딩하는 대신 셸 환경 (Shell environment)에서 값을 가져옵니다. 이를 통해 자격 증명이 버전 관리 시스템 (Version control)에 포함되지 않도록 유지할 수 있습니다.
적합한 경우: 각 개발자가 자신의 자격 증명으로 인증하는 stdio 서버 기반의 로컬 개발.
한계점: 확장성 (Scale)이 부족합니다. 각 개발자가 서버별로 자신의 자격 증명을 직접 관리해야 합니다. 중앙 집중식 권한 취소 (Revocation) 기능이 없습니다. 개발자가 퇴사할 때, 그들이 로컬 환경을 정리했기를 바라야만 합니다 (대개는 정리하지 않습니다).
원격 서버를 위한 PKCE 기반 OAuth 2.1
MCP 명세 (Spec)는 2025년 3월 개정판에서 PKCE를 포함한 OAuth 2.1을 표준화했습니다. 이는 기존의 ID 제공자 (Identity provider)를 통해 도구 호출을 실제 사용자 신원과 연결하기 때문에, 원격 MCP 서버를 위한 올바른 장기적 해답입니다.
흐름 (Flow):
- 에이전트 (Agent)가 MCP 연결을 시작합니다.
- 서버가 사용자의 IdP (Okta, Azure AD, Auth0)로 리다이렉트합니다.
- 사용자가 브라우저에서 인증을 수행합니다.
- IdP가 권한 부여 코드 (Authorization code)를 발급합니다.
- 클라이언트가 해당 코드를 액세스 토큰 (Access token)으로 교환합니다 (PKCE를 통해 가로채기를 방지합니다).
- 이후의 모든 MCP 호출에 토큰이 첨부됩니다.
이를 통해 얻는 이점: 도구 호출 (Tool calls)이 공유 서비스 자격 증명이 아닌 인증된 사용자와 연결됩니다. 토큰은 만료되며 자동으로 갱신됩니다. IdP에서 사용자의 액세스 권한을 취소하면 MCP 액세스 권한도 자동으로 취소됩니다.
이에 따른 비용: 더 많은 설정이 필요합니다. MCP 서버에 OAuth 리소스 서버 (Resource server) 측 구현이 필요합니다. 클라이언트는 브라우저 리다이렉트 흐름 (Browser redirect flow)을 처리해야 합니다. 모든 MCP 클라이언트가 2025년 11월 사양 개정안을 완전히 구현한 것은 아니므로, 이를 의존하기 전에 사용 중인 특정 클라이언트의 OAuth 지원 여부를 확인하십시오.
서비스 계정을 위한 PAT 및 VAT
인간의 개입 (Human-in-the-loop, 브라우저 리다이렉트 불가) 없이 실행되는 프로덕션 에이전트의 경우, 개별 사용자를 위한 개인 액세스 토큰 (PAT, Personal Access Tokens)과 서비스 계정을 위한 가상 계정 토큰 (VAT, Virtual Account Tokens) 패턴을 사용합니다.
- PAT: 특정 사용자의 신원과 결합되며, 개발 워크플로 및 사용자 위임 작업에 적합합니다.
- VAT: 정의된 권한을 가진 서비스 계정 자격 증명으로, 연결된 사용자 없이 프로덕션에서 실행되는 자동화된 에이전트에 적합합니다.
이 구분은 감사 추적 (Audit trails) 측면에서 중요합니다. PAT 호출은 특정 개발자로부터 오는 것으로 표시되며, VAT 호출은 지정된 서비스 계정으로부터 오는 것으로 표시됩니다.
우리가 최종적으로 선택한 설정
두 번의 아찔한 상황을 겪은 후, 우리는 개발자당 서버별로 개별적인 OAuth 흐름을 관리하고 싶지 않았습니다. 유지보수 범위가 너무 넓었기 때문입니다. 대신 우리가 구현한 것은 모든 다운스트림 인증 (Downstream auth)을 대신 처리해 주는 중앙 집중식 게이트웨이입니다.
작동 방식:
개발자당 하나의 토큰, 서비스 계정당 하나의 토큰. 개발자는 단일 PAT (Personal Access Token)로 게이트웨이에 인증합니다. 서비스 에이전트는 VAT (Virtual Access Token)로 인증합니다. 게이트웨이는 GitHub OAuth 토큰, Jira API 키, Confluence 토큰, 내부 API 서비스 계정 등 모든 다운스트림 자격 증명 (Downstream credentials)을 관리하며, 만료되기 전에 자동으로 갱신합니다.
도구 수준의 RBAC (Role-Based Access Control, 역할 기반 액세스 제어). 우리는 다음과 같이 설정할 수 있습니다: "A 유형의 팀은 Jira에서 search_issues와 create_issue를 호출할 수 있지만, delete_issue는 호출할 수 없다." 이는 게이트웨이 설정에서 서버별, 도구별, 역할별로 정의됩니다. 에이전트는 권한이 없는 도구를 절대 볼 수 없습니다. tools/list 호출 시 호출자의 신원을 기반으로 필터링된 세트만 반환됩니다.
사용자 위임 작업을 위한 OAuth 2.0. 특정 사용자를 대신하여 동작해야 하는 도구 호출(예: 특정 인물로서 Slack에 게시, 적절한 엔지니어가 작성한 것으로 표시되는 Jira 티켓 생성 등)의 경우, 우리의 Okta 설정과 함께 OAuth 2.0을 사용합니다. 게이트웨이가 토큰 교환 및 갱신을 처리합니다. 에이전트는 OAuth 흐름을 직접 관리하지 않습니다.
모든 호출에 대한 감사 로그 (Audit log). 모든 도구 호출이 기록됩니다: 어떤 에이전트가, 어떤 사용자 신분으로, 어떤 도구를, 어떤 파라미터로 호출했는지, 응답은 무엇이었는지, 그리고 타임스탬프가 포함됩니다. 이는 우리 보안 팀의 타협할 수 없는 요구 사항이었으며, 프로덕션 환경에서 에이전트 장애를 디버깅할 때도 실제로 매우 유용합니다.
우리는 TrueFoundry의 MCP Gateway를 사용하여 이를 구현했습니다. Okta 통합 설정에는 약 하루가 소요되었습니다. RBAC 설정은 정책을 적절히 정의하기 위해 서버당 대략 하루 정도가 걸렸습니다. 이러한 시간 투자는 첫 달 만에 보상을 받았습니다. 한 차례의 퇴사(offboarding) 이벤트가 발생했을 때, 6개의 개별 자격 증명을 일일이 찾아다니는 대신 대시보드에서 단 한 번의 작업으로 MCP 액세스를 완전히 취소할 수 있었습니다.
알아둘 만한 CVE
2026년 초, JFrog Security Research는 인기 있는 MCP OAuth 구현체(v0.1.16 및 이전 버전)에서 발견된 취약점을 공개했습니다. 해당 패키지는 OAuth 인증 엔드포인트(authorization endpoint) URL을 검증(sanitization) 없이 시스템 핸들러로 전달하는 문제가 있었습니다. 악의적인 MCP 서버는 개발자의 머신에서 임의의 OS 명령을 실행할 수 있는 URL을 구성할 수 있었습니다.
해당 문제는 v0.1.16에서 수정되었습니다. 하지만 더 중요한 교훈은 다음과 같습니다. MCP 클라이언트의 OAuth 흐름은 비교적 최근의 기술이며, 사양(spec)이 여전히 정립되는 과정에 있다는 점입니다(2025년 11월 개정판에서는 대부분의 경우 동적 클라이언트 등록(Dynamic Client Registration)을 대체하는 클라이언트 ID 메타데이터 문서(Client ID Metadata Documents)를 권장 등록 방식으로 도입했습니다). 프로덕션 워크로드에 OAuth를 의존하기 전에, 사용 중인 MCP 클라이언트의 패치 수준과 구현된 사양 준수 버전을 반드시 확인하십시오.
여러분의 현재 MCP 인증 설정은 어떠하며, 무엇이 여러분으로 하여금 이를 진지하게 다루도록 만들었나요? "쓰기 도구(write tool)를 통한 사고 직전의 상황" 패턴이 흔한 계기로 보이는데, 다른 분들은 어떤 경험을 하셨는지 궁금합니다. 댓글로 남겨주세요.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기