メインコンテンツまでスキップ
バージョン: 3.19

ユーザーの認証と認可

注記

このページは英語版のページが機械翻訳されたものです。英語版との間に矛盾または不一致がある場合は、英語版を正としてください。

ScalarDB Cluster では、きめ細かい認証と認可を実行できます。ユーザーを作成し、その権限を付与または取り消すことができます。ロールを作成して権限をグループ化し、ユーザーまたは他のロールに付与することもできます。このガイドでは、ScalarDB SQL で認証と認可を使用する方法について説明します。文法の詳細については、DCL を参照してください。

ヒント

プリミティブインターフェースを使用して認証と認可を行うこともできます。詳細については、ClusterClientTransactionAdminを参照してください。これは AuthAdmin を実装しています。

認証方法

ScalarDB Cluster は以下の認証方法をサポートしています:

  • ユーザー名とパスワード (USERPASS): ユーザーはユーザー名とパスワードで認証します。これはこのガイドで説明されているデフォルトの方法です。
  • OIDC (OIDC): クライアントアプリケーションは、パスワードの代わりに OIDC プロバイダー (例: Keycloak) からの JWT アクセストークンを渡します。ABAC と組み合わせることで、JWT クレームがリクエストごとに動的にアクセスを制限できます。詳細については、OIDC ベースの JWT アクセストークンを用いてユーザーアクセスを制御するを参照してください。

ユーザー

ユーザーは、ユーザー名とパスワードを使用して ScalarDB Cluster にログインし、必要な権限を持っている場合に SQL ステートメントを実行できます。

認証と認可では、次の2種類のユーザーがサポートされます:

  • スーパーユーザー: このタイプのユーザーにはすべての権限があります。スーパーユーザーのみが他のユーザーや名前空間を作成または削除できます。
  • 通常のユーザー: このタイプのユーザーには最初は権限がないため、スーパーユーザーまたは GRANT 権限を持つ別のユーザーによって権限を付与する必要があります。

初期ユーザー

認証と認可を有効にすると、初期ユーザー admin が作成され、そのユーザーの初期パスワードは admin になります。このユーザーはスーパーユーザーであり、すべての権限を持ちます。このユーザーでログインし、必要に応じて他のユーザーを作成できます。

警告

セキュリティ上の理由から、特に本番環境にデプロイする前に、初期ユーザーのパスワードを必ず変更してください。

ロール

ロールは、ユーザーまたは他のロールに付与できる権限の名前付きコレクションです。ロールを使用すると、各ユーザーに個別の権限を付与するよりも、複数のユーザーの権限を便利に管理できます。

スーパーユーザーのみがロールを作成または削除できます。GRANT 権限を持つユーザーは、その権限をロールに付与できます。

ロールがユーザーに付与されると、そのユーザーはそのロールに付与されたすべての権限を使用できます。ロールに他のロール (ロール階層) が付与されている場合、ユーザーはそれらのロールからの権限も使用できます。

ロールを付与する際、オプションで WITH ADMIN OPTION を指定して、付与対象者が同じロールを他者に付与できるようにすることができます。

権限

認証と認可を使用する場合、次の権限が利用できます:

  • SELECT
  • INSERT
  • UPDATE
  • DELETE
  • CREATE
  • DROP
  • TRUNCATE
  • ALTER
  • GRANT

各タイプの操作に必要な権限

次の表は、各タイプの操作に必要な権限を示しています:

DDL

コマンドスーパーユーザー権限が必要か必要な権限
CREATE NAMESPACEtrue
DROP NAMESPACEtrue
CREATE TABLECREATE
DROP TABLEDROP
CREATE INDEXCREATE
DROP INDEXDROP
TRUNCATE TABLETRUNCATE
ALTER TABLEALTER
CREATE COORDINATOR TABLEStrue
DROP COORDINATOR TABLEStrue
TRUNCATE COORDINATOR TABLEStrue

DML

コマンドスーパーユーザー権限が必要か必要な権限
SELECTSELECT
INSERTSELECTINSERTUPDATE
UPSERTSELECTINSERTUPDATE
UPDATESELECTINSERTUPDATE
DELETESELECTDELETE
注記

ScalarDB では最初、データを書き込むために UPSERT に対応する Put 操作のみが提供されていました。その結果、内部的には一つの書き込み権限しか存在しません。そのため、INSERTUPDATEUPSERT に必要な権限は同じであり、すべて SELECT 権限が必要です。将来的には、ScalarDB はより細かい書き込み権限の提供を予定しています。

DCL

コマンドスーパーユーザー権限が必要か必要な権限
CREATE USERtrue
ALTER USERtrue (ユーザーは自分のパスワードを変更できます。)
DROP USERtrue
GRANTGRANT (ユーザーは自分が持っている権限のみを付与できます。)
REVOKEGRANT (ユーザーは自分が持っている権限のみを取り消すことができます。)
CREATE ROLEtrue
DROP ROLEtrue
GRANT ... TO ROLEGRANT (ユーザーは自分が持っている権限のみを付与できます。)
REVOKE ... FROM ROLEGRANT (ユーザーは自分が持っている権限のみを取り消すことができます。)
GRANT ROLEロールの ADMIN OPTION (ユーザーはそれらのロールのみを付与できます。)
REVOKE ROLEロールの ADMIN OPTION (ユーザーはそれらのロールのみを取り消すことができます。)
REVOKE ADMIN OPTIONロールの ADMIN OPTION (ユーザーはそれらのロールの ADMIN OPTION のみを取り消すことができます。)

設定

このセクションでは、認証と認可に使用できる設定について説明します。

ScalarDB Cluster ノードの設定

認証と認可を有効にするには、scalar.db.cluster.auth.enabledtrue に設定する必要があります。

名前説明デフォルト
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.enabledtrue に設定する必要があります。

名前説明デフォルト
scalar.db.cluster.auth.enabled認証と認可が有効かどうか。false

ScalarDB Cluster SQL クライアント設定 セクションの設定に加えて、クライアントのユーザー名とパスワードを指定するために scalar.db.sql.cluster_mode.usernamescalar.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-typeTYPE呼び出しの認証方法。値は userpass または oidc_jwt (大文字小文字を区別しない) である必要があります。
auth-userpass-usernameUSERPASS_USERNAMEauth-typeuserpass の場合のユーザー名。必須。
auth-userpass-passwordUSERPASS_PASSWORDauth-typeuserpass の場合のパスワード。パスワードを持たないユーザーはオプション。
auth-oidc-jwt-access-tokenOIDC_JWT_ACCESS_TOKENauth-typeoidc_jwt の場合の JWT アクセストークン。必須。

com.scalar.db.cluster.client.AuthOperationAttributes クラスはこれらのキーを定数として提供していますが、リテラル文字列として指定することもできます。

以下のセクションで説明する場所で auth 属性を渡すことができます。例では userpass 認証タイプを使用しています。oidc_jwt の場合は、auth-typeoidc_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 インターフェースを使用したトランザクションの場合

SqlSessionbegin() または beginReadOnly() メソッドに属性を渡すか、BEGIN または START TRANSACTION ステートメントの WITH 句でキーを指定します。トランザクション内のすべてのステートメントは、指定されたユーザーとして認証されます。

BEGIN WITH 'auth-type' = 'userpass'
AND 'auth-userpass-username' = 'user1'
AND 'auth-userpass-password' = 'password1';

トランザクションマネージャーで直接実行される操作の場合

トランザクションを開始せずにトランザクションマネージャーで直接実行する1回限りの操作の場合は、操作ビルダーの attribute() メソッドを使用して操作自体に属性を設定します。これは、GetScanInsertUpsertUpdateDelete など、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.enabledfalse)、auth 属性は無視され、操作は認証なしで実行されます。そのため、認証と認可が無効な環境にデプロイする場合でも、アプリケーションコードに属性を保持できます。

ワイヤ暗号化

認証と認可を有効にする場合は、ユーザー資格情報を保護するために、本番環境でワイヤ暗号化を有効にすることを強くお勧めします。ワイヤ暗号化の詳細については、ワイヤ通信の暗号化を参照してください。

チュートリアル - ユーザーの認証と認可

このチュートリアルでは、認証と認可の使用方法を説明します。

前提条件

警告

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 として作成します。

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:3.19.0"
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 を使用します。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 を起動します。

java -jar scalardb-cluster-sql-cli-3.19.0-all.jar --config scalardb-cluster-sql-cli.properties

ユーザー名とパスワードをそれぞれ adminadmin と入力します。

これで、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 テーブルで user1SELECTINSERT、および UPDATE 権限を付与します。

GRANT SELECT, INSERT, UPDATE ON ns1.tbl TO user1;

次に、ns2 名前空間の user1SELECT 権限を付与します。

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 | |
+---------+-----------+-----------+---------------+-------------------------+

user1ns1.tbl テーブルに対する SELECTINSERTUPDATE 権限と、ns2 名前空間に対する SELECT 権限が付与されていることがわかります。

8. user1 としてログインする

user1 としてログインし、SQL ステートメントを実行します。

java -jar scalardb-cluster-sql-cli-3.19.0-all.jar --config scalardb-cluster-sql-cli.properties

ユーザー名とパスワードをそれぞれ user1user1 として入力します。

これで、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 |
+----+------+------+

user1INSERT および 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 権限がないため、上記のエラーメッセージが表示されます。

10. ロールを使用して権限を管理する

admin としてログインし、ロールの作成と管理を行います。

java -jar scalardb-cluster-sql-cli-3.19.0-all.jar --config scalardb-cluster-sql-cli.properties

ユーザー名とパスワードをそれぞれ adminadmin として入力します。

cleanup_role という名前のロールを作成します。

CREATE ROLE cleanup_role;

ロールが作成されたことを確認するには、次のコマンドを実行します。

SHOW ROLES;
+--------------+--------------+
| roleName | grantedRoles |
+--------------+--------------+
| cleanup_role | |
+--------------+--------------+

ns1.tbl テーブルの SELECTDELETETRUNCATE 権限をロールに付与します。

GRANT SELECT, DELETE, TRUNCATE ON ns1.tbl TO ROLE cleanup_role;

ロールに付与された権限を確認するには、次のコマンドを実行します。

SHOW ROLE GRANTS FOR cleanup_role;
+---------+-------+-----------+
| name | type | privilege |
+---------+-------+-----------+
| ns1.tbl | TABLE | SELECT |
| ns1.tbl | TABLE | DELETE |
| ns1.tbl | TABLE | TRUNCATE |
+---------+-------+-----------+

ロールを user1 に付与します。

GRANT ROLE cleanup_role TO user1;

user1 の権限を確認するには、次のコマンドを実行します。

SHOW GRANTS FOR user1;
+---------+-----------+-----------+---------------+-------------------------+
| name | type | privilege | grantedToUser | rolesProvidingPrivilege |
+---------+-----------+-----------+---------------+-------------------------+
| ns2 | NAMESPACE | SELECT | true | |
| ns1.tbl | TABLE | SELECT | true | cleanup_role |
| ns1.tbl | TABLE | INSERT | true | |
| ns1.tbl | TABLE | UPDATE | true | |
| ns1.tbl | TABLE | DELETE | false | cleanup_role |
| ns1.tbl | TABLE | TRUNCATE | false | cleanup_role |
+---------+-----------+-----------+---------------+-------------------------+

今度は、user1 としてログインして、再び DELETE ステートメントを試してみます。

java -jar scalardb-cluster-sql-cli-3.19.0-all.jar --config scalardb-cluster-sql-cli.properties

ユーザー名とパスワードをそれぞれ user1user1 として入力します。

DELETE FROM ns1.tbl WHERE id = 1;

今度は、user1cleanup_role ロールを通じて DELETE 権限を持っているため、ステートメントが成功します。

関連情報

RBAC の使用に関する詳細については、ScalarDB SQL 文法リファレンスのロール関連セクションを参照してください。