728x90
반응형
Gemini에서 생성된 이미지

엔터프라이즈 AI는 빛의 속도로 움직이고 있습니다. 팀은 LLM을 내부 데이터베이스, 지식 그래프, 문서 저장소 및 비즈니스 도구에 연결하여 실제로 질문에 답할 수 있는 AI 보조자를 구축하고 있습니다.데이터. 이를 가능하게 하는 프로토콜은모델 컨텍스트 프로토콜(MCP), 사람들이 "AI용 USB-C"라고 부르기 시작한 개방형 표준입니다. 하나의 인터페이스로 무엇이든 바로 연결됩니다.

하지만 물리적 USB-C 포트와 마찬가지로 무엇이든 연결할 수 있으며 이로 인해 눈에 띄는 보안 문제가 발생합니다.

MCP를 사용하면 AI 모델에 도구, 데이터 및 서비스에 대한 액세스 권한을 쉽게 부여할 수 있습니다. 대부분의 데모에서 조용히 건너뛰는 것은 해당 데이터가 모든 사람을 위한 것이 아닐 때 일어나는 일입니다. 사람마다 허가 수준이 다릅니다. 두 사람이 동일한 AI 어시스턴트를 통해 동일한 질문을 해도 동일한 답변이 표시되지 않아야 합니다.

하지만 오늘날 대부분의 MCP 설정에서는 그렇습니다.

무엇이 위태로워요

신원 인식 액세스 제어가 없으면 그 결과는 다음과 같습니다.

  • : 민감한 정보는 볼 의도가 전혀 없었던 사용자에 대한 AI 생성 응답에 표시됩니다.
  • 규정 준수 위반: GDPR, SOX, MiFID II와 같은 규정에서는 민감한 데이터에 대한 통제되고 감사 가능한 액세스가 필요합니다. 누가 요청했는지 구별할 수 없는 시스템은 신뢰할 수 있는 감사 추적을 생성할 수 없습니다.
  • : 이해관계자가 보지 말았어야 할 AI 비서 표면 데이터를 발견하면 전체 시스템에 대한 신뢰가 무너지고 채택 탱크가 발생합니다.

아이러니한 점은 대부분의 조직이 이미 인간 사용자에 대한 강력한 액세스 제어 기능을 갖추고 있다는 것입니다. 문제는 MCP가 사용자와 데이터베이스 사이에 위치하며 대부분의 구현에서 요청에서 사용자의 신원을 완전히 제거한다는 것입니다.

문제: MCP는 ID 진공 상태에서 작동합니다.

이것을 상상해보세요. 한 금융 서비스 회사는 MCP가 AI와 내부 지식 그래프 사이의 관문인 Agentic RAG 시스템을 구축했습니다. 매일 세 가지 다른 페르소나가 사용합니다.

  • A (예: 고위 관리자) 이사회 메모, AML 보고서 및 위험 평가를 검토합니다.
  • An (예: 분석가) 부문 실적 데이터, 시장 조사, 수익 분석 등을 다룹니다.
  • An (예: 고객 또는 감사자)는 보도 자료 및 규제 서류에만 접근할 수 있습니다.

그들은 각각 다른 허가 수준을 가지고 있습니다. 다른 데이터가 표시되어야 합니다. 하지만 그런 일은 일어나지 않습니다.

식별되지 않는 MCP: 하나의 열쇠가 모든 문을 엽니다.

비보안 MCP 설정을 사용하면 MCP 서버는 종종 환경 변수에 구운 단일 정적 자격 증명 세트를 사용하여 데이터베이스를 인증합니다. 누가 트리거했는지에 관계없이 모든 요청은 동일한 ID로 실행됩니다. 데이터베이스는 쿼리가 고위 관리자, 분석가 또는 외부 클라이언트로부터 나온 것인지 알 수 없습니다. 모든 것을 반환합니다.

당신이 알기도 전에 외부 클라이언트가 실수로 AML 보고서를 가져오거나 분석가가 보드 메모 요약을 받게 됩니다. 악의적으로 보안을 우회한 사람은 아무도 없습니다. 시스템은 사용자를 구별하는 방법을 몰랐습니다. LLM이 사용자를 대신하여 데이터베이스를 호출하면 보안 감사 추적에 막대한 사각지대가 생성됩니다. 이는 현재 대부분의 MCP 서버의 기본 상태입니다.

해결 방법: ID 기반 액세스 제어 도입

이 문제를 해결하려면 MCP 서버가 서비스 계정처럼 작동하는 것을 멈추고 투명한 파이프처럼 작동하여 사용자의 실제 신원을 평가할 데이터 계층으로 전달하는 아키텍처가 필요합니다.

이것이 실제로 어떻게 보이는지 설명하기 위해 다음을 사용하여 이 패턴을 구축하겠습니다.Neo4j MCP 서버. HTTP 전송 모드에서 Neo4j MCP 서버를 실행하면 모든 요청에 ​​대해 사용자의 OIDC Bearer 토큰을 직접 전달할 수 있습니다. 그래프 데이터베이스는 정적 자격 증명에 의존하는 대신 JWT를 평가하고 기본적이고 세분화된 역할 기반 액세스 제어를 시행합니다. 상담원은 질문만 합니다. 그래프는 정책을 시행합니다. 이것이 어떻게 작동하는지 살펴보겠습니다.

아키텍처: 원 토큰, 제로 트러스트

여기서 핵심 원칙은 간단합니다. 사용자의 신원은 스택 중간에서 제거, 번역 또는 재합성되어서는 안 됩니다. ID 공급자가 발행한 정확한 JWT는 데이터베이스에 도달하는 정확한 토큰이어야 합니다.

SSO/OIDC를 통한 MCP 인증/승인 워크플로

조각들이 서로 맞춰지는 방법은 다음과 같습니다.

  • 로그인:사용자는 PKCE와 함께 OIDC를 사용하여 ID 공급자에 대해 인증합니다. 이 아키텍처에서는 Keycloak이 로컬 IdP로 사용됩니다. 로그인 시 Keycloak은 사용자의 액세스 계층(/Confidential, /Internal 또는 /External)을 정의하는 그룹 클레임을 포함하는 JWT를 반환합니다.
  • 요청:사용자가 상담원에게 질문을 하면(“Globex Inc의 최신 소식은 무엇입니까?”), MCP 클라이언트(LLM으로 구동되는 FastAPI 백엔드)는 사용자의 JWT와 함께 Bearer 토큰으로 메시지를 수신합니다.
  • 통과:MCP 클라이언트는 Streamable HTTP를 통해 Neo4j MCP 서버에 연결하여 요청 헤더에 해당 Bearer 토큰을 전달합니다. MCP는 요청별 인증을 지원하므로 모든 도구 호출은 인간 호출자의 신원을 전달합니다.
  • 집행:MCP 서버가 Cypher 쿼리를 발행하면 단순히 토큰을 전달합니다. Neo4j는 Keycloak의 JWKS 엔드포인트에 대해 JWT를 검증하고, 그룹 클레임을 추출하고, 이를 기본 데이터베이스 역할에 매핑하고, 해당 권한 하에서 엄격하게 쿼리를 실행합니다.

설정 및 구성

각 역할이 Keycloak 그룹에서 범위가 지정된 Neo4j 액세스 계층/역할로 매핑되는 방법은 다음과 같습니다.

Keycloak 그룹을 Neo4j 역할에 매핑

1) 키클로크 구성

이 데모에서는 Neo4j의 OIDC 통합을 위해 구성된 클라이언트와 함께 myCorp라는 Keycloak 영역을 설정했습니다. 여기서는 영역 및 클라이언트 생성의 모든 단계를 다루지는 않겠습니다. 보다 전체적인 가이드는 다음을 참조하세요.Keycloak 시작 가이드.

영역 내에서 세 명의 사용자를 생성하고 각각을 다른 액세스 계층에 매핑되는 그룹에 할당했습니다. 아래 스크린샷에서 사용자 및 그룹 설정을 볼 수 있습니다.

Keycloak에 구성된 사용자
Keycloak에 구성된 그룹

: Keycloak을 설정할 때 다음 사항을 확인하세요.프로토콜 매퍼를 사용하여 명시적으로 구성됩니다. 이것이 없으면 Neo4j의 OIDC 제공자는 모든 토큰을 자동으로 거부합니다.aud 청구가 일치하지 않습니다.

2) Neo4j 구성

Neo4j Enterprise에는 기본OIDC/SSO 지원. 설정을 위해 Docker에서 로컬로 Neo4j와 Keycloak을 모두 실행했습니다. 전체 SSO 구성은 다음과 같습니다.

# OIDC / Keycloak SSO
NEO4J_dbms_security_authentication__providers: "oidc-keycloak,native"
NEO4J_dbms_security_authorization__providers: "oidc-keycloak,native"
NEO4J_dbms_security_oidc_keycloak_display__name: "Keycloak"
NEO4J_dbms_security_oidc_keycloak_auth__flow: "pkce"
NEO4J_dbms_security_oidc_keycloak_params: "client_id=neo4j-client;response_type=code;scope=openid email roles"
NEO4J_dbms_security_oidc_keycloak_audience: "account"
NEO4J_dbms_security_oidc_keycloak_claims_username: "preferred_username"
NEO4J_dbms_security_oidc_keycloak_claims_groups: "groups"

# Map Keycloak groups to Neo4j database roles
NEO4J_dbms_security_oidc_keycloak_authorization_group__to__role__mapping: '"/Confidential"=confidential;"/Internal"=internal;"/External"=external'

NEO4J_dbms_security_oidc_keycloak_config: "principal=preferred_username;token_type_principal=access_token;token_type_authentication=access_token"
NEO4J_dbms_security_oidc_keycloak_well__known__discovery__uri: "https://keycloak:8443/realms/myCorp/.well-known/openid-configuration"
NEO4J_dbms_security_oidc_keycloak_token__endpoint: "https://127.0.0.1:8443/realms/myCorp/protocol/openid-connect/token"

# Must match JWT iss claim (browser-facing)
NEO4J_dbms_security_oidc_keycloak_issuer: "https://127.0.0.1:8443/realms/myCorp"

# Browser-facing (PKCE redirect)
NEO4J_dbms_security_oidc_keycloak_auth__endpoint: "https://127.0.0.1:8443/realms/myCorp/protocol/openid-connect/auth"

그룹-역할 매핑은 ID가 인증되는 곳입니다. JWT가 [“/Confidential”] 그룹과 함께 도착하면 Neo4j는 해당 세션에 기밀 데이터베이스 역할을 할당합니다. 각 역할에 부여된 권한에 따라 표시되는 노드 라벨과 쿼리 결과에 표시되는 속성이 정확히 결정됩니다.

역할 기반 액세스 제어(RBAC)

실제 액세스 제어를 보여주기 위해 HAS_DOCUMENT 관계로 연결된 문서 및 회사 노드가 있는 작은 샘플 그래프를 설정했습니다. 여기서 핵심 메커니즘은 다음과 같습니다.액세스 등급으로서의 Neo4j 노드 라벨.

이 시나리오에서는 각 문서에 내부, 공개 또는 기밀과 같은 레이블이 지정되어 가시성 수준을 나타냅니다. 아래 스크린샷에서 선택한 문서 노드가 내부 소비 전용임을 나타내는 문서 및 내부 레이블을 모두 전달하는 방식을 확인하세요.

문서 및 회사 노드가 포함된 그래프를 보여주는 Neo4j Bloom

이것이 바로 Neo4j의 세밀한 RBAC가 빛을 발하는 부분입니다. 예를 들어 내부 역할이 있는 사용자는 내부 또는 공개라는 레이블이 붙은 문서 노드를 쿼리할 수 있습니다. 하지만 기밀 레이블이 붙은 모든 문서 노드는 전혀 보이지 않습니다. 쿼리가 실행된 후에는 필터링되지 않습니다. 해당 역할에 관한 한 해당 노드는 단순히 투명합니다. 이는 애플리케이션 수준 필터링이 아닌 데이터베이스 수준 적용입니다.

다중 보안 계층: 데이터베이스 + 레이블 + 속성 수준 RBAC

Neo4j의 액세스 제어는 라벨 가시성에 국한되지 않고 다음까지 확장됩니다.역할별로. 이는 당신이 통제할 수 있을 뿐만 아니라역할은 노드를 볼 수 있지만해당 노드를 쿼리하면 반환됩니다.

이를 통해 3가지 보안 계층이 생성됩니다.

사용자 역할과 권한의 매트릭스 매핑
  1. 데이터베이스 수준 액세스역할이 연결할 수 있는 데이터베이스를 제어하며 일반적으로 프로젝트 그룹이나 환경을 구분하는 데 사용됩니다. 관리에 있어서 매우 중요합니다그리고 저장각 데이터베이스가 한 명의 사용자에게 속하도록 하여 완전한 데이터 격리를 구축합니다. 이 게시물에서는 이에 대해 자세히 다루지 않겠습니다.
  2. 라벨 기반 액세스통제 수단역할은 전혀 볼 수 없습니다. 외부 사용자는 기밀 문서의 존재를 전혀 알 수 없습니다.
  3. 자산 기반 액세스통제 수단보이는 문서 내로 돌아옵니다. 내부 사용자는 문서의 요약과 메타데이터를 읽을 수 있지만 내부_노트(분석가가 실제로 생각하는 내용을 기록하는 곳)와 같은 민감한 필드는 결과에서 조용히 제외됩니다.

기밀 역할만이 수정되지 않은 전체 그림을 얻을 수 있습니다.

관계형 세계에서 왔다면 그래프에 기본적으로 적용되는 열 수준 보안이라고 생각하세요. 차이점은 라벨 기반 행 필터링 위에 레이어를 추가하여 일반적으로 실행하기 위해 뷰나 미들웨어가 필요한 다차원 액세스 매트릭스를 제공한다는 것입니다.

이것이 GenAI에 중요한 이유

위의 세 명의 사용자를 기억하시나요? 이제 그들이 모두 MCP 계층의 지원을 받는 AI 보조자에게 동일한 질문을 한다고 상상해 보십시오.“Globex Inc에 대한 최신 소식은 무엇인가요?

다양한 사용자가 서로 다른 현실을 경험함

MCP 계층은 매번 동일한 암호 패턴을 실행합니다. 즉, Company 노드에서 탐색하고 연결된 모든 문서 노드를 끌어와 LLM에 컨텍스트로 제공합니다. ID 기반 인증을 사용하면 MCP 계층에서 모든 도구를 자유롭게 호출할 수 있습니다. 누가 무엇을 보아야 하는지 이해할 필요는 없습니다. 해당 책임은 전적으로 데이터베이스에 위임되며 각 역할은 현실에 대해 근본적으로 다른 그림을 얻습니다.

  • The 깔끔한 보도 자료 수준의 요약을 얻습니다.
  • The 시장 분석에서 더 풍부한 컨텍스트를 볼 수 있지만 Internal_notes 필드는 자동으로 제외됩니다.
  • Only 이사회 전략 메모와 솔직한 분석가 논평 등 모든 것을 볼 수 있습니다.

엄격한 액세스 제어가 없으면 세 사용자 모두 M&A 파이프라인, 제재 플래그, 반대 입찰 인텔리전스, 팀을 떠날 의도가 없는 내부 논평 등 동일한 내용을 보게 됩니다.

종합해 보기: Tech Stack

테스트를 쉽게 하기 위해 모든 것을 단일 Docker Compose 스택으로 패키징했습니다. 그러면 Keycloak, Neo4j Enterprise, Neo4j MCP 서버 및 FastAPI 프런트엔드가 모두 동시에 실행됩니다. FastAPI 백엔드는 MCP 클라이언트 역할을 합니다. 저는 완전히 모델에 구애받지 않는 LiteLLM 설정을 선택했습니다. 즉, Cohere, OpenAI, Claude 또는 원하는 다른 LLM을 연결할 수 있습니다.

from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession

async def call_mcp_tool(tool_name: str, arguments: dict, bearer_token: str):
    """Connect to neo4j-mcp-server with the user's JWT."""
    headers = {"Authorization": f"Bearer {bearer_token}"}

    async with streamablehttp_client(MCP_SERVER_URL, headers=headers) as (
        read_stream, write_stream, _,
    ):
        async with ClientSession(read_stream, write_stream) as session:
            await session.initialize()
            result = await session.call_tool(tool_name, arguments)
            return result

주요 세부 사항: 모든 MCP 호출은사용자의 JWT, 서비스 계정 토큰이 아닙니다. Neo4j는 모든 요청에서 독립적으로 토큰의 유효성을 검사합니다. 액세스 제어는 애플리케이션 계층에만 존재하지 않습니다. 이는 데이터베이스 계층에서 전파되고 제어됩니다.

OIDC/PKCE와 함께 작동하는 Neo4j MCP 보기

위와 동일한 시나리오를 사용하면 다음과 같습니다.

3명의 다른 사용자가 로그인하여 다음과 같이 질문합니다.“Globex Inc에 대한 최신 소식은 무엇인가요?”

MCP 계층은 뒤에서 매번 동일한 Cypher 쿼리를 생성합니다. 변경되는 유일한 것은 요청에 연결된 JWT이며, 그 하나의 차이점이 LLM이 볼 수 있는 내용을 변환합니다.

시나리오 1: 기밀 사용자(관리자)

다음 계정으로 로그인내부.관리자, 사용자는 완전한 가시성을 갖습니다. 민감한 문서 정보를 포함하여 세 가지 문서를 모두 쿼리할 수 있습니다.

Internal.manager로 로그인 시 응답

Neo4j MCP 읽기 암호 도구는 다음 암호 쿼리를 생성했습니다.

read-cypher
{ "query": "MATCH p=(c:Company)-[:HAS_DOCUMENT]->(d:Document) WHERE c.name CONTAINS 'Globex' RETURN p" }

Internal_notes의 솔직한 분석가 논평과 전체 이사회 전략 메모를 포함하여 모든 민감한 정보가 답변에 제공됩니다.

시나리오 2: 내부 분석가(내부 액세스)

다음 계정으로 로그인내부.분석가, 범위가 좁아집니다. 기밀 문서 및 Internal_notes 속성이 수정되고 쿼리는 내부 및 공용 문서만 반환합니다.

Internal.analyst로 로그인 시 응답

Neo4j의 속성 수준 RBAC는 결과에서 Internal_notes를 자동으로 제외합니다. 아래 그래프 보기를 확대하면(Neo4j 시각화 라이브러리), 그래프에 기밀 문서가 전혀 없고 반환된 노드에 Internal_notes 속성이 누락되어 있습니다.

추적성과 설명성을 위한 그래프 보기

사용자는 지식 그래프의 어떤 문서가 LLM의 답변에 영향을 미쳤는지 추적하고 설명할 수 있으며, 더 중요한 것은 액세스 계층 외부의 어떤 것도 응답으로 유출되지 않았는지 확인할 수 있다는 것입니다.

시나리오 3: 외부 리더(공개 액세스만 해당)

다음 계정으로 로그인외부.리더, 공개 라벨이 붙은 문서만 검색됩니다.

external.reader로 로그인 시 응답

외부 사용자는 최소한의 속성이 있는 공개 문서만 볼 수 있습니다. 속성 수준 제한은 심층적인 방어를 위해 라벨 제한 위에 계층화됩니다.

시사점 및 결론

MCP를 채택하는 모든 기업은 결국 동일한 질문에 직면하게 됩니다. 이 요청은 실제로 누구에게서 왔으며, 그들이 무엇을 볼 수 있도록 허용됩니까?

정적 서비스 계정 위에는 제로 트러스트를 구축할 수 없습니다. LLM을 기업 데이터에 연결하는 진정한 힘은 이를 수행하는 동안 데이터 거버넌스와 주권을 유지하는 경우에만 작동합니다.

Note: 이 접근 방식을 사용하려면 프런트엔드 클라이언트가 MCP 서버에 토큰을 위임해야 합니다. 이 글을 쓰는 시점에는 대부분의 상용 AI 인터페이스가 이를 기본적으로 지원하지 않으므로 사용자 정의 프런트엔드를 구축해야 할 가능성이 높습니다.

전체 Docker Compose 설정, Keycloak 영역 내보내기, FastAPI 백엔드, 데모 UI 및 TLS 구성은 다음에서 사용할 수 있습니다..

현재 AI 워크플로에서 액세스를 어떻게 관리하고 있나요? 댓글로 알려 주시거나 다음을 통해 저에게 연락해주세요.이메일또는링크드인.


  • AI 거버넌스
  • mcp 프로토콜
  • mcp 서버

에이치시스템즈LogTree는 Neo4j 기반 GraphRAG 플랫폼으로, 데이터를 자동으로 지식그래프화하고 자연어 질의로 즉시 답을 제공합니다.

👉 에이치시스템즈 홈페이지

728x90
반응형

+ Recent posts