コンテンツにスキップ
これは最新の機能を備えた最新リリースですが、長期サポートは提供されません。サポートを継続するには、新しいリリースごとにアップグレードするか、四半期ごとの安定版リリースをご利用ください。

For the complete documentation index, see llms.txt. Markdown versions of all docs pages are available by appending .md to any docs URL.

Keycloak

Page as Markdown

Keycloak を OIDC プロバイダーとして設定し、Solo Enterprise for agentregistry でユーザーを認証します。

Solo Enterprise for agentregistry は ID プロバイダー (IdP) によって保護されているため、認可されたユーザーだけが AI アーティファクトにアクセス、公開、デプロイできます。このガイドでは、IdP として Keycloak をデプロイし、必要な OIDC クライアントを作成して、レジストリサーバーと CLI がそれらを使用するように設定する手順を説明します。

始める前に

  1. 次の CLI をインストールします。

    • helm: Install the Solo Enterprise for agentregistry Helm chart。
  • kubectl: Kubernetes クラスターを操作します。
    • aws: AWS Bedrock AgentCore 内のエージェントを操作します。
    • jq: このガイドではスクリプトのラッパーとして使用します。
  • openssl: JWT 署名用の一意の秘密鍵を生成します。brew install openssl でインストールします。
  1. Docker Desktop などの Docker Engine をローカルマシンにセットアップして起動し、Kind クラスターを扱えるようにします。Solo Enterprise for agentregistry は、Docker イメージのビルドと AI アーティファクトの起動にも Docker Compose を使用します。

  2. Kubernetes クラスターを作成するか、既存のクラスターを使用します。ローカルのテスト環境では、Kind クラスターを作成できます。

    kind create cluster

ステップ 1: Keycloak を構成する

Solo Enterprise for agentregistry は独自の ID プロバイダーをバンドルしていません。代わりに、外部の OIDC プロバイダーを使用してユーザーを認証し、アクセストークンを発行し、ロールベースのアクセス制御を適用します。

Keycloak をデプロイする前に、Solo Enterprise for agentregistry に必要なレルム、クライアント、プロトコルマッパー、グループ、ユーザーを定義する ConfigMap を作成して設定します。Keycloak は起動時にこの ConfigMap を読み取り、これらのリソースを自動的に作成するため、Keycloak UI から手動で設定する必要はありません。

OIDC クライアントの構成は、Solo Enterprise for agentregistry を接続するランタイムによって異なります。

次の ConfigMap は、Solo Enterprise for agentregistry を AWS Bedrock AgentCore、Azure AI Foundry、Microsoft Copilot Studio、および Solo Enterprise for agentgateway を基盤とする仮想ランタイムに接続するために必要なリソースを定義します。

ResourceNameDescription
Realmagentregistryagentregistry の ID 設定を他のアプリケーションから分離する専用の Keycloak レルムです。レジストリサーバーは、このレルムの発行者 URL を使用して OIDC エンドポイントを検出します。
Clientar-backendCLI クライアントと UI クライアントが発行したアクセストークンを検証するために、レジストリサーバーが使用するコンフィデンシャルクライアントです。
Clientar-cli-interactivearctl CLI 用のパブリッククライアントです。デバイス認可付与 (RFC 8628) を使用するため、ユーザーは表示された URL をブラウザーで開くことでターミナルからログインできます。
Clientar-cli-passwordCI/CD パイプラインでスクリプト化されたユーザー認証を行うためのパブリッククライアントです。ユーザー名とパスワードによるパスワード認証情報グラントを使用します。
Clientar-uiブラウザーベースのレジストリ UI 用のパブリッククライアントです。PKCE を使用した認可コードフローを使用します。redirectUris と webOrigins は、ローカルテスト用に * に設定されています。本番環境では、UI が実際に使用するオリジンに置き換えてください。
Clientar-mcp-clientClaude Code や Codex などの MCP クライアント用のパブリッククライアントです。PKCE を使用する認可コードフローを使用します。リダイレクト URI は http://localhost:* に制限されるため、ローカル MCP クライアントは Dynamic Client Registration を使用せずに OAuth コールバックを受信できます。
Protocol mappergroupsユーザーの Keycloak グループメンバーシップを Groups JWT クレームに書き込む oidc-group-membership-mapper です。レジストリはこのクレームを読み取り、RBAC ロールを判定します。ar-cli-interactive、ar-cli-password、ar-ui、ar-mcp-client クライアントに対して発行されるアクセストークンに追加されます。
Protocol mapperar-backend-audienceアクセストークンの aud クレームに ar-backend を追加する oidc-audience-mapper です。正しい aud クレームがない場合、レジストリサーバーは 401 Unauthorized エラーでトークンを拒否します。ar-cli-interactive、ar-cli-password、ar-ui、ar-mcp-client クライアントに対して発行されるアクセストークンに追加されます。
Groupadminsレジストリで完全な管理者アクセスを付与するグループです。admin-user に割り当てられるため、初回ログイン時からスーパーユーザー権限を持ちます。
Useradmin-userパスワードが password のテスト用管理ユーザーで、admins グループに割り当てられています。
  1. Keycloak ネームスペースを作成します。

    kubectl create namespace keycloak
  2. Solo Enterprise for agentregistry の OIDC 設定を含む ConfigMap を作成します。

    kubectl apply -f- <<EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: keycloak-agentregistry-realm
      namespace: keycloak
    data:
      agentregistry-realm.json: |
        {
          "realm": "agentregistry",
          "enabled": true,
          "clients": [
            {
              "clientId": "ar-backend",
              "enabled": true,
              "publicClient": false,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": false
            },
            {
              "clientId": "ar-cli-interactive",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": false,
              "attributes": {
                "oauth2.device.authorization.grant.enabled": "true"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "ar-cli-password",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": true,
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "ar-ui",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": true,
              "directAccessGrantsEnabled": false,
              "redirectUris": ["*"],
              "webOrigins": ["*"],
              "attributes": {
                "pkce.code.challenge.method": "S256"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "ar-mcp-client",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": true,
              "directAccessGrantsEnabled": false,
              "redirectUris": ["http://localhost:*"],
              "webOrigins": ["http://localhost:*"],
              "attributes": {
                "pkce.code.challenge.method": "S256"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            }
          ],
          "groups": [
            {"name": "admins"}
          ],
          "users": [
            {
              "username": "admin-user",
              "email": "admin-user@example.com",
              "firstName": "Admin",
              "lastName": "User",
              "enabled": true,
              "credentials": [
                {"type": "password", "value": "password", "temporary": false}
              ],
              "groups": ["admins"]
            }
          ]
        }
    EOF

次の ConfigMap は、Solo Enterprise for agentregistry を Solo Enterprise for kagent に接続する構成に必要なリソースを定義します。この構成には、kagent 管理プレーン UI 用のクライアントが追加で含まれます。

ResourceNameDescription
Realmagentregistryagentregistry の ID 設定を他のアプリケーションから分離する専用の Keycloak レルムです。レジストリサーバーは、このレルムの発行者 URL を使用して OIDC エンドポイントを検出します。
Clientar-backendCLI クライアントと UI クライアントが発行したアクセストークンを検証するために、レジストリサーバーが使用するコンフィデンシャルクライアントです。
Clientar-cli-interactivearctl CLI 用のパブリッククライアントです。デバイス認可付与 (RFC 8628) を使用するため、ユーザーは表示された URL をブラウザーで開くことでターミナルからログインできます。
Clientar-cli-passwordCI/CD パイプラインでスクリプト化されたユーザー認証を行うためのパブリッククライアントです。ユーザー名とパスワードによるパスワード認証情報グラントを使用します。
Clientar-uiブラウザーベースのレジストリ UI 用のパブリッククライアントです。PKCE を使用した認可コードフローを使用します。redirectUris と webOrigins は、ローカルテスト用に * に設定されています。本番環境では、UI が実際に使用するオリジンに置き換えてください。
Clientar-mcp-clientClaude Code や Codex などの MCP クライアント用のパブリッククライアントです。PKCE を使用する認可コードフローを使用します。リダイレクト URI は http://localhost:* に制限されるため、ローカル MCP クライアントは Dynamic Client Registration を使用せずに OAuth コールバックを受信できます。
Clientkagent-backendkagent-ui に発行されたアクセストークンを検証するために、kagent-enterprise コントローラーと solo-enterprise-ui バックエンドが使用するコンフィデンシャルクライアントです。aud クレームに ar-backend が含まれるトークンは受け付けられず、オーディエンスに kagent-backend が含まれるトークンだけが受け付けられます。
Clientkagent-uisolo-enterprise-ui ブラウザーフロントエンド用のパブリッククライアントです。PKCE を使用した認可コードフローを使用します。
Protocol mappergroupsユーザーの Keycloak グループメンバーシップを Groups JWT クレームに書き込む oidc-group-membership-mapper です。ar-cli-interactive、ar-cli-password、ar-ui、ar-mcp-client、kagent-ui クライアントに対して発行されるアクセストークンに追加されます。
Protocol mapperar-backend-audiencear-cli-interactive、ar-cli-password、ar-ui、ar-mcp-client クライアントに対して発行されるアクセストークンの aud クレームに ar-backend を追加する oidc-audience-mapper です。正しい aud クレームがない場合、レジストリサーバーは 401 Unauthorized エラーでトークンを拒否します。
Protocol mapperkagent-backend-audiencekagent-ui クライアント向けに発行されるアクセストークンの aud クレームに kagent-backend を追加する oidc-audience-mapper です。これがないと、kagent-enterprise は UI からのトークンを 401 Unauthorized エラーで拒否します。
ClientagentregistrySolo Enterprise for kagent コントローラーを呼び出すときに、agentregistry サーバーが自身を認証するために使用するコンフィデンシャルなサービスアカウントクライアントです。kagent ランタイムを対象とするデプロイを作成、更新、削除すると、agentregistry サーバーはこのクライアントを使用して OAuth2 client_credentials グラント経由で Keycloak からアクセストークンを取得します。このクライアントには groups プロトコルマッパーがあり、サービスアカウントのグループメンバーシップを Groups クレームに追加するため、kagent コントローラーはそれを RBAC ロールにマッピングできます。
Groupadminsレジストリで完全な管理者アクセスを付与するグループです。admin-user に割り当てられるため、初回ログイン時からスーパーユーザー権限を持ちます。
Groupagentregistryservice-account-agentregistry ユーザーに割り当てられます。kagent の RBAC はこのグループのメンバーシップを global.Writer ロールにマッピングし、agentregistry サーバーに kagent リソースの作成、更新、削除の権限を付与します。
Useradmin-userパスワードが password のテスト用管理ユーザーで、admins グループに割り当てられています。
Userservice-account-agentregistryagentregistry クライアントを内部的に表すために Keycloak が自動的に作成するバックエンドユーザーです。インポート時に agentregistry グループに割り当てられるため、client_credentials グラントで発行されたトークンには Groups: ["agentregistry"] クレームが含まれます。
  1. Keycloak ネームスペースを作成します。

    kubectl create namespace keycloak
  2. Solo Enterprise for agentregistry の OIDC 設定を含む ConfigMap を作成します。

    kubectl apply -f- <<EOF
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: keycloak-agentregistry-realm
      namespace: keycloak
    data:
      agentregistry-realm.json: |
        {
          "realm": "agentregistry",
          "enabled": true,
          "accessTokenLifespan": 86400,
          "ssoSessionIdleTimeout": 86400,
          "ssoSessionMaxLifespan": 86400,
          "clients": [
            {
              "clientId": "ar-backend",
              "enabled": true,
              "publicClient": false,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": false
            },
            {
              "clientId": "ar-cli-interactive",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": false,
              "attributes": {
                "oauth2.device.authorization.grant.enabled": "true"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "ar-cli-password",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": true,
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "ar-ui",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": true,
              "directAccessGrantsEnabled": false,
              "redirectUris": ["*"],
              "webOrigins": ["*"],
              "attributes": {
                "pkce.code.challenge.method": "S256"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "ar-mcp-client",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": true,
              "directAccessGrantsEnabled": false,
              "redirectUris": ["http://localhost:*"],
              "webOrigins": ["http://localhost:*"],
              "attributes": {
                "pkce.code.challenge.method": "S256"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "ar-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "ar-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "kagent-backend",
              "enabled": true,
              "publicClient": false,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": false
            },
            {
              "clientId": "kagent-ui",
              "enabled": true,
              "publicClient": true,
              "standardFlowEnabled": true,
              "directAccessGrantsEnabled": false,
              "redirectUris": ["*"],
              "webOrigins": ["*"],
              "attributes": {
                "pkce.code.challenge.method": "S256"
              },
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "true",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "true"
                  }
                },
                {
                  "name": "kagent-backend-audience",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-audience-mapper",
                  "consentRequired": false,
                  "config": {
                    "included.client.audience": "kagent-backend",
                    "id.token.claim": "false",
                    "access.token.claim": "true"
                  }
                }
              ]
            },
            {
              "clientId": "agentregistry",
              "enabled": true,
              "publicClient": false,
              "serviceAccountsEnabled": true,
              "standardFlowEnabled": false,
              "directAccessGrantsEnabled": false,
              "protocolMappers": [
                {
                  "name": "groups",
                  "protocol": "openid-connect",
                  "protocolMapper": "oidc-group-membership-mapper",
                  "consentRequired": false,
                  "config": {
                    "claim.name": "Groups",
                    "full.path": "false",
                    "id.token.claim": "false",
                    "access.token.claim": "true",
                    "userinfo.token.claim": "false"
                  }
                }
              ]
            }
          ],
          "groups": [
            {"name": "admins"},
            {"name": "agentregistry"}
          ],
          "users": [
            {
              "username": "admin-user",
              "email": "admin-user@example.com",
              "firstName": "Admin",
              "lastName": "User",
              "enabled": true,
              "credentials": [
                {"type": "password", "value": "password", "temporary": false}
              ],
              "groups": ["admins"]
            },
            {
              "username": "service-account-agentregistry",
              "enabled": true,
              "serviceAccountClientId": "agentregistry",
              "groups": ["agentregistry"]
            }
          ]
        }
    EOF

Step 2: Deploy Keycloak

レルムの設定が完了したら、Keycloak をデプロイします。このステップでは Keycloak Pod を作成し、ロードバランサーサービスを通じて公開して、レジストリサーバーと arctl CLI の両方から到達できるようにします。--import-realm フラグを指定すると、Keycloak は起動時にステップ 1 の ConfigMap を読み込み、レルム、クライアント、ユーザーのすべての設定を自動的に適用します。

  1. Keycloak のデプロイとサービスを作成します。

    kubectl apply -f- <<EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: keycloak
      namespace: keycloak
      labels:
        app: keycloak
    spec:
      ports:
      - name: http
        port: 8080
        targetPort: 8080
      selector:
        app: keycloak
      type: LoadBalancer
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: keycloak
      namespace: keycloak
      labels:
        app: keycloak
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: keycloak
      template:
        metadata:
          labels:
            app: keycloak
        spec:
          containers:
          - name: keycloak
            image: quay.io/keycloak/keycloak:26.1.3
            args: ["start-dev", "--import-realm"]
            env:
            - name: KC_BOOTSTRAP_ADMIN_USERNAME
              value: "admin"
            - name: KC_BOOTSTRAP_ADMIN_PASSWORD
              value: "admin"
            - name: PROXY_ADDRESS_FORWARDING
              value: "true"
            - name: KC_PROXY
              value: "edge"
            ports:
            - name: http
              containerPort: 8080
            readinessProbe:
              httpGet:
                path: /realms/master
                port: 8080
            volumeMounts:
            - name: realm-config
              mountPath: /opt/keycloak/data/import
          volumes:
          - name: realm-config
            configMap:
              name: keycloak-agentregistry-realm
    EOF
  2. Keycloak のロールアウトが完了するまで待ちます。

    kubectl -n keycloak rollout status deploy/keycloak
  3. ロードバランサーサービスから Keycloak のエンドポイント情報を設定します。これらの環境変数は、このガイドの残りの部分で使用します。KEYCLOAK_ISSUER は、レジストリがトークンエンドポイントと JWKS エンドポイントを見つけるために使用する OIDC 検出 URL です。Kind でローカルに実行していて、ロードバランサーサービスにローカル IP アドレスが必要な場合は、cloud-provider-kind の使用を検討してください。

    export ENDPOINT_KEYCLOAK=$(kubectl -n keycloak get service keycloak -o jsonpath='{.status.loadBalancer.ingress[0].ip}{.status.loadBalancer.ingress[0].hostname}'):8080
    export HOST_KEYCLOAK=$(echo ${ENDPOINT_KEYCLOAK} | cut -d: -f1)
    export PORT_KEYCLOAK=$(echo ${ENDPOINT_KEYCLOAK} | cut -d: -f2)
    export KEYCLOAK_URL=http://${ENDPOINT_KEYCLOAK}
    export KEYCLOAK_REALM=agentregistry
    export KEYCLOAK_ISSUER=$KEYCLOAK_URL/realms/${KEYCLOAK_REALM}
    echo $KEYCLOAK_ISSUER
  4. Keycloak が自動生成したクライアントシークレットを取得します。これらのシークレットは、次の手順でそれぞれの Helm チャートに渡します。

    ar-backend クライアントシークレットを取得します。レジストリサーバーは、このシークレットを使用してアクセストークンを検証します。

    export KEYCLOAK_TOKEN=$(curl -s \
      -d "client_id=admin-cli" -d "username=admin" -d "password=admin" \
      -d "grant_type=password" \
      "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
      | jq -r .access_token)
    
    export AR_BACKEND_ID=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=ar-backend" \
      | jq -r '.[0].id')
    
    export AR_BACKEND_SECRET=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${AR_BACKEND_ID}/client-secret" \
      | jq -r .value)
    echo "AR_BACKEND_SECRET: $AR_BACKEND_SECRET"

    ar-backend、kagent-backend、agentregistry の各クライアントシークレットを取得します。レジストリサーバーは、アクセストークンの検証に ar-backend シークレットを使用します。kagent-enterprise コントローラーは、kagent-ui クライアントに発行されたトークンの検証に kagent-backend シークレットを使用します。agentregistry シークレットは、レジストリサーバーが自身のサービス ID で Solo Enterprise for kagent を呼び出すときに使用されます。

    export KEYCLOAK_TOKEN=$(curl -s \
      -d "client_id=admin-cli" -d "username=admin" -d "password=admin" \
      -d "grant_type=password" \
      "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
      | jq -r .access_token)
    
    export AR_BACKEND_ID=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=ar-backend" \
      | jq -r '.[0].id')
    export AR_BACKEND_SECRET=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${AR_BACKEND_ID}/client-secret" \
      | jq -r .value)
    echo "AR_BACKEND_SECRET: $AR_BACKEND_SECRET"
    
    export KAGENT_BACKEND_ID=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=kagent-backend" \
      | jq -r '.[0].id')
    export KAGENT_BACKEND_SECRET=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${KAGENT_BACKEND_ID}/client-secret" \
      | jq -r .value)
    echo "KAGENT_BACKEND_SECRET: $KAGENT_BACKEND_SECRET"
    
    export AGENTREGISTRY_OUTBOUND_ID=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients?clientId=agentregistry" \
      | jq -r '.[0].id')
    export AGENTREGISTRY_OUTBOUND_SECRET=$(curl -s -H "Authorization: Bearer ${KEYCLOAK_TOKEN}" \
      "${KEYCLOAK_URL}/admin/realms/${KEYCLOAK_REALM}/clients/${AGENTREGISTRY_OUTBOUND_ID}/client-secret" \
      | jq -r .value)
    echo "AGENTREGISTRY_OUTBOUND_SECRET: $AGENTREGISTRY_OUTBOUND_SECRET"

次のステップ