Skip to main content
Glama
gwanghun-choi

vault-mcp

vault-mcp

vault-mcp 는 단순한 HashiCorp Vault 관리 도구가 아니라, 사내 서버·웹사이트·API 접속 정보(Credential)를 중앙에서 인증·인가·감사하며 관리하는 Ops Broker 다.

LLM(Claude) 또는 CLI 가 사용자의 요청을 중앙 API 에 전달하면, 중앙 API 가 사용자 인증·인가 → 리소스 해석 → Vault Credential 조회 → 결과 마스킹 → 감사 기록을 통제한다. 실제 Secret 은 Vault 에만 있고, LLM·CLI·DB·API 응답 어디에도 새지 않는다.

현재 단계: STEP 8.7 — Resource 유형 확장(SERVER/WEBSITE/API) 완료. 다음은 STEP 9(인증 개선). SSH 실행(Runner)은 STEP 10 으로 아직 미구현이다. 단계별 상세는 docs/development-roadmap.md.


목차


Related MCP server: Better Auth MCP Server

핵심 원칙

원칙

내용

Secret 격리

실제 Secret 은 Vault 에만. DB·API 응답·로그·감사에는 credential_ref(논리 경로)만.

1 Resource = 1 Credential

하나의 등록 항목 = 하나의 접속 대상 = 하나의 Credential. credential_id 개념 없음(1:N 아님).

소유자 전용

리소스는 소유자만 관리. 타인 리소스는 403 이 아니라 404(존재 은닉).

클라이언트 입력 불신

요청 body 의 user_id/credential_ref/vault_path/host 를 신뢰하지 않는다. 서버가 결정.

LLM 은 별칭만

Claude 는 alias + operation 만 추출. 서버 해석·Credential 조회는 중앙 API 가 사용자 권한 안에서 수행.

감사 강제

모든 Credential 접근(등록/교체/삭제/reveal)은 감사 로그에 기록(Secret 원문 제외).


아키텍처

현재 구현된 데이터 흐름(등록 / 조회 / 삭제). SSH 실행(Runner)은 STEP 10 으로 아직 없다.

flowchart TD
    subgraph client [클라이언트]
      W[Web UI · Jinja2]
      S[Claude Skill · REST]
    end
    W -->|Cookie 세션 + CSRF| API
    S -->|API Key| API
    API[vault-mcp FastAPI]

    API -->|인증 4종 → users.id| AUTH{인증·인가}
    AUTH -->|비민감 메타데이터| PG[(PostgreSQL<br/>vault_mcp schema)]
    AUTH -->|credential_ref 로 Secret| VAULT[(HashiCorp Vault<br/>KV v2)]
    API --> AUDIT[(audit_logs)]

    PG -.->|credential_ref = 논리 경로| VAULT

흐름

경로

등록

리소스 등록(PG) → Credential 등록 → Vault write → credential_ref 를 PG 에 저장

조회(reveal)

소유권 확인(PG) → credential_ref 로 Vault read → 평문 Secret 반환(no-store)

삭제

Vault soft delete → PG 상태/credential_ref 갱신 → commit. commit 실패 시 Vault undelete 로 보상

컴포넌트 책임:

컴포넌트

한다

하지 않는다

Claude Skill

alias/operation 추출, 결과 분석, 비민감 요약만 출력

Secret 원문 출력(사용자 요청해도 금지), Vault/경로 접근

Web UI

로그인, 리소스 CRUD, Credential 등록/교체/삭제, API Key 발급

Secret 재표시(Web 에 reveal 없음)

FastAPI

인증·인가·리소스 해석·Vault 연동·마스킹·감사

Secret 을 응답/로그에 노출

Vault

실제 Secret 저장

PostgreSQL

비민감 메타데이터 + credential_ref

실제 Secret 저장


Resource 유형과 저장 책임

STEP 8.7 부터 등록 대상은 SERVER / WEBSITE / API 세 유형이다(OTHER 는 범위 밖). 유형은 등록 후 변경 불가(409). 정본: docs/resource-types.md.

사용 · 항상 NULL(보내면 400) · 굵게 = 필수

필드

저장소

SERVER

WEBSITE

API

alias / description / service_name

PG

/ ✓ /

/ ✓ / ✓

/ ✓ / ✓

status / environment

PG

✓ / ✓

✓ / —

✓ / —

host / ssh_port

PG

/

site_url

PG

base_url / auth_type(ApiAuthType)

PG

/

header_name / token_prefix / scopes / expires_at

PG

login_id

PG

(¹)

✓(= client_id)

memo

PG

username / port

Vault

/ ✓

password

Vault

✓(²)

private_key / passphrase

Vault

✓(²)

api_key / token / refresh_token / client_secret / webhook_secret

Vault

✓(³)

  • (¹) SERVER 의 SSH username 은 Vault 에만 있다(하위 호환). 그래서 목록 응답의 login_id 는 SERVER 에서 항상 null.

  • (²) SERVER 는 auth_type(SshAuthType) 에 따라 password 또는 private_key(+선택 passphrase).

  • (³) API 는 auth_type(ApiAuthType) 이 어떤 Secret 이 필수인지 결정한다. client_id 는 secret 이 아니므로 PG, client_secret 은 Vault — reveal 이 한 쌍으로 반환.

인증 유형 enum 은 분리 유지한다: SERVER = SshAuthType(PASSWORD/PRIVATE_KEY, Vault), API = ApiAuthType(API_KEY/ACCESS_TOKEN/BEARER_TOKEN/PERSONAL_ACCESS_TOKEN/CLIENT_CREDENTIALS/ OAUTH_TOKEN/WEBHOOK_SECRET/CUSTOM, PostgreSQL). WEBSITE 는 인증 유형 개념이 없다.


API 레퍼런스

Base prefix /api/v1. 스키마·Authorize·curl 예시: docs/swagger-guide.md (/docs, /redoc, /openapi.json 은 local/dev 에서만 노출).

Secret 반환 은 reveal 하나뿐이다. 나머지 Credential API 는 상태 메타데이터만 준다.

Method

Path

용도

인증 / scope

Secret

GET

/health · /ready

Liveness / Readiness(DB+Vault)

없음

POST

/auth/register · /auth/login

LOCAL 가입 / 로그인(JWT 발급)

없음

GET

/me

현재 사용자 프로필

인증

POST/GET/DELETE

/api-keys · /api-keys/{id}

API Key 발급(1회 노출)/목록/폐기

Web 사용자만(API Key 로 불가)

발급 시 1회

GET

/servers · /servers/{alias}

operation 권한 있는 서버 목록/상세

servers.read

POST/PUT/GET/DELETE

/resources/{id}/credentials

전 유형 Credential 등록/교체/상태/삭제

인증

POST/PUT/GET/DELETE

/servers/{id}/credentials/ssh

SSH Credential (SERVER 전용 하위 호환)

인증

GET

/my/resources · /my/resources/search

내 소유 리소스 목록/검색(전 유형)

resources:read

POST

/my/resources/{id}/credentials/reveal

⚠️ Credential 원문 조회

credentials:reveal

평문

  • /resources/{id}/credentials(전 유형, STEP 8.7 신규)와 /servers/{id}/credentials/ssh(SERVER 전용 하위 호환)는 SERVER 에 대해 동작·저장 결과가 동일하다. 후자는 WEBSITE/API 대상이면 409.

  • reveal 응답은 resource_type discriminator 로 갈리는 oneOf(SERVER/WEBSITE/API). SERVER 응답은 resource_type 키만 additive 로 추가돼 기존 Skill 이 그대로 동작한다.

  • scope 표기 불일치는 코드 그대로다: servers.read(점) vs resources:read/credentials:reveal(콜론).

Web UI(/web/*, HTML+Cookie, OpenAPI 미노출): 로그인, 대시보드, 리소스 CRUD(유형 선택 → 유형별 폼), Credential 등록/삭제(reveal 없음), API Key 발급/폐기. 상세: docs/web-ui.md.


인증 방식

Authorization 헤더에서 4종을 라우팅하며 모두 내부 users.id 로 귀결된다. 클라이언트가 보낸 user_id/tenant_id/oid 는 신뢰하지 않는다.

방식

헤더

알고리즘

사용자 식별

용도 · 활성 조건

LOCAL JWT

Bearer <JWT>

HS256

sub = 내부 user_id

개발 주 로그인 / Web UI. local_auth_enabled + issuer 일치

Microsoft Entra

Bearer <JWT>

RS256(only, JWKS)

(tid, oid) 매핑

사내 SSO. Bearer JWT 기본 경로

API Key

ApiKey <dv_...> (또는 Bearer dv_...)

HMAC-SHA256 해시

key_hash → user_id

Claude/CLI. 접두 dv_dev_/dv_live_

DEV

헤더 없음

dev_auth_user_id

로컬 편의. dev_auth_enabled + is_local(prod fail-fast)


Vault 경로와 삭제 정책

논리 경로(DB credential_ref 에 저장). DB 값이 경로의 정본 — 읽기/교체/삭제 시 재생성하지 않고 저장값을 그대로 쓴다(그래서 기존 행이 호환 로직 없이 동작). 경로는 UUID 로만 구성(사용자 입력·alias 미사용 → path traversal 차단).

구분

형식

신규(전 유형)

users/{user_id}/resources/{resource_id}/credential

legacy(STEP 6~8 SERVER)

users/{user_id}/servers/{server_resource_id}/ssh

KV v2 물리 경로 = {mount}/data/{credential_ref}. VaultClient 는 App Token Policy 가 실제로 허용하는 endpoint 만 쓴다:

동작

HTTP endpoint

필요 capability

write / read

POST/GET /v1/{mount}/data/{path}

data/* create·read·update

metadata read

GET /v1/{mount}/metadata/{path}

metadata/* read

soft delete

POST /v1/{mount}/delete/{path}

delete/* update

undelete(보상)

POST /v1/{mount}/undelete/{path}

undelete/* update

삭제는 soft delete 다(destroy 아님, 복구 가능). 정책이 data/* 에 delete 를 주지 않으므로 DELETE /data/ 가 아니라 POST /delete/(버전 지정, metadata 로 current_version 선조회)를 쓴다 — 전자를 쓰면 403 으로 삭제가 전부 실패한다. Resource 삭제도 Vault Secret 을 함께 soft delete 하고, DB commit 실패 시 undelete 로 보상한다. 정본: docs/vault-client.md, docs/credential-storage-flow.md.


데이터 모델

전용 PostgreSQL schema vault_mcp 에 격리(공유 DB vault_mcp 의 public·타 schema 미사용). enum 은 비네이티브 VARCHAR(32). 정본: docs/data-model.md.

테이블

역할

users

신원. LOCAL(login_id+password_hash) / MICROSOFT(tenant_id+entra_oid) 두 출처

api_keys

API Key 메타데이터. 원문 미저장(key_hash/key_prefix 만)

server_resources

등록 대상 Resource(SERVER/WEBSITE/API 전부). 이름은 하위 호환으로 유지

server_permissions

인가 단위: 사용자 × 리소스 × operation. Default Deny, DENY 우선

vault_connections

Vault 접속 메타데이터. 중앙 Vault(시스템 소유)면 owner NULL

audit_logs

감사 이력. Secret 컬럼 없음

주요 제약(server_resources):

  • uq_server_resources_owner_user_id_alias — UNIQUE(owner_user_id, alias) WHERE status ≠ 'DELETED'(partial). soft delete 는 행을 남기므로, 삭제한 별칭을 재사용할 수 있게 DELETED 를 제외한다(0006). → 같은 alias 의 DELETED 행이 여러 개일 수 있어 alias 조회는 DELETED 를 거른다.

  • resource_type_allowedresource_type IN ('SERVER','WEBSITE','API')

  • auth_type_api_onlyauth_type IS NULL OR resource_type = 'API'(SshAuthType/ApiAuthType 혼용 차단)

Migration 이력(revision id 는 alembic_version.version_num VARCHAR(32) 제약):

revision

내용

0001_initial

초기 스키마 5테이블(vault_mcp schema, enum=VARCHAR(32))

0002_local_auth_and_api_keys

LOCAL 로그인 필드 + api_keys 테이블, Entra 필드 nullable 전환

0003_credential_ref_nullable

server_resources.credential_ref nullable(미등록=NULL)

0004_server_environment

environment 컬럼(DEV/STAGING/PROD 표시용)

0005_resource_types

resource_type + 유형별 필드, host/ssh_port/service_name NOT NULL 해제, 기존 행 SERVER backfill

0006_alias_unique_active_only

alias unique 를 DELETED 제외 partial index 로 교체

SQLite(테스트)는 ALTER COLUMN / ADD CONSTRAINT 미지원 → NOT NULL 완화·CHECK 추가는 PostgreSQL 에서만 수행하고, SQLite 는 모델 create_all 이 동일한 최종 스키마를 만든다.


빠른 시작

요구: Python 3.12+, uv. DB/Vault 없이도 /api/v1/health 는 뜬다.

# [로컬 PC / WSL·zsh]
uv sync                                   # 가상환경 + 의존성
cp .env.example .env                      # 값 채우기(아래 환경 변수 참고)
uv run uvicorn app.main:app --reload      # 또는: bash scripts/run-local.sh
  • API 문서: http://127.0.0.1:8000/docs (local/dev 에서만)

  • Web UI: http://127.0.0.1:8000/web/login

  • PoC 로그인 계정 생성: docs/poc-user-seed.md 의 seed 스크립트

LOCAL 로그인은 .env 에서 LOCAL_AUTH_ENABLED=true 여야 활성화된다(기본 false). Credential 등록/조회는 Vault 연결이 필요하다 — 개발 Vault 터널·App Token 준비는 docs/vault-local-development.md.


환경 변수

.env 로 관리(Git 커밋 금지, .env.example 만 저장). Secret 값은 Vault 또는 K8S Secret 으로, .env 에는 서버별 Credential 을 넣지 않는다.

접두

예시 키

비고

APP_*

APP_ENV, APP_HOST, APP_PORT

APP_ENV = local/dev/test/production

DB_*

DB_HOST/PORT/NAME/USERNAME/PASSWORD/SCHEMA

공유 DB vault_mcp, schema vault_mcp

LOCAL_* / PASSWORD_*

LOCAL_AUTH_ENABLED, LOCAL_JWT_SECRET, LOCAL_JWT_ISSUER

HS256 자체 JWT

API_KEY_*

API_KEY_HASH_SECRET, API_KEY_MAX_ACTIVE_PER_USER

미설정 시 SHA-256 fallback

ENTRA_*

ENTRA_TENANT_ID, ENTRA_CLIENT_SECRET, ENTRA_AUDIENCE, ENTRA_ISSUER

Resource Server 검증

VAULT_*

VAULT_ADDR, VAULT_TOKEN / VAULT_TOKEN_FILE, VAULT_KV_MOUNT

Token 원문 또는 0600 파일

DEV_AUTH_*

DEV_AUTH_ENABLED, DEV_AUTH_USER_ID

local/dev 한정(prod fail-fast)

기타

LOG_LEVEL, DOCS_ENABLED, CORS_ALLOWED_ORIGINS

굵게 = SecretStr(로그/응답 미노출): DB_PASSWORD, LOCAL_JWT_SECRET, API_KEY_HASH_SECRET, ENTRA_CLIENT_SECRET, VAULT_TOKEN.


테스트·품질 게이트

uv run pytest              # 493 passed, 7 skipped (skip = 실 Vault 통합 테스트)
uv run ruff check .        # All checks passed
uv run ruff format --check .
uv run mypy app            # strict, no issues (87 files)
  • 테스트 32개 파일. 보안 경계(타 사용자 접근, 권한 없는 operation, Secret 노출, alias 위조, Vault 실패 일관성 등)를 필수로 테스트.

  • 실 Vault 통합 테스트는 기본 skip. 실행: VAULT_MCP_INTEGRATION=1 VAULT_ADDR=... VAULT_TOKEN_FILE=... uv run pytest tests/vault/test_real_vault_integration.py.


디렉터리 구조

app/
  main.py                       FastAPI 앱 조립 + OpenAPI 설정
  core/                         config, exceptions, openapi, api_docs, logging, middleware, security
  api/
    dependencies.py             인증/서비스 DI
    v1/router.py, v1/endpoints/ health, auth, me, api_keys, servers,
                                credentials(SSH 하위호환), resource_credentials(전 유형),
                                my_resources(목록/검색/reveal)
    internal/                   dev 전용 라우터(local/dev 에서만 등록)
  auth/                         verifier(Entra), local_token/local_service, dependencies, context, jwks, password
  api_keys/                     generator, hasher, service, repository, schemas
  credentials/                  service, compensation, validation, schemas, errors
  server_resources/             crud, service(alias 해석/인가), repository, validation, schemas
  vault/                        client(KV v2), factory, token_file, credential_ref, errors
  db/                           base(schema 격리), session, models/{user,api_key,server_resource,...}
  domain/                       enums, errors, resolved
  audit/                        service(감사 기록)
  web/                          router(Jinja2), csrf, dependencies
  templates/  static/{css,js}   Web UI
  scripts/seed_poc_user.py      PoC 사용자 seed
  ssh/  operations/             SSH Runner·운영 API 자리(STEP 10~11, 미구현)
migrations/versions/            Alembic 0001~0006
tests/                          api, api_keys, auth, services, vault, web, skills, db, models
skills/vault-mcp/             전사 공통 Claude Skill(REST 호출, Secret 미출력)
deploy/                         gitops-repo(Kustomize+ArgoCD), k8s/dev(수동 kubectl 대안)
docs/                           설계·운영 문서(아래 인덱스)
Dockerfile  Jenkinsfile         멀티스테이지 이미지 / CI 파이프라인

개발 단계

STEP

내용

상태

1

FastAPI 골격

2

DB 모델·권한·서버 해석(Alembic, schema 격리)

3

Microsoft Entra 인증

4

LOCAL 로그인 + API Key + 사용자별 Vault 경로 모델

5

개발 Vault 설치·단독 검증(NCP)

6

FastAPI ↔ Vault 연동 + Credential 등록

7

Skill 기반 REST API PoC

8

사용자 Web UI(Jinja2)

8.5 / 8.6

개발 K8S 배포 / Jenkins+Harbor+ArgoCD GitOps

8.7

Resource 유형 확장(SERVER/WEBSITE/API)

9

사용자 인증 개선(Device Flow/짧은 Access Token)

예정

10

SSH Runner 등 Credential 활용

미구현

11 / 12 / 13

읽기 전용 운영 API / CLI+Keyring / K8S 배포 정리

미구현

아직 미구현: SSH 실행(Runner), 운영 API(logs/status/disk), CLI/OS Keyring. Entra 실제 App Registration 통합 검증은 조직 환경에서 수행 필요.


배포

Jenkins(CI) → Harbor(registry) → ArgoCD(GitOps). 정본: docs/ci-gitops.md, deploy/gitops-repo/README.md.

flowchart LR
    GIT[소스 push] -->|pollSCM| J[Jenkins]
    J -->|build| IMG[이미지 sha-태그]
    IMG -->|push| H[Harbor]
    J -->|newTag 갱신 commit| D[vault-mcp-deploy repo]
    D -->|watch| A[ArgoCD]
    A -->|PreSync: migration Job| K[K8S vault-mcp ns]
    A -->|sync: Deployment| K
  • 이미지: Dockerfile 멀티스테이지, non-root(uid 10001), uvicorn :8000. Secret 미포함(K8S Secret 주입).

  • Jenkinsfile: Init(short SHA) → Build → Push Harbor → deploy repo 의 newTagsha-<SHA> 로 갱신. Deployment 와 migration Job 이 같은 SHA 로 반영(불일치 방지).

  • GitOps: deploy/gitops-repo/(Kustomize + ArgoCD Application). migration 은 PreSync Hook, seed 는 수동 1회.

  • deploy/k8s/dev/ 는 GitOps 없이 수동 kubectl apply 로 검증하는 대안이다.


기술 스택

영역

스택

언어

Python 3.12+

FastAPI ≥0.115, Uvicorn ≥0.34

검증

Pydantic v2 ≥2.9, pydantic-settings ≥2.6

DB

SQLAlchemy 2.x async, asyncpg ≥0.30, Alembic ≥1.14, PostgreSQL

인증

PyJWT[crypto] ≥2.9, pwdlib[argon2] ≥0.2

Vault/HTTP

httpx ≥0.28 (KV v2 직접 호출)

Web

Jinja2 ≥3.1, python-multipart

개발

pytest + pytest-asyncio, aiosqlite, ruff(line 100, py312), mypy(strict)

패키지

uv(비패키지 애플리케이션 모드)


문서 인덱스


Git 정책: 기본 브랜치 main, 명시적 요청 없이 commit/push 하지 않는다. .env·Token·인증서· Private Key 는 커밋 금지. 프로젝트 원칙과 작업 하네스는 CLAUDE.md.

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    D
    maintenance
    Enterprise-grade authentication solution that provides secure credential management with encryption, multi-protocol authentication (OAuth2, SAML, LDAP), and real-time threat detection for applications.
    8
    1
    AGPL 3.0
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables secure management of agent-scoped secrets in HashiCorp Vault through MCP protocol. Provides per-agent namespacing, multiple authentication methods (API key, JWT, mTLS), and optional encryption/decryption capabilities with built-in rate limiting.
    3
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Encrypted-at-rest credential vault with MCP server for agent credential lookup and management.
    8 npm
    MIT