OpenMetadata について
OpenMetadataのMCPモジュールは、メタデータへのMCPアクセスにOAuth 2.0認証を提供します。OpenMetadataを利用する組織向けで、SSOまたはBasic Authを通じてユーザーの身元と権限を引き継ぎます。
主な機能
- 01PKCE対応の認可コードフロー
- 02SSOとBasic Authに対応
- 03リフレッシュトークンのローテーションと暗号化保存
- 04動的クライアント登録とディスカバリーエンドポイント
- 05データベース駆動の実行時設定
活用シーン
- 01OpenMetadataへのMCPクライアント認証
- 02ツール要求へのOpenMetadataユーザー権限の適用
- 03クラスタインスタンス間でのMCP設定更新
MCP 対応
MCPツールを通じて、リネージ取得、メタデータ検索、エンティティ発見などのOpenMetadata機能をクライアントに提供します。OAuthでユーザーを認証し、OpenMetadataの認可ポリシーでツールへのアクセスを制御します。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://{openmetadata_host}/mcpclaude mcp add --transport http open-metadata-openmetadata https://{openmetadata_host}/mcp{"mcpServers":{"open-metadata-openmetadata":{"type":"http","url":"https://{openmetadata_host}/mcp"}}}Cursor で開く{"servers":{"open-metadata-openmetadata":{"type":"http","url":"https://{openmetadata_host}/mcp"}}}VS Code で開く{"mcpServers":{"open-metadata-openmetadata":{"type":"http","url":"https://{openmetadata_host}/mcp"}}}{"mcpServers":{"open-metadata-openmetadata":{"serverUrl":"https://{openmetadata_host}/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
OpenMetadata MCP OAuth 実装
OpenMetadata との Model Context Protocol(MCP)連携に対応する OAuth 2.0 認証サーバーです。Claude Desktop やその他の MCP クライアントから、メタデータに安全にアクセスできます。
概要
このモジュールは、MCP クライアント向けに PKCE を使用する OAuth 2.0 認可コードフローを完全に実装し、OpenMetadata の既存の SSO プロバイダー(Google、Okta、Azure AD、Auth0、AWS Cognito、Custom OIDC、LDAP、SAML)または Basic Auth によるユーザー認証を可能にします。この実装により、MCP ツールを通じて OpenMetadata のメタデータ管理機能に、安全かつ標準に準拠してアクセスできます。
重要:これは MCP クライアント向けのユーザー SSO 認証であり、データソース向けのコネクタベースの OAuth ではありません。ユーザーは OpenMetadata の認証情報(SSO またはユーザー名/パスワード)で認証し、MCP ツールはそのユーザーの権限で実行されます。
機能
OAuth 2.0 の実装
- PKCE を使用する認可コードフロー - RFC 7636 に準拠し、認可コードの傍受攻撃を防止します
- リフレッシュトークンのローテーション - セキュリティを強化するため、トークンを自動更新し、ローテーションします
- トークンの暗号化 - 保存時のトークンを Fernet 対称暗号化で保護します
- CSRF 対策 - OAuth フロー全体で state パラメーターを検証します
- セッション固定化の防止 - 認証成功後にセッションを再生成します
認証方式
- SSO 連携 - pac4j を通じて、Google、Okta、Azure AD、Auth0、AWS Cognito、Custom OIDC、LDAP、SAML プロバイダーと OAuth 2.0 連携します
- Basic Auth - OpenMetadata の認証情報を使用して、ユーザー名/パスワードで認証します
- ユーザーのなりすまし - MCP ツールで、なりすましユーザーのコンテキストをサポートします
- 自動検出 - OpenMetadata の設定に応じて、SSO または Basic Auth を自動的に選択します
セキュリティ機能
- PKCE 検証 - SHA-256 のコードチャレンジ/ベリファイアを検証します
- トークン有効期限の管理 - アクセストークンの有効期間は 10 分です。リフレッシュトークンはサインインから 30 日間有効で、ローテーションしても有効期間は延長されません
- レート制限 - エンドポイントを保護するため、登録は IP ごとに 1 時間あたり 10 回、トークンは IP ごとに 1 分あたり 30 回に制限します
- スレッドセーフな並行処理 - リクエストを分離するために ThreadLocal ストレージを使用します
- 監査ログ - OAuth 操作は SLF4J を通じて記録されます(将来の利用に備えて oauth_audit_log テーブルを使用できます)
データベース駆動の設定
- 実行時設定 - REST API を通じて、サーバーを再起動せずに MCP 設定を更新できます
- クラスター同期 - データベースのポーリング(10 秒間隔)により、すべてのクラスターインスタンスで一貫した設定を維持します
- 設定変更リスナー - 設定が変更されると、CORS オリジンを動的に更新します
- 永続ストレージ - 設定変更はサーバーの再起動後も保持されます(データベース優先、YAML にフォールバック)
- HTTP タイムアウト設定 - SSO プロバイダーのメタデータ取得に使用する接続タイムアウトと読み取りタイムアウトを設定できます
MCP 連携
- Claude Desktop のサポート - Claude Desktop MCP クライアントと初めから連携できます
- OAuth ディスカバリーエンドポイント - クライアント設定用の標準 .well-known エンドポイント
- 動的クライアント登録 - RFC 7591 に準拠したクライアント登録
- JWKS のサポート - JWT 検証用の公開鍵エンドポイント
アーキテクチャ
コアコンポーネント
UserSSOOAuthProvider
- 認可コードフローを実装する主要な OAuth プロバイダー
- Google SSO と Basic Auth の両方のフローを処理
- トークンの生成、検証、更新ロジック
- タイミングセーフな比較による PKCE チャレンジ/ベリファイアの検証
OAuthHttpStatelessServerTransportProvider
- OAuth エンドポイント用の HTTP トランスポート層
- 認可、トークン、ディスカバリーの各リクエストをルーティング
- サーブレットベースのステートレスなリクエスト処理
- プロバイダーを考慮した OAuth スコープ設定
SecurityConfigurationManager
- 実行時のセキュリティ設定(認証、認可、MCP 設定)を管理するシングルトンマネージャー
- データベース優先の設定読み込みと YAML フォールバック
- リアクティブな更新を実現する設定変更リスナーパターン
- インスタンス間の変更を検出するクラスター対応のポーリング機構(間隔は 10 秒)
- 設定更新に失敗した場合のロールバック機構
- 一貫性のある設定読み取りを実現する、スレッドセーフな同期ゲッター
OAuth Repositories
- OAuthClientRepository - クライアントの管理と検証
- OAuthAuthorizationCodeRepository - 認可コードの CRUD 操作
- OAuthAccessTokenRepository - アクセストークンのライフサイクル管理
- OAuthRefreshTokenRepository - リフレッシュトークンのローテーションとクリーンアップ
- McpPendingAuthRequestRepository - データベースに基づく OAuth 状態の永続化
- OAuthAuditLogRepository - 包括的な監査証跡
データベーススキーマ
監査ログを含む 5 つの主要な OAuth テーブル:
- oauth_clients - RFC 7591 を介して動的に登録される MCP クライアント
- oauth_authorization_codes - PKCE チャレンジを含む、有効期間の短いコード(TTL は 10 分)
- oauth_access_tokens - 現在は書き込まれません。アクセストークンは 10 分間有効な JWT としてクライアントに返されます
- oauth_refresh_tokens - 自動ローテーションによって有効期間が延長されるリフレッシュトークン(サインインから 30 日間)
- mcp_pending_auth_requests - クロスドメインリダイレクト用の OAuth 状態パラメーター(TTL は 10 分)
- oauth_audit_log - すべての OAuth 操作の包括的な監査証跡
クリーンアップジョブ:OAuthTokenCleanupJob は 10 分ごとに実行され、期限切れのトークンと保留中のリクエストを削除します。
OAuth フロー
PKCE を使用する認可コードフロー
┌─────────────┐ ┌──────────────┐
│ Claude │ │ OpenMetadata │
│ Desktop │ │ MCP │
│ (MCP Client)│ │ Server │
└──────┬──────┘ └──────┬───────┘
│ │
│ 1. Generate PKCE code_verifier (random 43-128 chars) │
│ Calculate code_challenge = BASE64URL(SHA256(verifier)) │
│ │
│ 2. GET /api/v1/mcp/authorize │
│ ?client_id={registered_client_id} │
│ &redirect_uri=http://127.0.0.1:XXXXX/callback │
│ &code_challenge={challenge} │
│ &code_challenge_method=S256 │
│ &state={client_state} │
│─────────────────────────────────────────────────────────────────>│
│ │
│ 3. Store OAuth state in database: │
│ - client_id, redirect_uri │
│ - code_challenge, method │
│ - state, scopes, TTL (10 min) │
│ Generate authRequestId │
│ │
│ 4. 302 Redirect to Auth Page │
│ /api/v1/mcp/authorize?state=mcp:{authRequestId} │
│<─────────────────────────────────────────────────────────────────│
│ │
│ 5. User authenticates via: │
│ ┌──────────────────────────────────────┐ │
│ │ Option A: SSO Provider │ │
│ │ - Redirect to SSO provider: │ │
│ │ • Google OAuth │ │
│ │ • Okta │ │
│ │ • Azure AD │ │
│ │ • Auth0 │ │
│ │ • AWS Cognito │ │
│ │ • Custom OIDC │ │
│ │ • LDAP │ │
│ │ • SAML │ │
│ │ - User grants consent │ │
│ │ - SSO callback with ID token (pac4j)│ │
│ └──────────────────────────────────────┘ │
│ OR │
│ ┌─────────────────────────────┐ │
│ │ Option B: Basic Auth │ │
│ │ - Username/password form │ │
│ │ - Validate with │ │
│ │ OpenMetadata │ │
│ └─────────────────────────────┘ │
│ │
│ 6. Lookup OAuth state from DB using │
│ authRequestId from state parameter │
│ Generate authorization code │
│ Store code + code_challenge in DB │
│ │
│ 7. 302 Redirect with authorization code │
│ {redirect_uri}?code={auth_code}&state={client_state} │
│<─────────────────────────────────────────────────────────────────│
│ │
│ 8. POST /api/v1/mcp/token │
│ grant_type=authorization_code │
│ code={auth_code} │
│ code_verifier={verifier} │
│ client_id={registered_client_id} │
│ redirect_uri=http://127.0.0.1:XXXXX/callback │
│─────────────────────────────────────────────────────────────────>│
│ │
│ 9. PKCE Validation: │
│ Lookup code_challenge from DB │
│ Verify: BASE64URL(SHA256(verifier)) │
│ == code_challenge │
│ Delete authorization code (single-use)│
│ │
│ 10. 200 OK │
│ { │
│ "access_token": "eyJhbGc...", // JWT, 10 min TTL │
│ "refresh_token": "fernet_encrypted", // 30 days TTL │
│ "token_type": "Bearer", │
│ "expires_in": 600 │
│ } │
│<─────────────────────────────────────────────────────────────────│
│ │
│ 11. Use MCP Tools │
│ Authorization: Bearer eyJhbGc... │
│─────────────────────────────────────────────────────────────────>│
│ MCP Tool Execution (lineage, search, discovery, etc.) │
│<─────────────────────────────────────────────────────────────────│
│ │
│ 12. Token Expiry - Refresh Flow │
│ POST /api/v1/mcp/token │
│ grant_type=refresh_token │
│ refresh_token={encrypted_token} │
│─────────────────────────────────────────────────────────────────>│
│ │
│ 13. Refresh Token Rotation: │
│ - Decrypt and validate refresh token │
│ - Delete old refresh token │
│ - Generate new access + refresh tokens│
│ │
│ 14. 200 OK │
│ { │
│ "access_token": "eyJhbGc...", // New JWT │
│ "refresh_token": "new_encrypted", // New rotated token │
│ "token_type": "Bearer", │
│ "expires_in": 600 │
│ } │
│<─────────────────────────────────────────────────────────────────│
│ │
主なセキュリティ機構
PKCE(Proof Key for Code Exchange)
- クライアントがランダムな code_verifier(43~128 文字)を生成します
- code_challenge = BASE64URL(SHA256(code_verifier)) を計算します
- サーバーは code_challenge を認可コードとともに保存します
- クライアントはトークン交換時に code_verifier を送信し、所持していることを証明します
- サーバーは BASE64URL(SHA256(code_verifier)) == 保存済みの code_challenge であることを検証します
- 認可コードの傍受攻撃を防ぎます
データベースに基づく状態の永続化
- OAuth 状態パラメーターは HTTP セッションではなく、データベースに保存されます
- クロスドメインリダイレクト(例:Google OAuth コールバック)後も状態が保持されます
- 各リクエストには、状態パラメーターに埋め込まれた一意の authRequestId が割り当てられます
- 10 分の TTL により、古い状態を悪用する攻撃を防ぎます
- 1 回限りの使用です。コールバック成功後に削除されます
トークンのセキュリティ
- アクセストークン:RSA-256 で署名された JWT。JWKS エンドポイントを介して検証されます
- リフレッシュトークン:保存時に Fernet の共通鍵暗号化を使用します
- 認可コード:1 回限りの使用、有効期限は 10 分、PKCE チャレンジにひも付けられます
- リフレッシュトークンのローテーション:新しいトークンが発行されると、古いトークンは無効になります
設定
MCP の設定(データベース駆動)
MCP 固有の設定は、データベースに永続化される REST API を通じて管理します。
# Get current MCP configuration
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8585/api/v1/system/mcp/config
# Update MCP configuration (no restart required)
curl -X PUT -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"baseUrl": "https://metadata.example.com",
"allowedOrigins": ["https://app.example.com"],
"connectTimeout": 30000,
"readTimeout": 60000,
"enabled": true
}' \
http://localhost:8585/api/v1/system/mcp/config
設定プロパティ:
baseUrl- OAuth 発行者 URL(メタデータエンドポイントで使用)allowedOrigins- OAuth エンドポイントの CORS 許可リスト(*ではなく、特定のオリジンを指定してください)connectTimeout- SSO プロバイダーのメタデータ取得に使用する HTTP 接続タイムアウト(ミリ秒)readTimeout- SSO プロバイダーのメタデータ取得に使用する HTTP 読み取りタイムアウト(ミリ秒)enabled- MCP サーバーの有効化/無効化
主な機能:
- 変更は、すべてのクラスターインスタンスに直ちに反映されます(ポーリング間隔は 10 秒です)
- 設定はサーバーの再起動後も保持されます(データベースを優先し、YAML をフォールバックとして使用)
- リスナーパターンにより、再起動せずに CORS オリジンを動的に更新します
OAuth サーバーの設定
OAuth サーバーは openmetadata.yaml で設定します。
- JWT の設定 - トークン署名用の RSA キーペア、JWKS エンドポイント URL
- トークンの有効期限 - アクセストークン(10 分)とリフレッシュトークン(サインインから 30 日)の有効期間はコード内で固定されており、ここでは設定しません
- レート制限 - 登録(IP ごとに 1 時間あたり 10 回)およびトークンエンドポイント(IP ごとに 1 分あたり 30 回)のレート制限
- SSO プロバイダー - SSO 統合用の Google、Okta、Azure AD などの OAuth クライアント ID とシークレット
- コールバック URL - OAuth クライアントで許可されるリダイレクト URI
クライアントの登録
MCP クライアントは、POST /api/v1/mcp/register を使用した**動的クライアント登録(RFC 7591)**を利用します。
- client_name - 人が読めるクライアント名
- redirect_uris - OAuth リダイレクトで許可されるコールバック URL
- scopes - 要求する OAuth スコープ(openid、profile、email、offline_access)
- grant_types - サポートするグラントタイプ(authorization_code、refresh_token)
登録エンドポイントは、OAuth フロー用の client_id と、任意で client_secret を返します。
MCP ツールの統合
すべての MCP ツールは、OAuth フローで取得した Bearer トークンを使用して認証します。
- GetLineageTool - 認可チェックを行いながらエンティティのリネージを取得します
- SearchTool - ユーザー権限に基づいてメタデータを検索します
- DiscoveryTool - アクセス制御を適用しながらエンティティを検出します
権限モデル: ツールの権限は、JWT から取得したユーザーの ID を使用して、OpenMetadata の Authorizer によって適用されます。これにより、MCP ユーザーは OpenMetadata の UI を使用する場合と同じアクセス権を持ち、すべてのポリシー、ロール、所有権ルールが尊重されます。OAuth はユーザーを認証し、Authorizer はユーザーがアクセスできる対象を適用します。
トランスポートプロバイダーは、すべてのリクエストで JWT を抽出して検証し、後続の MCP ツール実行に向けてセキュリティコンテキストを設定します。
最近の改善
セキュリティと信頼性の修正
スレッドセーフと並行処理
- 同期化されたゲッターを使用して、設定の読み取りにおける競合状態を修正
- メモリーリークを防ぐため、外側の finally ブロックに ThreadLocal のクリーンアップを実装
- 設定の更新に失敗した場合のロールバック機構を追加
HTTP クライアントの設定
- JVM 全体に適用されるシステムプロパティを、pac4j 固有の HTTP タイムアウトに置き換え
- SSO プロバイダーのメタデータ取得に使用する接続タイムアウトと読み取りタイムアウトを設定可能に
- タイムアウトの変更が他の HTTP クライアントに影響しないように対応
セッションのセキュリティ
- セッションの再生成後に null チェックを追加し、無効化/再作成へのフォールバックに対応
- 競合状態を防ぐため、pac4j クライアントのコールバック URL の変更を同期化
- 適切なセッション処理により CSRF 保護を改善
設定管理
- データベースを優先して読み込むことで、設定が再起動後も保持されるように対応
- クラスター内のインスタンス間で設定の一貫性を保つため、10 秒間隔でポーリング
- 設定変更リスナーにより、再起動せずに CORS を動的に更新
- MCP 設定 API の URL 検証(無効なプロトコルや部分的なワイルドカードを防止)
入力検証
- baseUrl のプロトコルを検証(HTTP/HTTPS のみ)
- 部分的なワイルドカードオリジン(例:
https://*.example.com)を拒否 - 開発環境では完全一致のワイルドカード(
*)を許可
単体テスト
SecurityConfigurationManagerTest(9 件のテスト)
- シングルトンパターンの検証
- リスナーの登録と削除
- スレッドセーフな設定アクセス(10 スレッド × 100 回の反復)
- 競合状態を防ぐ同期ゲッター(50 個の並行スレッド)
- ロールバック機構の検証
- 設定ゲッターの動作
MCPConfigurationIntegrationTest(9 件のテスト、保留中)
- データベース優先の読み込み検証
- API 経由での設定更新
- キャッシュ再読み込み後の設定の保持
- ポーリングによる設定変更の検出
- 入力検証(無効なプロトコル、ワイルドカードのオリジン)
- 設定再読み込み時のリスナーへの通知
- 複数回の連続更新
テスト
OAuth フローのテスト
UserSSOOAuthProviderIntegrationTest に 15 件の包括的な統合テストがあります。
- 認可エンドポイントの検証(client_id、redirect_uri、PKCE パラメーター)
- PKCE 検証を伴うトークン交換
- リフレッシュトークンのローテーション
- 無効な PKCE challenge/verifier の拒否
- 期限切れの認可コードの処理
- 無効な client_id と redirect_uri の検証
- パラメーター不足時のエラー処理
セキュリティテスト
- 複数のテストケースでの PKCE challenge/verifier の検証
- トークンの有効期限とリフレッシュフローの検証
- 認可コードの使い捨ての徹底
- CSRF state パラメーターの検証
- レート制限の動作検証
SSO 統合テスト
モック ID プロバイダー(Google、Okta、Azure AD など)と pac4j を使用して、SSO プロバイダーとの統合をテストします。UserSSOOAuthProvider は、OpenMetadata の認証設定から構成済みの SSO プロバイダーを自動検出します。
デプロイ
データベースのマイグレーション
bootstrap/sql/migrations/native/1.12.0/ にあるスキーママイグレーション:
- mysql/schemaChanges.sql - OAuth テーブルの作成(oauth_clients、oauth_authorization_codes、oauth_access_tokens、oauth_refresh_tokens、mcp_pending_auth_requests、oauth_audit_log)
- postgres/schemaChanges.sql - OAuth テーブルの作成(PostgreSQL 相当)
サーバーの初期化
OAuth コンポーネントは McpServer で初期化されます。
- JwtFilter とオーソライザーのセットアップ
- OAuth リポジトリーのインスタンス化
- SSO 設定を使用した UserSSOOAuthProvider の初期化
- OAuthHttpStatelessServerTransportProvider を /mcp/* に登録
- SSO コールバックサーブレットと Basic Auth ログインサーブレットの登録
- OAuthTokenCleanupJob をスケジュール(10 分間隔)
環境変数
SSO プロバイダーの設定(プロバイダーによって異なります):
- OIDC_CLIENT_ID - SSO プロバイダー(Google、Okta、Azure など)の OAuth クライアント ID
- OIDC_CLIENT_SECRET - SSO プロバイダーの OAuth クライアントシークレット
- OIDC_TYPE - SSO プロバイダーの種類(google、okta、azure、auth0、aws-cognito、custom-oidc)
- OIDC_DISCOVERY_URI - OIDC 検出エンドポイントの URL
JWT トークンの設定:
- JWT_ISSUER - トークン検証用の JWT issuer クレーム
- JWT_KEY_ID - トークン署名用の RSA キーペア ID
MCP の設定(任意。API 経由でも設定できます):
- MCP_BASE_URL - OAuth issuer のベース URL
- MCP_ALLOWED_ORIGINS - カンマ区切りの CORS オリジン
セキュリティに関する考慮事項
- パブリッククライアントのセキュリティ - すべての認可コードフローで PKCE を必須とします
- リダイレクト URI の検証 - HTTP リダイレクト URI は RFC 8252 に従ってループバックアドレスに制限されます。HTTPS URI は登録済みのクライアント URI と照合して検証されます
- トークンの保存 - リフレッシュトークンは Fernet を使用して保存時に暗号化されます
- セッション管理 - ステートレス設計で、データベースを使用して状態を永続化します
- 監査証跡 - コンプライアンスとフォレンジックのため、すべての OAuth 操作をログに記録します
- レート制限 - 登録エンドポイント(IP あたり 10 回/時間)とトークンエンドポイント(IP あたり 30 回/分)にレート制限を適用します
- CORS セキュリティ - MCP 設定を利用できない場合は、すべての CORS を拒否します(localhost への許可的なフォールバックはありません)
- 単回使用コード - 認可コードは交換後に削除されます
- トークンローテーション - 露出を抑えるため、リフレッシュのたびにリフレッシュトークンをローテーションします
- タイミングセーフな比較 - CSRF と PKCE の検証では、タイミング攻撃を防ぐために MessageDigest.isEqual() を使用します
- プロバイダーに応じたスコープ - SSO プロバイダー(Google、Okta、Azure など)に基づいて OAuth スコープを自動的に調整します
- JWK キャッシュ - キーローテーションに迅速に対応できるよう、6 時間の TTL とキャッシュミス時の再試行を設定します
ライセンス
Apache License 2.0
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。