---
title: "ClickHouse Cloud における JWT 認証のご紹介"
date: "2026-10-09T03:25:52.959Z"
author: "ClickHouse team"
category: "Product"
excerpt: "データベースのパスワードを使う代わりに、ID プロバイダーから発行された有効期間の短いトークンを使用して ClickHouse Cloud に接続できます。"
---

# ClickHouse Cloud における JWT 認証のご紹介

> TL;DR
> データベースのパスワードの代わりに、お使いのIDプロバイダーが発行する有効期間の短いトークンを使用して ClickHouse Cloud に接続できます。

長期間有効なデータベースの認証情報は管理が困難です。ユーザー、パイプライン、アプリケーションごとにパスワードや証明書が必要になり、アクセスの変更に応じてそれらを保存、ローテーション、失効させる必要があります。

ClickHouse Cloud サービス(26.4 以降)向けの JWT 認証は、このワークフローを Okta や Microsoft Entra を含む既存の OpenID Connect プロバイダーから発行される有効期間の短い JWT トークンに置き換えます。IDとロールはプロバイダー側で保持され、ClickHouse Cloud は個別のデータベースパスワードの代わりにそのトークンを受け付けます。トークンの有効期限が切れると、そのトークンによって付与されたアクセス権も失効します。

これにより、セキュリティチームやプラットフォームチームが管理しなければならない認証情報の数が減り、ユーザーやワークロードごとに永続的なデータベースユーザーをプロビジョニングする必要がなくなります。これは、ClickHouse Cloud における広範なセキュリティおよびガバナンスへの取り組みの一環です。

## 仕組み

クライアントが JWT トークンを提示すると、ClickHouse は設定されたプロバイダーと照合して、その署名と必要なクレームを検証します。その後、エフェメラル(一時的な)ユーザーを作成し、サービスの権限制限の範囲内で、トークンに含まれるロールと付与権限(Grants)を適用します。

トークンには、標準の JWT クレームとともに、ロールや権限用の任意の ClickHouse クレームが含まれます。

- `iss`: トークンを発行した発行者
- `aud`: トークンの対象となるサービス
- `sub`: 対象となるユーザー
- `iat` および `exp`: トークンが発行された日時と有効期限
- `clickhouse:roles`: 有効化する既存のロール名の任意のリスト

お使いのIDプロバイダーがロール用に別のクレーム名(例: `groups`)を使用している場合は、どのクレームを読み取るかを ClickHouse に指定できます。

```json
{
  "iss": "https://your-tenant.okta.com",
  "sub": "jane.doe",
  "aud": "my-clickhouse-service",
  "exp": 1719504000,
  "iat": 1719500400,
  "clickhouse:roles": ["analyst", "reader"]
}
```

有効なトークンを受け取ると、ClickHouse はメモリ内にエフェメラルユーザーを作成し、トークンが要求したアクセス権を付与してクエリを実行します。ユーザー名は固定のパターンに従い、発行者、サブジェクト、オーディエンス、およびロールのクレームを対象としてハッシュが計算されます。

```text
JWT::<subject>::<claims_hash>
```

同じユーザーであっても、ロールが異なるトークンからはそれぞれ異なるユーザーが生成されるため、同一のIDに属していても `system.users` でセッションを区別できます。マルチレプリカのサービスでは、トークンは転送されるクエリとともに伝播し、各ノードが個別にトークンを検証します。

## ユーザープロビジョニングが不要に

エフェメラルユーザーによって、データベース側でのユーザー管理の意味が変わります。パスワードや証明書を使用するユーザーの場合、新規採用者ごとに `CREATE USER` と一連の `GRANT` 文を実行し、それをIDプロバイダーと同期させ、退職時には忘れずに `DROP USER` を実行する必要があります。多くのチームでは最終的にスクリプトを作成することになりますが、スクリプトのメンテナンスが追いつかなくなります。

<!-- Editorial note from Notion: Consider linking readers to the security docs and explicitly recommending IdP-issued JWTs over older ephemeral passwords and certificate users. -->

JWT 認証では、スクリプトを作成する必要が一切ありません。有効なトークンが最初に提示された時点でメモリ上にユーザーが現れ、そのトークンが持つロールが付与され、トークンの `exp` が切れた後にバックグラウンドタスクによって削除されます。ユーザー自体がディスクに書き込まれることはありません。`CREATE USER` の手順は存在せず、トークンのライフサイクルがそのままユーザーのライフサイクルとなるため、`CREATE USER ... IDENTIFIED WITH jwt` は意図的に例外を発生させます。`ALTER USER` や `DROP USER` も適用されず、復元すべき対象が存在しないため、JWT ユーザーはバックアップにも含まれません。

ClickHouse 側で管理するのはロールのみです。`analyst` や `pipeline_writer` など、自社のチームに必要なロールを一度作成すれば、あとはトークン内にロール名を含めることで、誰にどのロールを付与するかをIDプロバイダー側で判断できます。オンボーディングはプロバイダー側でグループを割り当てるだけであり、オフボーディングはその割り当てを解除するだけです。そして `system.users` には、過去にアクセス権を付与された全員ではなく、現在アクティブなユーザーのみが表示されます。

## 独自のIDプロバイダーの持ち込み

お使いのIDプロバイダーが OpenID Connect に対応していれば、ClickHouse が必要とする要件はすでにすべて揃っています。OIDC プロバイダーは、ディスカバリードキュメント内で発行者と `jwks_uri` を公開し、`iss`、`aud`、`sub`、`exp`、`iat` をあらかじめ含めたトークンに署名します。これらが、ClickHouse が検証する値です。私たちは Okta および Microsoft Entra でのセットアップを検証済みですが、標準に準拠しているプロバイダーであれば同様に動作します。カスタムプロバイダーの場合、ClickHouse 自体はログインフローを実行しません。プロバイダーがトークンを発行し、クライアントがそれを提示し、ClickHouse が検証します。

Enterprise プランで 26.4 以降を実行しているサービスの場合、Cloud コンソールで対象のサービスを開き、Settings → Security → JWT authentication に移動します。各プロバイダーには、名前、プロバイダーがトークンに設定する発行者とオーディエンスの値、および JSON Web Key Set(JWKS)を公開している HTTPS URL が必要です。プロバイダーが `clickhouse:roles` 以外のクレーム(例: `groups` クレーム)にグループの所属情報を設定している場合は、Roles claim フィールドにその名前を設定します。その値は、サービス上に存在するロール名と一致している必要があります。設定を保存する際に ClickHouse が JWKS URL を取得するため、入力ミスがあってもユーザーの初回ログイン時ではなく、設定時にエラーとして検出されます。

JWKS プロバイダーは RSA キー(`RS256`)を受け付けます。バージョン 26.8 からは、P-256、P-384、P-521 曲線上の EC キー(`ES256`、`ES384`、`ES512`)もサポートされます。JWKS URL はパブリックな HTTPS エンドポイントである必要があります。

## 接続

クライアントが保持できるトークンには2種類あり、区別しておく価値があります。独自のIDプロバイダーによって発行されたトークンと、Cloud アカウント用に ClickHouse Cloud によって発行されたトークンです。

### IDプロバイダーからのトークン

カスタムプロバイダーの場合、IDプロバイダーがトークンを発行し、ClickHouse ドライバーがそれを提示します。トークンを取得する最も簡単な方法は、プロバイダー向けにすでに使用している OAuth クライアントライブラリを利用することです。サービスやパイプラインの場合は、通常、プロバイダーの SDK を介したクライアントクレデンシャルフローを意味します。ユーザーの場合は、プロバイダーが提供している任意のログインフローを意味します。トークン文字列を取得すれば、公式クライアントではユーザー名とパスワードの代わりにそれを受け付けることができます。

```typescript
// clickhouse-js
import { createClient } from '@clickhouse/client'

const client = createClient({
  url: 'https://your-instance.clickhouse.cloud:8443',
  access_token: token,
})
```

```python
# clickhouse-connect
import clickhouse_connect

client = clickhouse_connect.get_client(
    host='your-instance.clickhouse.cloud',
    port=443,
    secure=True,
    access_token=token,
)
```

トークンには有効期限があるため、多くのクライアントでは独自のリフレッシュロジックを組み込むこともできます。`clickhouse-connect` は `token_provider` コールバックを受け付け、最初のトークン取得時、および期限切れのトークンがサーバーに拒否された際に再度このコールバックを呼び出します。Go クライアントはオプション内で `GetJWT` コールバックを受け取ります。Java クライアントには、ビルダー上に `useBearerTokenAuth` が用意されており、実行中のクライアントでトークンを切り替えるための `updateBearerToken` も備わっています。アドホックなクエリであれば、`clickhouse-client` や通常の HTTP でも機能します。

```bash
clickhouse-client --host your-instance.clickhouse.cloud --secure --jwt "$TOKEN"

curl -H "Authorization: Bearer $TOKEN" \
    'https://your-instance.clickhouse.cloud:8443/?query=SELECT+currentUser()'
```

すべてのクライアントにおいて、トークンはユーザー名やパスワードに追加されるのではなく、それらを置き換えるものとして機能します。両方を渡すとエラーになります。

### ClickHouse Cloud からのトークン

すべての Cloud サービスには組み込みの認証機能(オーセンティケーター)も備わっており、ClickHouse Cloud がお使いの Cloud アカウント向けにそのトークンを発行します。このトークンを手動で扱う必要はありません。SQL Console は自動的にこれらを使用し、`clickhouse-client --login` は Cloud ログインに対して OAuth2 デバイスコードフローを実行し、その結果を ClickHouse トークンと交換し、バックグラウンドでリフレッシュして、新しいトークンが届いたときに再接続します。

```bash
clickhouse-client --host your-instance.clickhouse.cloud --login
```

## 出現しては消えるユーザーに対するクォータと行ポリシー

JWT ユーザーがトークンの有効期間中しか存在しないとすれば、ClickHouse が通常ユーザーに関連付けている各種設定はどうなるのでしょうか。通常のユーザーは多くの設定の紐付け先となります。設定プロファイルはアナリストのクエリが使用できるメモリ量を制限します。クォータはダッシュボードが1時間あたりに実行できるクエリ数を制限します。行ポリシーは、地域のチームが自地域の行のみを参照できるようにします。これらはすべて名前によってユーザーに割り当てられるため、ユーザーが数時間ごとに消滅するとしたら、その割り当ても一緒に消滅してしまうと考えるのが自然です。

しかし、実際には消滅しません。JWT ユーザーには異なる2つの名前があるためです。先ほど確認した目に見えるユーザー名は、トークン内のロールが変更されるたびに変わります。その裏で、ClickHouse は発行者、サブジェクト、オーディエンスの各クレームから計算された UUID をすべてのIDに付与します。その UUID は、同じ人物が同じプロバイダー経由でログインする限り、トークンがどのロールを持っていても、ユーザーの有効期限が切れて再作成された回数に関係なく、常に同一です。

設定プロファイル、クォータ、行ポリシー、およびカラムマスキングポリシーは、この UUID に紐付けられます。通常のユーザーに使用するのと同じステートメントを使用して、ユーザーがアクティブな間に `system.users` に表示されている現在の名前を参照することで割り当てを行います。

```sql
ALTER SETTINGS PROFILE readonly_profile ADD TO 'JWT::jane.doe::<claims_hash>';
```

割り当てはプロファイル、クォータ、またはポリシー自体に記録され、ロールやその他の SQL で作成されたオブジェクトを保持するのと同じ複製アクセストレージ(ClickHouse Cloud では Keeper をバックエンドとします)に保存されます。メモリ上にのみ存在するエフェメラルユーザー側には何も書き込まれません。そのため、トークンの有効期限が切れてユーザーが削除され、次回のログインで新しいユーザーが作成された後も、割り当ては維持されます。実際には、ほとんどのチームがユーザー単位での割り当てをまったく行わないでしょう。プロファイル、クォータ、行ポリシーはロールにも関連付けることができ、トークンが運ぶのはロールであるため、`analyst` ロールに制御を関連付ければ、すべてのアナリストが自動的に対象となります。

<!-- Editorial note from Notion: Add explicit best-practice guidance for assigning profiles, quotas, and row policies to roles instead of inferred JWT users. -->

同じ疑問はビューにも当てはまります。`SQL SECURITY DEFINER` で作成されたビューは、ビューをクエリしたユーザーではなく、ビューを作成したユーザーの権限で実行されます。作成者がエフェメラルユーザーであった場合、そのユーザーのトークンが失効した瞬間にビューは動作しなくなります。そのため、JWT ユーザーが DEFINER ビューを作成すると、ClickHouse は元の名前に `:definer` サフィックスを付けた永続的なシャドウコピーをユーザーとして書き込み、作成時点の権限を保持させつつログインはできない状態にします。それ以降、ビューはそのシャドウユーザーとして実行され、元のトークンがなくなった後も動作し続けます。

## 提供状況

|  | ClickHouse 組み込みオーセンティケーター | カスタムIDプロバイダー |
| --- | --- | --- |
| 主な用途 | SQL Console、`clickhouse-client --login` | OIDC プロバイダーのトークンを持つ任意のクライアント |
| 対象プラン | すべて | Enterprise |
| 最小バージョン | 制限なし | 26.4(EC キーは 26.8) |
| セットアップ | 不要(サービスとともにプロビジョニング) | Cloud コンソールの Settings → Security |

## 発展の基盤として

JWT 認証は、突き詰めればひとつの考え方に集約されます。それは、あなたが誰であり、どのロールを持っているかについての署名付きステートメントを、そのステートメントが有効である限り ClickHouse が信頼するということです。アクセス権はIDプロバイダーが決定します。データベースユーザーは、作成したり削除したりする対象ではなくなります。トークンは、端末の前にいるユーザー、パイプライン、あるいは数分間だけ動作するエージェントに対して、単一のロールに絞り込み、1つのジョブの実行時間だけ有効にするといった柔軟な運用が可能です。

私たちは、JWT 認証を今後も拡張し続けられる基盤であると考えています。署名されたクレームは、検証済みのIDを ClickHouse に渡す汎用的な手法であり、トークンが運ぶ情報、トークンの発行元、そしてそのIDで実行できる権限を、今後もさらに拡張していくことができます。

クレーム、エフェメラルユーザー、およびクライアントの使用方法の詳細については、[JWT 認証のリファレンス](https://clickhouse.com/docs/ja/concepts/features/security/external-authenticators/jwt)をご覧ください。