Chuyển đến nội dung chính

レッスン 9: クライアント ポリシーと高度なクライアント構成

クライアント ポリシー アーキテクチャ (プロファイル、条件、エグゼキュータ)、FAPI 2.0 セキュリティ プロファイル、クライアント シークレット ローテーション、サービス アカウント、対象者サポート、機密クライアント資格情報 (クライアント ID/シークレット、署名付き JWT、X.509)、標準トークン交換、JWT 認可付与 (RFC 7523)、および MCP サーバーの構成。

🔒 DevSecOps — レッスン 9 レッスン 9: クライアント ポリシーとアドバンスト クライアント 構成

基本から上級までの Keycloak

パート 2: SSO プロトコル - OpenID Connect と SAML

xdev.asia

1. クライアントポリシー

クライアント ポリシーは有効なフレームワークですセキュリティ要件を強制するクライアントに自動的にインストールされます。各クライアントの設定を手動で確認する代わりに、Keycloak が自動的に検証して適用するポリシーを定義します。

1.1 クライアント ポリシーが必要なのはなぜですか?

  • 一貫性: すべてのクライアントが同じセキュリティ標準に準拠していることを確認します。

  • オートメーション: 準拠していないリクエストを自動的に拒否します

  • コンプライアンス: 業界標準の強制 (FAPI、PSD2、オープン バンキング)

  • ガバナンス: クライアントの登録と構成を制御します

1.2 アーキテクチャ: プロファイル、条件、エグゼキュータ

クライアント ポリシーには、次の 3 つの主要コンポーネントが含まれます。

┌─────────────────────────────────────────────────┐
│                  Client Policy                   │
│                                                   │
│  ┌──────────────┐     ┌──────────────────────┐   │
│  │  Conditions   │     │      Profiles        │   │
│  │ (Khi nào?)    │────>│   (Áp dụng gì?)      │   │
│  │               │     │                      │   │
│  │ • Client Role │     │  ┌────────────────┐  │   │
│  │ • Client Scope│     │  │   Executors    │  │   │
│  │ • Any Client  │     │  │ (Làm gì?)      │  │   │
│  │ • Client      │     │  │                │  │   │
│  │   Access Type │     │  │ • PKCE Enforcer│  │   │
│  │ • Client      │     │  │ • Secure Alg   │  │   │
│  │   Update      │     │  │ • DPoP Verify  │  │   │
│  │   Source      │     │  │ • ...          │  │   │
│  └──────────────┘     │  └────────────────┘  │   │
│                        └──────────────────────┘   │
└─────────────────────────────────────────────────┘
材料説明する例えば
プロフィールエグゼキュータのセット — 「何を強制するか」を定義しますfapi-2-セキュリティプロファイル
状態条件によって、どのクライアントが影響を受けるかが決まります - 「誰に対して強制するか」クライアントには役割があるファピクライアント
執行者特定の施行ロジック - 「施行方法」PKCE S256 が必要です

1.3 クライアントプロファイルの作成

  1. 入力レルム設定 → クライアントポリシー→タブプロフィール

  2. クリッククライアントプロファイルの作成

  3. 入力名前そして説明

  4. クリック保存→プロフィールを開く→クリック実行者の追加

1.4 利用可能なエグゼキュータ

執行者説明するパラメータ
セキュアクライアント認証システム特定の認証方法が必要許可された認証子: client-secret、client-jwt、client-x509
PKCE 執行者PKCEが必要ですオーグメント: ON (クライアントが不足している場合は自動的に追加)
安全な署名アルゴリズム安全なアルゴリズムのみが許可されますデフォルト: RS256、ES256、PS256
署名付き JWT の安全な署名アルゴリズムクライアント JWT 認証のアルゴリズムPS256、ES256(RS256は不可)
鍵の所有者執行者必要なトークン バインディング (mTLS または DPoP)自動構成: オン
DPoP 証明検証者トークンリクエストで DPoP 証明を要求する
機密クライアント執行者機密クライアントのみが許可されます
同意が必要です必須の同意画面
フルスコープ無効フルスコープマッピングをオフにする
暗黙的な許可を拒否する暗黙的なフローは許可されません
リソース所有者のパスワード認証情報の付与を拒否するROPC は許可されません
セキュア リダイレクト URI エンフォーサリダイレクト URI を検証するHTTPS が必要、ワイルドカードなし
安全なリクエストオブジェクト必須の JAR (JWT で保護された承認リクエスト)
安全な応答タイプ安全な応答タイプのみが許可されます許可: コード (トークンなし、id_token)
セキュアセッションエンフォーサセッション設定を強制する

1.5 利用可能な条件

状態説明する例えば
あらゆるクライアントすべてのクライアントに適用されますグローバルセキュリティポリシー
クライアントアクセスタイプクライアントのタイプに基づく (公開/機密)すべてのパブリック クライアントに PKCE を適用する
クライアントの役割クライアントには特定の役割がありますクライアントには役割があるfapi準拠
クライアントスコープクライアントは特定のスコープを使用しますクライアントリクエストのスコープ支払い
クライアント更新ソースグループソースの作成/更新クライアントに基づく動的登録によって作成されたクライアント
クライアント更新コンテキストクライアント更新時のコンテキスト認可リクエスト、トークンリクエスト

1.6 クライアントポリシーの作成

  1. 入力レルム設定 → クライアントポリシー→タブポリシー

  2. クリッククライアントポリシーの作成

  3. 入力名前そして説明

  4. もっと条件(影響を受けるクライアントを特定する)

  5. もっとクライアントプロファイル(どのプロファイルが適用されるか)

# Ví dụ: Tạo policy enforce PKCE cho tất cả public clients
Profile: pkce-required-profile
  Executors:
    - PKCE Enforcer
        Augment: ON (auto-add PKCE nếu client không gửi)

Policy: enforce-pkce-for-public
  Conditions:
    - Client Access Type: public
  Profiles:
    - pkce-required-profile

1.7 実践的なポリシーの例

ポリシー 1: すべてのクライアントのベースライン セキュリティ

Profile: baseline-security
  Executors:
    - Reject Implicit Grant
    - Reject Resource Owner Password Credentials Grant
    - PKCE Enforcer (S256)
    - Secure Signing Algorithm (RS256, ES256, PS256)

Policy: baseline-all-clients Conditions: - Any Client Profiles: - baseline-security

ポリシー 2: 金融 API の高セキュリティ

Profile: financial-api-profile
  Executors:
    - Confidential Client Enforcer
    - Holder-of-Key Enforcer (mTLS hoặc DPoP)
    - Secure Client Authenticator (private_key_jwt, client-x509)
    - Secure Request Object Required
    - Consent Required
    - Secure Redirect URIs Enforcer (HTTPS only)

Policy: financial-api-policy Conditions: - Client Scopes: fapi-scope Profiles: - financial-api-profile

2. FAPI 2.0 セキュリティ プロファイル

FAPI (金融グレード API) は、OpenID Foundation によって開発された一連の高度なセキュリティ標準であり、以下で広く使用されています。オープンバンキング, 決済サービス指令 2 (PSD2)、金融アプリケーションなど。

2.1 FAPI 2.0 ベースライン プロファイル

Keycloak は、FAPI 2.0 の組み込みプロファイルを提供します。

リクエスト説明する
認可コードフローのみ暗黙的および ROPC は許可されません
PKCE (S256)すべてのクライアントに必須
機密クライアントクライアント認証が必要です
安全な署名アルゴリズムPS256、ES256 (RS256なし)
送信者制限付きトークンDPoP または mTLS トークン バインディング
リダイレクト URI の完全一致ワイルドカードなし
HTTPSが必要ですすべてのエンドポイントに対して

2.2 FAPI 2.0 高度なプロファイル (メッセージ署名)

ベースラインに加えて、アドバンスト プロファイルでは以下が追加されます。

  • PAR (プッシュされた認可リクエスト)— RFC 9126: リダイレクトする前にバックチャネル経由で認可リクエストを送信する

  • JAR (JWT で保護された承認リクエスト)— RFC 9101: JWT で署名された認証パラメーター

  • JARM (JWT で保護された認証応答モード): JWT で署名された承認応答

# PAR request — gửi authorization params qua backchannel
POST /realms/my-realm/protocol/openid-connect/ext/par/request
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)

response_type=code&
client_id=my-fapi-client&
redirect_uri=https://myapp.com/callback&
scope=openid payments&
state=random-state&
code_challenge=code_challenge_value&
code_challenge_method=S256

# Response
{
  "request_uri": "urn:ietf:params:oauth:request_uri:abc123",
  "expires_in": 60
}

# Authorization request chỉ chứa request_uri
GET /realms/my-realm/protocol/openid-connect/auth?
  client_id=my-fapi-client&
  request_uri=urn:ietf:params:oauth:request_uri:abc123

2.3 KeycloakでFAPI 2.0を有効にする

  1. 入力レルム設定 → クライアントポリシー→タブプロフィール

  2. キークロークが利用可能ですグローバルプロファイル:

    • fapi-2-セキュリティプロファイル
    • fapi-2-メッセージ署名プロファイル
  3. 対応するプロファイルを使用してポリシーを作成する

  4. コンプライアンスが必要なクライアントを選択するための条件の割り当て

# Ví dụ: Enforce FAPI 2.0 cho clients có scope "fapi"
Policy: fapi-2-enforcement
  Conditions:
    - Client Scopes: fapi
  Profiles:
    - fapi-2-security-profile     # Built-in global profile
    - fapi-2-message-signing-profile  # Thêm nếu cần message signing

3. クライアント シークレットのローテーション

クライアント シークレットのローテーションにより、クライアント シークレットを変更できますダウンタイムを引き起こさない— 古いシークレットは移行期間中もアクティブのままです。

3.1 クライアント シークレット ローテーションの構成

使用クライアントポリシー遺言執行者付きシークレットローテーション:

# Tạo Profile với Secret Rotation executor
Profile: secret-rotation-profile
  Executors:
    - Secret Rotation
        Secret Expiration: 2592000        # 30 ngày (tính bằng giây)
        Rotated Secret Expiration: 604800  # Grace period: 7 ngày
        Remain Expiration: 604800          # Thời gian cảnh báo trước khi hết hạn

仕組み:

Timeline:
┌──────────────────────────────────────────────────────────┐
│ Ngày 0         Ngày 23        Ngày 30          Ngày 37  │
│   │               │              │                │     │
│   ▼               ▼              ▼                ▼     │
│ Secret A      Cảnh báo      Secret B           Secret A │
│ created       sắp hết hạn   created + active   hết hạn  │
│                              Secret A vẫn       hoàn toàn│
│                              hoạt động                   │
│                              (grace period)              │
└──────────────────────────────────────────────────────────┘

Khoảng grace period (Ngày 30-37):

  • Secret B: active (primary)
  • Secret A: vẫn valid (rotated secret, grace) → Ứng dụng có 7 ngày để chuyển sang Secret B

3.2 シークレットローテーションの導入

# 1. Lấy current secret
CURRENT_SECRET=$(curl -s -X GET \
  "$KC_URL/admin/realms/my-realm/clients/$CLIENT_UUID/client-secret" \
  -H "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.value')

2. Rotate secret — regenerate new secret

curl -s -X POST
"$KC_URL/admin/realms/my-realm/clients/$CLIENT_UUID/client-secret"
-H "Authorization: Bearer $ADMIN_TOKEN"

3. Lấy new secret

NEW_SECRET=$(curl -s -X GET
"$KC_URL/admin/realms/my-realm/clients/$CLIENT_UUID/client-secret"
-H "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.value')

4. Update ứng dụng với new secret

Trong grace period, cả current và new secret đều hoạt động

4. サービスアカウント

オンにした場合サービスアカウントの役割機密クライアントの場合、Keycloak は 1 つを作成しますサービスアカウントユーザー特にそのクライアントのために。このユーザーは、マシン間の操作においてクライアントを表します。

4.1 サービスアカウントのユーザー

# Service account user naming convention
Username: service-account-{client-id}
# Ví dụ: service-account-my-backend-service

Service account user có các đặc điểm:

- Không có password (authenticate bằng client credentials)

- Có thể gán realm roles và client roles

- Có thể thêm user attributes

- Xuất hiện trong Users list (với filter service accounts)

4.2 サービスアカウントへの役割の割り当て

  1. クライアント→タブを開くサービスアカウントの役割

  2. クリック役割の割り当て

  3. レルムの役割を選択するか、クライアントでフィルタリングして、クライアントの役割を割り当てます

# Admin CLI: Gán roles
# Gán realm role
bin/kcadm.sh add-roles -r my-realm \
  --uusername service-account-my-backend-service \
  --rolename realm-admin

# Gán client role từ client khác
bin/kcadm.sh add-roles -r my-realm \
  --uusername service-account-my-backend-service \
  --cclientid realm-management \
  --rolename manage-users

# REST API: Gán role
# Lấy service account user
SA_USER=$(curl -s -X GET \
  "$KC_URL/admin/realms/my-realm/clients/$CLIENT_UUID/service-account-user" \
  -H "Authorization: Bearer $ADMIN_TOKEN")

SA_USER_ID=$(echo $SA_USER | jq -r '.id')

# Gán realm role
ROLE_ID=$(curl -s -X GET \
  "$KC_URL/admin/realms/my-realm/roles/admin" \
  -H "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.id')

curl -s -X POST \
  "$KC_URL/admin/realms/my-realm/users/$SA_USER_ID/role-mappings/realm" \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '[{"id":"'$ROLE_ID'","name":"admin"}]'

4.3 サービスアカウントのベストプラクティス

  • 最低限の特権: 各サービスに必要な役割のみを割り当てます

  • 個別のクライアント: マイクロサービスごとに個別のクライアントを作成し、共有しないでください。

  • 監査: イベント ログを有効にしてサービス アカウントのアクティビティを追跡します

  • トークンの寿命が短い: サービス アカウントのアクセス トークンは短くする必要があります (1 ~ 5 分)。

  • 認証情報のローテーション: クライアント シークレット ローテーションまたは証明書ベースの認証を使用します。

5. 視聴者サポート

観客 (オード請求)決定どのリソースサーバーですか?アクセストークンは使用することを目的としています。これは、トークンが望ましくないサービスで使用されるのを防ぐための重要なセキュリティ メカニズムです。

5.1 問題点

# Mặc định, access token chỉ có aud = client-id đã request
{
  "aud": "my-frontend-app",     // ← chỉ có client đã request
  "azp": "my-frontend-app"
}

Resource Server (my-api-service) verify token:

→ aud không chứa "my-api-service"

→ REJECT! (nếu resource server validate audience)

5.2 ソリューション: オーディエンス プロトコル マッパー

もっとオーディエンスマッパークライアントまたはクライアント スコープに移動してリソース サーバーを追加しますオード:

# Cách 1: Thêm Audience Mapper trực tiếp vào client
Client: my-frontend-app → Client scopes → Dedicated scope → Add mapper
  Mapper Type: Audience
  Name: api-audience
  Included Client Audience: my-api-service
  Included Custom Audience: (trống)
  Add to ID token: OFF
  Add to access token: ON

# Cách 2: Tạo Client Scope chứa Audience Mapper
Client Scope: api-access
  Mapper: Audience → my-api-service
  Gán scope cho frontend client

# Kết quả trong access token:
{
  "aud": ["my-frontend-app", "my-api-service"],
  "azp": "my-frontend-app"
}

5.3 オーディエンス解決マッパー

Keycloakには組み込み観客の決意マッパー (デフォルトのスコープ内)役割。役割) — 自動的に追加オードユーザーがクライアントの役割を持っているクライアントの場合:

# Nếu user có role "app-admin" của client "my-api-service"
# → Audience Resolve tự động thêm "my-api-service" vào aud
{
  "aud": ["my-frontend-app", "my-api-service"],
  "resource_access": {
    "my-api-service": {
      "roles": ["app-admin"]
    }
  }
}

6. 機密クライアント認証情報

6.1 クライアント ID とシークレット

最も単純な方法 — クライアントはリクエストで ID とシークレットを送信します。

# Cách 1: Form parameter
POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=my-client&
client_secret=my-secret

# Cách 2: HTTP Basic Authentication
POST /token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic base64(client_id:client_secret)

grant_type=client_credentials

6.2 署名付き JWT (private_key_jwt)

クライアントは秘密鍵を使用して JWT を作成および署名し、Keycloak に送信します。 Keycloakは登録された公開鍵/証明書を使用して検証します。

Keycloakでの設定:

  1. クライアント → タブ資格 → クライアント認証子: 署名付き JWT

  2. クライアント証明書または JWKS URL をアップロードする

# Tạo key pair cho client
openssl genrsa -out client-private.pem 2048
openssl req -new -x509 -key client-private.pem -out client-cert.pem -days 365

# Upload client-cert.pem vào Keycloak client Credentials tab

# Token request với client_assertion
POST /realms/my-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials&
client_id=my-client&
client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&
client_assertion=eyJhbGciOiJSUzI1NiIs...

クライアント アサーション JWT 構造:

{
  "iss": "my-client",                    // Client ID
  "sub": "my-client",                    // Client ID
  "aud": "http://localhost:8080/realms/my-realm",  // Token endpoint
  "iat": 1711800000,
  "exp": 1711800060,                     // Short-lived (60s)
  "jti": "unique-jwt-id"                 // Unique ID
}

6.3 X.509証明書/相互TLS

クライアントはクライアント TLS 証明書 (相互 TLS — mTLS) を使用して認証します。これが最も安全な方法です。

構成:

  1. クライアント → タブ資格 → クライアント認証子: X.509証明書

  2. 入力件名DNまたは証明書照合のパターン

  3. Keycloakサーバーを構成してmTLSエンドポイントを有効にする

# Keycloak mTLS configuration (quarkus)
# conf/keycloak.conf hoặc environment variables
KC_HTTPS_CLIENT_AUTH=request
KC_HTTPS_KEY_STORE_FILE=/opt/keycloak/certs/server-keystore.p12
KC_HTTPS_TRUST_STORE_FILE=/opt/keycloak/certs/truststore.p12

# Client gọi token endpoint với client certificate
curl -s -X POST \
  "https://localhost:8443/realms/my-realm/protocol/openid-connect/token" \
  --cert client-cert.pem \
  --key client-private.pem \
  -d "grant_type=client_credentials" \
  -d "client_id=my-mtls-client"

mTLS と証明書にバインドされたトークンを組み合わせます。

# Access token chứa certificate thumbprint
{
  "cnf": {
    "x5t#S256": "sha256-thumbprint-of-client-certificate"
  }
}

Resource server verify:

1. Client gửi request với TLS client certificate

2. Resource server extract certificate thumbprint

3. So sánh với cnf.x5t#S256 trong access token

→ Nếu match → token hợp lệ + bound to correct client

7. 標準トークン交換 (RFC 8693)

トークン交換によりサービスが可能になりますトークンを交換する異なる権限または対象者を持つ新しいトークンを受け取るため。

7.1 使用例

  • 代表団: サービス A は、ユーザーの「代理」としてサービス B を呼び出したいと考えています。アクセス トークンを交換して、オーディエンス = サービス B と新しいトークンを取得します。

  • なりすまし: 管理者は別のユーザーのように行動したいと考えています

  • トークンの種類の変換: SAML アサーションのアクセス トークンを交換します (またはその逆)。

7.2 トークン交換の構成

Keycloakのトークン交換はプレビュー機能— 有効にする必要があります:

# Bật feature
bin/kc.sh start-dev --features=token-exchange

# Docker
docker run -e KC_FEATURES=token-exchange quay.io/keycloak/keycloak:26.2.4 start-dev

権限を構成します。

  1. 開けるターゲットクライアント(トークンを交換したいクライアント) → タブ権限

  2. オンにする許可が有効です

  3. クリックトークン交換許可 → ソースクライアント交換を許可するポリシーを設定

# Token Exchange request
POST /realms/my-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
subject_token=USER_ACCESS_TOKEN&
subject_token_type=urn:ietf:params:oauth:token-type:access_token&
requested_token_type=urn:ietf:params:oauth:token-type:access_token&
audience=target-service&
client_id=source-service&
client_secret=SOURCE_SECRET

# Response — token mới cho target-service
{
  "access_token": "new-token-for-target-service",
  "token_type": "Bearer",
  "expires_in": 300,
  "issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
}

7.3 委任と偽装

モード説明するトークンの要求
代表団サービス B は、サービス A がユーザーに代わって動作していることを認識していますact.sub= サービス A、サブ= ユーザー
なりすましサービス B は知りません - トークンはそれを直接要求したユーザーと同一ですサブ= ユーザー (なし活動。活動)

8. JWT 認可付与 (RFC 7523)

クライアントが使用できるようにしますJWT アサーションは信頼できる発行者によって発行されますユーザーの介入なしでアクセス トークンを取得します。

8.1 フロー

# External issuer (ví dụ: Azure AD, Google) cấp JWT cho client
# Client gửi JWT đến Keycloak để exchange lấy Keycloak access token

POST /realms/my-realm/protocol/openid-connect/token Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer& assertion=eyJhbGciOiJSUzI1NiIs...& # JWT from external issuer client_id=my-client& client_secret=my-secret& scope=openid

8.2 JWT 許可の構成

  1. レルム設定 →キー→ 外部発行者の署名キーを追加

  2. または構成アイデンティティプロバイダー外部発行者向け

  3. クライアントが持っている必要があるサービスアカウントの役割有効になりました。有効

9. MCPサーバー用のKeycloakの構成

Model Context Protocol (MCP) サーバーは、OAuth 2.0 を使用してクライアントを認証します。 Keycloakが役割を果たす可能性がある認可サーバーMCP エコシステム向け。

9.1 MCP OAuth 2.0 フロー

MCP 仕様では、サーバー間およびクライアント間の認証に OAuth 2.0 が必要です。

┌──────────┐     ┌──────────┐     ┌──────────┐
│ MCP Host │     │ Keycloak │     │MCP Server│
│ (Client) │     │  (AuthZ) │     │(Resource)│
└────┬─────┘     └────┬─────┘     └────┬─────┘
     │                │                │
     │ 1. Request     │                │
     │    auth info    │                │
     │───────────────────────────────>│
     │ 2. Return      │                │
     │    auth metadata│                │
     │<──────────────────────────────│
     │                │                │
     │ 3. Authorization Code Flow     │
     │    (hoặc Client Credentials)   │
     │───────────────>│                │
     │ 4. Tokens      │                │
     │<───────────────│                │
     │                │                │
     │ 5. API call with access token  │
     │───────────────────────────────>│
     │ 6. MCP Server validates token  │
     │    via Keycloak JWKS/Introspect│
     │<──────────────────────────────│

9.2 MCP ホストのクライアントの作成

# MCP Host client — ứng dụng AI/LLM kết nối tới MCP servers
Client ID: mcp-host-app
Client type: OpenID Connect
Client authentication: ON (confidential)

Capability Config: Standard flow: ON # Cho interactive MCP sessions Service accounts roles: ON # Cho automated MCP operations

Access Settings: Valid redirect URIs: http://localhost:3001/callback Web origins: http://localhost:3001

Advanced: PKCE Code Challenge Method: S256 Access Token Lifespan: 300 # 5 phút

9.3 MCP サーバー (リソース サーバー) のクライアントの作成

# MCP Server client — validate incoming tokens
Client ID: mcp-tool-server
Client type: OpenID Connect
Client authentication: ON (confidential)

Capability Config: Standard flow: OFF Service accounts roles: ON # Nếu MCP server cần gọi Keycloak APIs

MCP Server cấu hình JWT validation

Sử dụng Keycloak JWKS endpoint để verify access tokens

JWKS_URI: http://localhost:8080/realms/my-realm/protocol/openid-connect/certs ISSUER: http://localhost:8080/realms/my-realm

9.4 MCP 操作のスコープの作成

# Tạo Client Scopes cho MCP permissions
Client Scope: mcp:tools:read
  Type: Optional
  Description: Read access to MCP tools
  Protocol Mapper: Hardcoded claim
    Token Claim Name: mcp_permissions
    Claim Value: ["tools:read"]

Client Scope: mcp:tools:execute Type: Optional Description: Execute MCP tools Protocol Mapper: Hardcoded claim Token Claim Name: mcp_permissions Claim Value: ["tools:execute"]

Client Scope: mcp:resources:read Type: Optional Description: Read MCP resources Protocol Mapper: Hardcoded claim Token Claim Name: mcp_permissions Claim Value: ["resources:read"]

Gán scopes cho MCP Host client

Client: mcp-host-app Default scopes: mcp:tools:read, mcp:resources:read Optional scopes: mcp:tools:execute

9.5 MCP のオーディエンス マッパー

# MCP Host client cần access token với audience = MCP Server
Client: mcp-host-app → Client scopes → Dedicated scope → Add mapper
  Mapper Type: Audience
  Name: mcp-server-audience
  Included Client Audience: mcp-tool-server
  Add to access token: ON

Access token kết quả:

{ "iss": "http://localhost:8080/realms/my-realm", "sub": "user-or-service-account-id", "aud": ["mcp-host-app", "mcp-tool-server"], "azp": "mcp-host-app", "scope": "openid mcp:tools:read mcp:resources:read", "mcp_permissions": ["tools:read", "resources:read"] }

9.6 MCP マルチサーバーのトークン交換

MCP ホストが多くの異なる MCP サーバーを呼び出す必要がある場合は、トークン交換を使用して各サーバーのトークンを取得します。

# MCP Host có access token cho mcp-tool-server-1
# Cần access mcp-tool-server-2

POST /realms/my-realm/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:token-exchange&
subject_token=CURRENT_ACCESS_TOKEN&
subject_token_type=urn:ietf:params:oauth:token-type:access_token&
audience=mcp-tool-server-2&
client_id=mcp-host-app&
client_secret=HOST_SECRET&
scope=mcp:tools:execute

9.7 MCP のクライアント ポリシー

# Enforce security cho tất cả MCP clients
Profile: mcp-security-profile
  Executors:
    - PKCE Enforcer (S256)
    - Confidential Client Enforcer
    - Secure Signing Algorithm (RS256, ES256)
    - Reject Implicit Grant
    - Reject Resource Owner Password Credentials Grant
    - Holder-of-Key Enforcer  # DPoP cho high-security MCP operations

Policy: mcp-clients-policy Conditions: - Client Scopes: mcp:tools:read # Áp dụng cho clients request MCP scopes Profiles: - mcp-security-profile

10. 練習問題

ラボ 1: クライアント ポリシー — ベースライン セキュリティ

  1. クライアントプロファイルの作成ベースラインセキュリティエグゼキュータを使用: 暗黙的な許可の拒否、PKCE エンフォーサ、安全な署名アルゴリズム

  2. クライアントポリシーの作成ベースラインを強制する条件付きあらゆるクライアント

  3. テスト: 新しいクライアントを作成し、PKCE なしでトークンを要求しようとします → 拒否されました

  4. テスト: 暗黙的なフローをオンにしてみてください → 拒否されました

ラボ 2: FAPI 2.0 への準拠

  1. 組み込みの FAPI 2.0 セキュリティ プロファイルを使用してクライアント プロファイルを作成する

  2. ロールを持つクライアントにのみ適用されるポリシーを作成するファピクライアント

  3. 署名付き JWT 認証を使用して機密クライアントを作成する

  4. PAR + PKCE + DPoP を使用して完全な認証フローをテストする

ラボ 3: クライアント シークレットのローテーション

  1. Secret Rotation executor を構成します (有効期限: 60 秒、猶予期間: テスト用に 30 秒)

  2. 機密クライアントの作成 → シークレットAを記録

  3. 60秒待つ → シークレットを再生成 → シークレットBを記録

  4. 検証: シークレット A は猶予期間 (30 秒) の間アクティブのままです。

  5. 検証: 猶予期間の後、シークレット B のみがアクティブになります

ラボ 4: サービス アカウント + トークン交換

  1. 3 つのクライアントを作成します。フロントエンドアプリ(公共)、APIゲートウェイ(機密 + サービス アカウント)、決済サービス(機密)

  2. ユーザーは次の方法でログインしますフロントエンドアプリ→ アクセストークンを受け取る

  3. APIゲートウェイフロントエンドからトークンを受け取り、新しいトークンと交換します決済サービス

  4. 確認: 新しいトークンが利用可能ですaud: 支払いサービスそしてact.sub: API ゲートウェイ

ラボ 5: MCP サーバーの構成

  1. レルムの作成mcp-デモ

  2. クライアントを作成します。mcp-ホスト(機密)、mcp-ツール-サーバー(機密)

  3. クライアント スコープを作成します。mcp:ツール:読み取り, mcp:ツール:実行

  4. オーディエンス マッパーを構成するmcp-ホスト→ 視聴者 =mcp-ツール-サーバー

  5. クライアント認証情報フローでトークンを取得する

  6. トークンの内容を確認します: 対象者、スコープ、権限

  7. MCP サーバーのシミュレートは、JWKS エンドポイントを使用してトークンを検証します

ラボ 6: 署名付き JWT クライアント認証

  1. RSA キー ペアの生成 (オープンSSL)

  2. オーセンティケータを使用して機密クライアントを作成 =署名付き JWT

  3. 証明書をKeycloakにアップロードする

  4. client_assertion JWT を作成して署名するスクリプトを作成します。

  5. トークンをリクエストするクライアントアサーションの代わりにクライアントシークレット

  6. 受け取ったトークンを確認する