SDK·MCP 데이터 인가 (#2701)
MCP 도구·AI Agent·CLI 가 공통으로 쓰는 gend_api.sdk 계층의 데이터 인가 운영
가이드입니다. REST 라우터(/api/v1/query/execute, /api/v1/catalog/*)와 같은 시행
헬퍼를 쓰므로 두 경로의 판정이 갈리지 않습니다.
이 기능 이전에는 SDK 계층에 데이터 인가가 없었습니다. 같은 SQL 을 REST 로 보내면 마스킹되고 MCP 로 보내면 원본이 나왔습니다. ADR-0031 참조.
무엇이 언제 적용되는가
| 통제 | 플래그 | 기본 동작 |
|---|---|---|
| PII 컬럼 마스크 | 없음 | 항상 시행. 면제는 unmask 역할 단독 (admin 이라는 이유만으로는 면제되지 않음, #2673) |
| 행 필터 (AccessPolicy) | 없음 | 항상 시행 |
gendpg 워크스페이스 행 필터 | 없음 | 항상 시행. 안전 재작성 불가 시 거부(fail-closed) |
| DataGrant SELECT 차단 | GEND_GRANT_ENFORCEMENT_MODE | REST 와 동일 설정을 공유 (현재 prod whitelist) |
| DataGrant 가시성 필터 (카탈로그/스키마/테이블 목록) | GEND_SDK_AUTHZ_MODE | observe — 관측만, 목록을 바꾸지 않음 |
가시성 필터만 단계 시행하는 이유는 기존 MCP 클라이언트가 grant 부족으로 갑자기 빈 목록을 받는 회귀를 막기 위해서입니다. 마스킹·행필터는 결과가 "빈 목록"이 아니라 "마스킹된 값"이라 그런 위험이 없어 즉시 시행합니다.
GEND_SDK_AUTHZ_MODE
| 값 | 동작 |
|---|---|
off | 가시성 필터를 계산하지 않음 |
observe | 기본. 필터를 계산해 카운터·로그만 남기고 원본 목록을 반환 |
enforce | REST 라우터와 동일하게 실제 필터링. 단건 조회는 ForbiddenError |
- 알 수 없는 값은 error 로그 후
observe로 폴백합니다 (오타가 전면 차단이나 전면 무시로 번지지 않도록). observe는 필터 조회가 실패해도 원본을 반환합니다. 관측 목적으로 켜둔 코드가 DB 순단만으로 MCP 호출을 깨뜨려서는 안 되기 때문입니다.enforce에서는 예외를 전파합니다(fail-closed).
메트릭
| 메트릭 | 라벨 | 의미 |
|---|---|---|
gend_sdk_authz_filtered_total | domain, caller_type, mode | 가시성 필터가 걸러낸(또는 걸러냈을) 항목 수 |
gend_sdk_authz_bypass_total | caller_type | control-plane(SYSTEM) 호출자가 게이트를 우회한 횟수 |
gend_sdk_authz_gate_total | domain, caller_type, mode | 게이트가 평가된 횟수 (filtered 의 분모, #2719) |
domain 은 catalogs / schemas / tables / columns / sample.
승격 절차 (observe → enforce)
- 관측 (1주 권장): 필터링 비율로 판단합니다 —
sum(rate(gend_sdk_authz_filtered_total[1w])) / sum(rate(gend_sdk_authz_gate_total[1w])). 분모 없이 분자만 보면 "거를 게 없었다"와 "게이트가 안 돌았다"가 구분되지 않습니다.domain·caller_type별로 확인합니다. - 0 이 아니면 grant 를 먼저 발급합니다. 지금 목록을 보고 있는 caller 가
enforce 전환 즉시 못 보게 되는 것이 그 수치의 의미입니다.
caller_type=mcp가 대부분이라면 해당 M2M 클라이언트의 DataGrant 현황을 먼저 확인하세요. - 1주간 0 에 수렴하면 승격합니다.
kubectl --context aks-genos-prod -n gend set env deploy/gend-api \GEND_SDK_AUTHZ_MODE=enforcekubectl --context aks-genos-prod -n gend rollout status deploy/gend-api
- 롤백은 같은 명령으로
observe를 되돌려 놓으면 됩니다 — DB 변경이 없어 즉시 복구됩니다.
감사
MCP 도구 호출은 mcp_call_logs 에 기록되며, 이 기능부터 다음이 채워집니다.
workspace_id— 호출자의 워크스페이스params_hash— 도구 인자의 SHA-256 (인자 원본은 저장하지 않음)
대상 좌표(catalog/schema/table)는 mcp_access_history(#832)에 별도로 기록되며 두
테이블을 조인해 재구성합니다.
감사 HMAC 체인이 서명하는 것은 endpoint 와 status 이고, SQL 본문은
/api/v1/query 접두 경로에서만 2000자까지 저장됩니다. SDK·MCP·CLI 경로의 SQL 본문은
기록되지 않습니다. 고객 문서에 "모든 열람이 기록된다"고 쓰지 마십시오 —
"열람 행위가 기록된다"까지가 정확합니다.
커버리지와 한계
커버: MCP 도구 6종(list_catalogs / list_schemas / list_tables /
describe_table / sample_table / execute_query), AI Agent 의 SQL·카탈로그 도구,
gend-cli 의 동일 경로.
미커버 (의도된 범위 제한):
sample_table의 컬럼 마스킹 — REST 의 sample 엔드포인트에도 없습니다. 한쪽만 조이면 MCP 가 UI 보다 엄격해지는 포크가 되므로 양 평면 동시 적용을 별도 처리합니다.- MCP/Agent 쿼리의
query_history기록 — 별도 작업. governance/quality/engineering/complianceSDK 도메인의 워크스페이스 필터.- 엔진 계층 — gend-api 를 거치지 않고 Trino 에 직접 도달하는 경로는 본 시행 밖입니다 (ADR-0030, #2683).
- 벡터/문서 검색(Weaviate) — Trino 를 거치지 않아 본 시행이 닿지 않습니다.