ユーザーの認証と認可
このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。
ScalarDB Cluster では、きめ細かい認証と認可を実行できます。ユーザーを作成し、その権限を付与または取り消すことがで きます。ロールを作成して権限をグループ化し、ユーザーまたは他のロールに付与することもできます。このガイドでは、ScalarDB SQL で認証と認可を使用する方法について説明します。文法の詳細については、DCL を参照してください。
プリミティブインターフェースを使用して認証と認可を行うこともできます。詳細については、認証と認可 APIを参照してください。
認証方法
ScalarDB Cluster は以下の認証方法をサポートしています:
- ユーザー名とパスワード (
USERPASS): ユーザーはユーザー名とパスワードで認証します。これはこのガイドで説明されているデフォルトの方法です。 - OIDC (
OIDC): クライアントアプリケーションは、パスワードの代わりに OIDC プロバイダー (例: Keycloak) からの JWT アクセストークンを渡します。ABAC と組み合わせることで、JWT クレームがリクエストごとに動的にアクセスを制限できます。詳細については、OIDC ベースの JWT アクセストークンを用いてユーザーアクセスを制御するを参照してください。
ユーザー
ユーザーは、ユーザー名とパスワードを使用して ScalarDB Cluster にログインし、必要な権限を持っている場合に SQL ステートメントを実行できます。
認証と認可では、次の2種類のユーザーがサポートされます:
- スーパーユーザー: このタイプのユーザーにはすべての権限があります。スーパーユーザーのみが他のユーザーや名前空間を作成または削除できます。
- 通常のユーザー: このタイプのユーザーには最初は権限がないため、スーパーユーザーまたは
GRANT権限を持つ別のユーザーによって権限を付与する必要があります。
初期ユーザー
認証と認可を有効にすると、初期ユーザー admin が作成され、そのユーザーの初期パスワードは admin になります。このユーザーはスーパーユーザーであり、すべての権限を持ちます。このユーザーでログインし、必要に応じて他のユーザーを作成できます。
セキュリティ上の理由から、特に本番環境にデプロイする前に、初期ユーザーのパスワードを必ず変更してください。
ロール
ロールは、ユーザーまたは他のロールに付与できる権限の名前付きコレクションです。ロールを使用すると、各ユーザーに個別の権限を付与するよりも、複数のユーザーの権限を便利に管理できます。
スーパーユーザーのみがロールを作成または削除できます。GRANT 権限を持つユーザーは、その権限をロールに付与できます。
ロールがユーザーに付与されると、そのユーザーはそのロールに付与されたすべての権限を使用できます。ロールに他のロール (ロール階層) が付与されている場合、ユーザーはそれらのロールからの権限も使用できます。
ロールを付与する際、オプションで WITH ADMIN OPTION を指定して、付 与対象者が同じロールを他者に付与できるようにすることができます。
権限
認証と認可を使用する場合、次の権限が利用できます:
SELECTINSERTUPDATEDELETECREATEDROPTRUNCATEALTERGRANT
各タイプの操作に必要な権限
次の表は、各タイプの操作に必要な権限を示しています:
DDL
| コマンド | スーパーユーザー権限が必要か | 必要な権限 |
|---|---|---|
CREATE NAMESPACE | true | |
DROP NAMESPACE | true | |
CREATE TABLE | CREATE | |
DROP TABLE | DROP | |
CREATE INDEX | CREATE | |
DROP INDEX | DROP | |
TRUNCATE TABLE | TRUNCATE | |
ALTER TABLE | ALTER | |
CREATE COORDINATOR TABLES | true | |
DROP COORDINATOR TABLES | true | |
TRUNCATE COORDINATOR TABLES | true |
DML
| コマンド | スーパーユーザー権限が必要か | 必要な権限 |
|---|---|---|
SELECT | SELECT | |
INSERT | SELECT、INSERT、UPDATE | |
UPSERT | SELECT、INSERT、UPDATE | |
UPDATE | SELECT、INSERT、UPDATE | |
DELETE | SELECT、DELETE |
ScalarDB では最初、データを書き込むために UPSERT に対応する Put 操作のみが提供されていました。その結果、内部的には一つの書き込み権限しか存在しません。そのため、INSERT、UPDATE、UPSERT に必要な権限は同じであり、すべて SELECT 権限が必要です。将来的には、ScalarDB はより細かい書き込み権限の提供を予定しています。
DCL
| コマンド | スーパーユーザー権限が必要か | 必要な権限 |
|---|---|---|
CREATE USER | true | |
ALTER USER | true (ユーザーは自分のパスワードを変更できます。) | |
DROP USER | true | |
GRANT | GRANT (ユーザーは自分が持っている権限のみを付与できます。) | |
REVOKE | GRANT (ユーザーは自分が持っている権限のみを取り消すことができます。) | |
CREATE ROLE | true | |
DROP ROLE | true | |
GRANT ... TO ROLE | GRANT (ユーザーは自分が持っている権限のみを付与できます。) | |
REVOKE ... FROM ROLE | GRANT (ユーザーは自分が持っている権限のみを取り消すことができます。) | |
GRANT ROLE | ロー ルの ADMIN OPTION (ユーザーはそれらのロールのみを付与できます。) | |
REVOKE ROLE | ロールの ADMIN OPTION (ユーザーはそれらのロールのみを取り消すことができます。) | |
REVOKE ADMIN OPTION | ロールの ADMIN OPTION (ユーザーはそれらのロールの ADMIN OPTION のみを取り消すことができます。) |
設定
このセクションでは、認証と認可に使用できる設定について説明します。
ScalarDB Cluster ノードの設定
認証と認可を有効にするには、scalar.db.cluster.auth.enabled を true に設定する必要があります。
| 名前 | 説明 | デフォルト |
|---|---|---|
scalar.db.cluster.auth.enabled | 認証と認可が有効かどうか。 | false |
以下を設定することもできます。
| 名前 | 説明 | デフォルト |
|---|---|---|
scalar.db.cluster.auth.cache_expiration_time_millis | 認証および認可情報のキャッシュ有効期限 (ミリ秒単位)。 | 60000 (1分) |
scalar.db.cluster.auth.auth_token_expiration_time_minutes | 認証お よび認可トークンの有効期限 (分単位)。 | 1440 (1日) |
scalar.db.cluster.auth.auth_token_gc_thread_interval_minutes | 認証および認可トークンのガベージコレクション (GC) スレッド間隔 (分単位)。 | 360 (6時間) |
scalar.db.cluster.auth.pepper | ハッシュ化の前にパスワードに追加されるシークレットの値。指定しない場合、パスワードはペッパーなしでハッシュ化されます。 |
ScalarDB Cluster Java Client SDK 設定
クライアント側で認証と認可を有効にするには、scalar.db.cluster.auth.enabled を true に設定する必要があります。
| 名前 | 説明 | デフォルト |
|---|---|---|
scalar.db.cluster.auth.enabled | 認証と認可が有効かどうか。 | false |
ScalarDB Cluster SQL クライアント設定 セクションの設定に加えて、クライアントのユーザー名とパスワードを指定するために scalar.db.sql.cluster_mode.username と scalar.db.sql.cluster_mode.password も設定する必要があります。
| 名前 | 説明 | デフォルト |
|---|---|---|
scalar.db.sql.cluster_mode.username | クライアントのユーザー名。 | |
scalar.db.sql.cluster_mode.password | クライアントのパスワード。 |
クレデンシャルをプログラムで渡す
クレデンシャルを提供する最も簡単な方法は、設定プロパティで指定することです。userpass 認証タイプの場合はユーザー名とパスワード、oidc_jwt 認証タイプの場合は JWT アクセストークンです。ただし、この方法ではクライアントを単一の ScalarDB ユーザーに固定し、プロパティで設定されたトークンは有効期限が切れてもリフレッシュできません。アプリケーションが実行時に異なる ScalarDB ユーザーとして認証する必要がある場合 (例: 1つのアプリケーションインスタンスが多数のエンドユーザーにサービスを提供する場合)、以下のセクションで説明するように、スレッドごと、トランザクションごと、または操作ごとにプログラムでクレデンシャルを渡すことができます。各メカニズムは両方の認証タイプで機能します。
スレッドごとにクレデンシャルを渡す
クレデンシャルホルダーは、コードブロックの実行中に現在のスレッドのクレデンシャルを設定します。ブロック内のすべての ScalarDB Cluster 操作は、保持されたクレデンシャルで識別されたユーザーとして実行されます。
クライアントの認証タイプがデフォルトの userpass の場合は UserpassHolder を使用します:
import com.scalar.db.cluster.client.UserpassHolder;
UserpassHolder.executeWithUserpass(username, password, () -> {
// このブロック内のすべての ScalarDB Cluster 操作は、指定されたユーザー名とパスワードで認証されたユーザーとして実行されます。
});
クライアントの認証タイプが oidc_jwt の場合は OidcJwtAccessTokenHolder を使用します:
import com.scalar.db.cluster.client.OidcJwtAccessTokenHolder;
OidcJwtAccessTokenHolder.executeWithToken(jwtAccessToken, () -> {
// このブロック内のすべての ScalarDB Cluster 操作は、指定されたトークンからマッピングされたユーザーとして実行されます。
});
ホルダーを使用する際は、以下の点に注意してください:
- クレデンシャルは現在のスレッドにのみ設定されます。他のスレッドには影響しないため、複数のスレッドからホルダーを安全に同時使用できます。
- クレデンシャルはリクエストごとに解決されます。そのため、ブロック内でトランザクションを開始した場合は、ブロック内でコミットまたはロールバックしてください。
- 例外がスローされた場合でも、ブロックが完了するとクレデンシャルは自動的にクリアされます。
- 同じホルダーのネストされた呼び出しはサポートされておらず、
IllegalStateExceptionをスローします。 - 他の認証タイプのホルダーに設定されたクレデンシャルは無視されます。
- ホルダーに設定されたクレデンシャルは、設定プロパティに設定されたクレデンシャルより優先されます。
UserpassHolderの場合、パスワードを持たないユーザーのパスワードはnullに なります。
オペレーション属性としてクレデンシャルを渡す
オペレーション属性を使用して、特定のトランザクション、操作、または SQL ステートメントのクレデンシャルを渡すことができます。オペレーション属性の詳細については、オペレーション属性を参照してください。以下の属性キーは認証クレデンシャル用に予約されています:
| キー | AuthOperationAttributes の定数 | 説明 |
|---|---|---|
auth-type | TYPE | 呼び出しの認証方法。値は userpass または oidc_jwt (大文字小文字を区別しない) である必要があります。 |
auth-userpass-username | USERPASS_USERNAME | auth-type が userpass の場合のユーザー名。必須。 |
auth-userpass-password | USERPASS_PASSWORD | auth-type が userpass の場合のパスワード。パスワードを持たないユーザーはオプション。 |
auth-oidc-jwt-access-token | OIDC_JWT_ACCESS_TOKEN | auth-type が oidc_jwt の場合の JWT アクセストークン。必須。 |
com.scalar.db.cluster.client.AuthOperationAttributes クラスはこれらのキーを定数として提供していますが、リテラル文字列として指定することもできます。
以下のセクションで説明する場所で auth 属性を渡すことができます。例では userpass 認証タイプを使用しています。oidc_jwt の場合は、auth-type を oidc_jwt に設定し、ユーザー名とパスワードのキーの代わりに auth-oidc-jwt-access-token キーを使用して JWT アクセストークンを指定します。
プリミティブインターフェースを使用したトランザクションの場合
トランザクションマネージャーの begin() または beginReadOnly() メソッドに属性を渡します。トランザクション内のすべての操作は、指定されたユーザーとして認証されます。
import com.scalar.db.cluster.client.AuthOperationAttributes;
Map<String, String> attributes = new HashMap<>();
attributes.put(AuthOperationAttributes.TYPE, "userpass");
attributes.put(AuthOperationAttributes.USERPASS_USERNAME, "user1");
attributes.put(AuthOperationAttributes.USERPASS_PASSWORD, "password1");
DistributedTransaction transaction = manager.begin(attributes);
SQL インターフェースを使用したトランザクションの場合
SqlSession の begin() または beginReadOnly() メソッドに属性を渡 すか、BEGIN または START TRANSACTION ステートメントの WITH 句でキーを指定します。トランザクション内のすべてのステートメントは、指定されたユーザーとして認証されます。
BEGIN WITH 'auth-type' = 'userpass'
AND 'auth-userpass-username' = 'user1'
AND 'auth-userpass-password' = 'password1';
トランザクションマネージャーで直接実行される操作の場合
トランザクションを開始せずにトランザクションマネージャーで直接実行する1回限りの操作の場合は、操作ビルダーの attribute() メソッドを使用して操作自体に属性を設定します。これは、Get、Scan、Insert、Upsert、Update、Delete など、attribute() メソッドをサポートする操作ビルダーで機能します。
import com.scalar.db.cluster.client.AuthOperationAttributes;
Insert insert = Insert.newBuilder()
.namespace("ns1")
.table("tbl")
.partitionKey(Key.ofInt("id", 1))
.textValue("col1", "a")
.attribute(AuthOperationAttributes.TYPE, "userpass")
.attribute(AuthOperationAttributes.USERPASS_USERNAME, "user1")
.attribute(AuthOperationAttributes.USERPASS_PASSWORD, "password1")
.build();
manager.insert(insert);
トランザクション外で実行される SQL ステートメントの場合
トランザクションを開始せずに実行する SQL ステートメントの場合は、ステートメントの WITH 句でキーを指定します。これは、プリペアドステートメントを含む WITH 句をサポートする任意のステートメントで機能します。
INSERT INTO ns1.tbl (id, col1) VALUES (1, 'a')
WITH 'auth-type' = 'userpass'
AND 'auth-userpass-username' = 'user1'
AND 'auth-userpass-password' = 'password1';
auth 属性の処理方法
オペレーション属性としてクレデンシャルを渡す際は、以下の点に注意してください:
auth-type属性が空でない値で存在する場合、指定されたクレデンシャルがその呼び出しに使用され、クレデンシャルホルダーによって現在のスレッドに設定されたクレデンシャルおよびクライアント設定プロパティに設定されたクレデンシャルより優先されます。- 上記の場所のいずれかで auth 属性を渡すと、クライアントはリクエストをクラスターに転送する前に属性を削除するため、クレデンシャルはサーバー側のログやエラーメッセージに表示されません。同じ属性マップまたは
WITH句内の他の属性は保持されます。 - auth 属性は上記 の場所でのみ認識されます。トランザクション内で実行される操作や SQL ステートメントなど、他の場所で指定した場合は、クレデンシャルとして解釈されず、通常のオペレーション属性としてクラスターに転送されます。
- 不明な
auth-type値や必須属性の欠落などの無効な値は、リクエストが送信される前にクライアント側でIllegalArgumentExceptionを引き起こします。 executeBatch()メソッドを使用して SQL ステートメントのバッチを実行する場合、最初のステートメントのWITH句にある auth 属性のみが使用され、選択されたクレデンシャルがバッチ全体に適用されます。- 同様に、トランザクションマネージャーで複数の操作を1回の呼び出しで実行する場合 (例:
mutate()メソッドを使用)、最初の操作の auth 属性のみが使用され、選択されたクレデンシャルがその呼び出しのすべての操作に適用されます。 - 認証と認可が無効になっている場合 (
scalar.db.cluster.auth.enabledがfalse)、auth 属性は無視され、操作は認証なしで実行されます。そのため、認証と認可が無効な環境にデプロイする場合でも、アプリケーションコードに属性を保持できます。
ワイヤ暗号化
認証と認可を有効にする場合は、ユーザー資格情報を保護するために、本番環境でワイヤ暗号化を有効にすることを強くお勧めします。ワイヤ暗号化の詳 細については、ワイヤ通信の暗号化を参照してください。
チュートリアル - ユーザーの認証と認可
このチュートリアルでは、認証と認可の使用方法を説明します。
前提条件
- 以下のいずれかの Java Development Kit (JDK):
- Oracle JDK: 8、11、17、または 21 (LTS バージョン)
- OpenJDK ディストリビューション (Eclipse Temurin、Amazon Corretto、または Microsoft Build of OpenJDK): 8、11、17、または 21 (LTS バージョン)
- Docker 20.10以降と Docker Compose V2以降
ScalarDB Cluster を使用するには、ライセンスキー (試用ライセンスまたは商用ライセンス) が必要です。ライセンスキーをお持ちでない場合は、試用ライセンスキーの設定方法に従ってすぐに使える試用ライセンスキーをご利用いただけます。商用ライセンスを取得するには、お問い合わせください。
1. ScalarDB Cluster 設定ファイルを作成する
次の設定ファイルを scalardb-cluster-node.properties として作成し、<YOUR_LICENSE_KEY> と <LICENSE_CHECK_CERT_PEM> を ScalarDB ライセンスキーとライセンスチェック証明書の値に置き換えます。ライセンスキーと証明書の詳細については、製品ライセンスキーの設定方法を参照してく ださい。
scalar.db.storage=jdbc
scalar.db.contact_points=jdbc:postgresql://postgresql:5432/postgres
scalar.db.username=postgres
scalar.db.password=postgres
scalar.db.cluster.node.standalone_mode.enabled=true
scalar.db.sql.enabled=true
# Enable cross-partition scan to perform a full scan by using the SELECT statements in this tutorial.
# This is not required for authentication and authorization itself.
scalar.db.cross_partition_scan.enabled=true
# Enable authentication and authorization
scalar.db.cluster.auth.enabled=true
# License key configurations
scalar.db.cluster.node.licensing.license_key=<YOUR_LICENSE_KEY>
scalar.db.cluster.node.licensing.license_check_cert_pem=<LICENSE_CHECK_CERT_PEM>
2. Docker Compose ファイルを作成する
次の設定ファイルを docker-compose.yaml として作成します。<X.Y.Z> は使用したい ScalarDB Cluster のバージョンに置き換えてください。
services:
postgresql:
container_name: "postgresql"
image: "postgres:15"
ports:
- 5432:5432
environment:
- POSTGRES_PASSWORD=postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready || exit 1"]
interval: 1s
timeout: 10s
retries: 60
start_period: 30s
scalardb-cluster-standalone:
container_name: "scalardb-cluster-node"
image: "ghcr.io/scalar-labs/scalardb-cluster-node-byol-premium:<X.Y.Z>"
ports:
- 60053:60053
- 9080:9080
volumes:
- ./scalardb-cluster-node.properties:/scalardb-cluster/node/scalardb-cluster-node.properties
depends_on:
postgresql:
condition: service_healthy
3. PostgreSQL と ScalarDB Cluster を起動します
次のコマンドを実行して、PostgreSQL と ScalarDB Cluster をスタンドアロンモードで起動します。
docker compose up -d
4. ScalarDB Cluster に接続する
ScalarDB Cluster に接続するために、このチュートリアルでは、ScalarDB Cluster に接続して SQL クエリを実行するツールである SQL CLI を使用します。使用してい る ScalarDB Cluster のバージョンに一致する SQL CLI を、ScalarDB Releases ページからダウンロードしてください。
scalardb-cluster-sql-cli.properties という名前の設定ファイルを作成します。このファイルは、SQL CLI を使用して ScalarDB Cluster に接続するために使用されます。
scalar.db.sql.connection_mode=cluster
scalar.db.sql.cluster_mode.contact_points=indirect:localhost
# Enable authentication and authorization
scalar.db.cluster.auth.enabled=true
次に、次のコマンドを実行して SQL CLI を起動します。<X.Y.Z> は事前にダウンロードしたバージョンに置き換えてください。
java -jar scalardb-cluster-sql-cli-<X.Y.Z>-all.jar --config scalardb-cluster-sql-cli.properties
ユーザー名とパスワードをそれぞれ admin と admin と入力します。
これで、ScalarDB Cluster で認証と認可を有効にしてデータベースを使用する準備が整いました。
5. 名前空間とテーブルを作成する
名前空間を作成します。
CREATE NAMESPACE ns1;
CREATE NAMESPACE ns2;
次に、ns1 名前空間にテーブルを作成します。
CREATE TABLE ns1.tbl (
id INT PRIMARY KEY,
col1 TEXT,
col2 INT);
6. ユーザーを作成する
user1 という名前のユーザーを作成します。
CREATE USER user1 WITH PASSWORD 'user1';
ユーザーを確認するには、次のコマンドを実行します。
SHOW USERS;
+----------+-------------+-----------------------+
| username | isSuperuser | authenticationMethods |
+----------+-------------+-----------------------+
| user1 | false | USERPASS |
| admin | true | USERPASS |
+----------+-------------+-----------------------+
user1 ユーザーが作成されたことがわかります。
7. 権限の付与
ns1.tbl テーブルで user1 に SELECT、INSERT、および UPDATE 権限を付与します。
GRANT SELECT, INSERT, UPDATE ON ns1.tbl TO user1;
次に、ns2 名前空間の user1 に SELECT 権限を付与します。
GRANT SELECT ON NAMESPACE ns2 TO user1;
権限を確認するには、次のコマンドを実行します。
SHOW GRANTS FOR user1;
+---------+-----------+-----------+---------------+-------------------------+
| name | type | privilege | grantedToUser | rolesProvidingPrivilege |
+---------+-----------+-----------+---------------+-------------------------+
| ns2 | NAMESPACE | SELECT | true | |
| ns1.tbl | TABLE | SELECT | true | |
| ns1.tbl | TABLE | INSERT | true | |
| ns1.tbl | TABLE | UPDATE | true | |
+---------+-----------+-----------+---------------+-------------------------+
user1 に ns1.tbl テーブルに対する SELECT、INSERT、UPDATE 権限と、ns2 名前空間に対する SELECT 権限が付与されていることがわかります。
8. user1 としてログインする
user1 としてログインし、SQL ステートメントを実行します。
java -jar scalardb-cluster-sql-cli-<X.Y.Z>-all.jar --config scalardb-cluster-sql-cli.properties
ユーザー名とパスワードをそれぞれ user1 と user1 として入力します。
これで、user1 として SQL ステートメントを実行できます。
9. DML ステートメントを実行する
user1 として次の INSERT ステートメントを実行します。
INSERT INTO ns1.tbl VALUES (1, 'a', 1);
次に、user1 として次の SELECT ステートメントを実行します。
SELECT * FROM ns1.tbl;
+----+------+------+
| id | col1 | col2 |
+----+------+------+
| 1 | a | 1 |
+----+------+------+
user1 が INSERT および SELECT ステートメントを実行できることがわかります。
次に、user1 として次の DELETE ステートメントを実行してみてください。
DELETE FROM ns1.tbl WHERE id = 1;
Error: Authorization error (PERMISSION_DENIED: SQL-10021: Access denied: You need the DELETE privilege on the table ns1.tbl to execute this operation) (state=SDB11,code=9911)
user1 には ns1.tbl テーブルに対する DELETE 権限がないため、上記のエラーメッセージが表示されます。