Shieldを使用してユーザーの権限に応じた検索結果を取得する
Elasticsearchで検索サービスを開発しているお客様から、検索を行うユーザーの権限に応じて検索結果を変えたいという要件を、しばしば伺います。例えば、企業の財務に関するドキュメントは、経理部門のスタッフ以外には、検索結果として表示したくない。顧客情報が含まれる文書は、営業部門やコールセンター部門にアクセスを限定したい、といったケースです。
本プログでは、ユーザーが閲覧を許可されたドキュメントのみ、検索結果として表示させる方法をご紹介します。Elasticのサブスクリプションに含まれるプラグインShieldを使用します。
対象とするElasticsearchのバージョンは2.3.xです。
Shieldのインストール
ElasticsearchやKibanaを起動している場合には、一旦停止します。ターミナルなどでElasticsearchをインストールしたディレクトリに移動し、Shieldをインストールします。
$ bin/plugin install license $ bin/plugin install shield
すでに他のプラグインなどを使用していて、licenseプラグインがインストール済みである場合には、Shieldのインストールのみ、行ってください。
Shieldの設定
ユーザー、ロールなどの追加は、ElasticsearchのAPIを使用して行うことができますが、APIを実行するユーザーは事前に認証されている必要があります。esusers
コマンドで管理者ユーザーを追加します。
$ bin/shield/esusers useradd admin -r admin -p [password]
[password]
には、パスワードとしてふさわしい任意の文字列を指定してください。
Elasticsearchを起動します。
$ bin/elasticsearch
まず、Shieldの認証が正しく機能していることを確認します。curl
コマンドを使用して、ユーザー、パスワードを指定せずにアクセスを試みます。HTTP/1.1 401 Unauthorize
が、メッセージとともに返されます。
$ curl --include localhost:9200 HTTP/1.1 401 Unauthorized WWW-Authenticate: Basic realm="shield" Content-Type: application/json; charset=UTF-8 Content-Length: 329 {"error":{"root_cause":[{"type":"security_exception","reason":"missing authentication token for REST request [/]","header":{"WWW-Authenticate":"Basic realm=\"shield\""}}],"type":"security_exception","reason":"missing authentication token for REST request [/]","header":{"WWW-Authenticate":"Basic realm=\"shield\""}},"status":401}%
次に、先ほど作成したユーザーadmin
でアクセスを試みます。
$ curl localhost:9200 --include --user admin:[password] HTTP/1.1 200 OK Content-Type: application/json; charset=UTF-8 Content-Length: 305 { "name" : "Sushi", "cluster_name" : "v233", "version" : { "number" : "2.3.3", "build_hash" : "218bdf10790eef486ff2c41a3df5cfa32dadcfde", "build_timestamp" : "2016-05-17T15:40:04Z", "build_snapshot" : false, "lucene_version" : "5.5.0" }, "tagline" : "You Know, for Search" }
HTTP/1.1 200 OK
が返されます。
ロールとユーザーの作成
managers
、users
のふたつのロールがある組織を想定します。managers
ロールを割り当てるメンバーとしてjohn_doe
、users
ロールを割り当てるメンバーとしてfred_bloggs
がいます。managers
ロールを割り当てられたメンバーには、managers
のみが閲覧可能なドキュメントと、users
が閲覧可能なドキュメントの両方を検索結果として表示します。users
のメンバーには、明示的にusers
メンバーの閲覧が許されたドキュメントだけを検索結果として返します。
ロールの作成
managers
ロールを作成します。managers
ロールを割り当てられたユーザーは、すべてのindexのaccess_control
フィールドにmanagers
もしくはusers
が含まれるドキュメントのみ、閲覧することができます。
$ curl -XPOST localhost:9200/_shield/role/managers --user admin:[password] -d ' { "cluster": [ "all" ], "indices": [ { "names": [ "sample" ], "privileges": [ "read" ], "query": { "terms": { "access_control": ["managers", "users"] } } } ] }'
同様に、users
ロールを作成します。users
ロールを割り当てられたユーザーは、すべてのindexのaccess_control
フィールドに、users
が含まれるドキュメントのみ、閲覧することができます。
curl -XPOST localhost:9200/_shield/role/users --user admin:[password] -d ' { "cluster": [ "all" ], "indices": [ { "names": [ "sample" ], "privileges": [ "read" ], "query": { "terms": { "access_control": ["users"] } } } ] }'
ユーザーの作成
ユーザーjohn_doe
とfred_bloggs
を作成します。[password]
には、パスワードにふさわしい任意の文字列を指定してください。
curl -XPOST localhost:9200/_shield/user/john_doe --user admin:[password] -d ' { "password" : "[password]", "roles" : [ "managers" ], "full_name" : "John Doe" }'
curl -XPOST /_shield/user/fred_bloggs --user admin:[password] -d ' { "password" : "[password]", "roles" : [ "users" ], "full_name" : "Fred Bloggs" }'
動作の確認
ドキュメントの作成
manager
、users
双方が閲覧可能なドキュメント、managers
のみが閲覧可能なドキュメント、users
のみ明示的に閲覧が許可されたドキュメントをそれぞれ作成します。
curl -XPUT localhost:9200/sample/doc/1 --user admin:[password] -d ' { "access_control": ["managers", "users"], "content": "This document should be readable for managers and users" }'
curl -XPUT localhost:9200/sample/doc/2 --user admin:[password] -d ' { "access_control": ["managers"], "content": "This document should be readable for managers only" }'
curl -XPUT localhost:9200/sample/doc/3 --user admin:[password] -d ' { "access_control": ["users"], "content": "This document should be readable for managers and users" }'
それぞれのユーザーが閲覧可能なドキュメントの確認
最初に、users
ロールを割り当てられたfred_bloggs
による検索結果を取得してみます。
curl 'localhost:9200/sample/_search?pretty' --user fred_bloggs:[password] { "took" : 2, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "hits" : { "total" : 2, "max_score" : 1.0, "hits" : [ { "_index" : "sample", "_type" : "doc", "_id" : "1", "_score" : 1.0, "_source" : { "access_control" : [ "managers", "users" ], "content" : "This document should be readable for managers and users" } }, { "_index" : "sample", "_type" : "doc", "_id" : "3", "_score" : 1.0, "_source" : { "access_control" : [ "users" ], "content" : "This document should be readable for managers and users" } } ] } }
access_control
にusers
が含まれるドキュメントのみ検索結果として現れることが確認できました。次にmanagers
ロールを割り当てられたjohn_doe
で、同様に検索結果を確認します。
$ curl 'localhost:9200/sample/_search?pretty' --user john_doe:[password] { "took" : 1, "timed_out" : false, "_shards" : { "total" : 1, "successful" : 1, "failed" : 0 }, "hits" : { "total" : 3, "max_score" : 1.0, "hits" : [ { "_index" : "sample", "_type" : "doc", "_id" : "1", "_score" : 1.0, "_source" : { "access_control" : [ "managers", "users" ], "content" : "This document should be readable for managers and users" } }, { "_index" : "sample", "_type" : "doc", "_id" : "2", "_score" : 1.0, "_source" : { "access_control" : [ "managers" ], "content" : "This document should be readable for managers only" } }, { "_index" : "sample", "_type" : "doc", "_id" : "3", "_score" : 1.0, "_source" : { "access_control" : [ "users" ], "content" : "This document should be readable for managers and users" } } ] } }
managers
およびusers
がaccess_control
に含まれるドキュメントが、検索結果に含まれることが確認できました。
ユーザー、ロール、およびドキュメントの追加
ユーザーを追加する場合には、そのユーザーに正しいロールを割り当てます。ロールを追加する際には、access_control
を使用してふさわしいクエリーが出来るよう検討します。合わせて、すでにインデックスされているドキュメントの扱いについても考慮します。Elasticsearchにドキュメントを追加する場合には、access_control
に閲覧を許可するロールを付加し、インデックスします。
Active Directory連携
Active Directory連携を行う場合には、Shield上でのロールの定義を不要にすることも可能です。Shieldの認証レルムの設定でunmapped_groups_as_roles: true
を指定します。本設定により、Shieldにロールが存在しない場合には、ユーザーが属するActive Directoryのセキュリティグループ名を、Shieldのロールとして採用します。ユーザーとロールの対応付けが不要になり、運用がより容易になることが期待されます。
shield: authc: realms: active_directory: type: active_directory order: 0 domain_name: example.com url: ldap://ad.example.com:389 unmapped_groups_as_roles: true
まとめ
ロールに基づいたアクセス制御は、Shieldのドキュメントに、より詳しい記載があります。また、Active Directory連係については、こちらのページが参考になります。
Shieldは、当社のサブスクリプションユーザーに提供しているプラグインのひとつです。本エントリにて紹介したアクセス制御はDocument Level Securityと呼ぶもので、Platinumサブスクリプションをご契約のお客様がご利用になれます。サブスクリプションをご契約頂きますと、Shieldの他、特定の条件に応じた際にアラートや通知を行うWatcher、既存のElasticsearchのインデックスを利用して、UIでのデータ探索を可能にするGraphなどもご利用いただけます。当社のElastic Stackの開発者にお問い合わせいただけるほか、お客様の開発工数を削減する、これらの便利なプラグインにもアクセス可能ですので、ぜひご利用ください。