CLOVER🍀

That was when it all began.

Elasticsearch(シングルノード)で、認証・認可設定をする

これは、なにをしたくて書いたもの?

Elasticsearchのセキュリティまわりを勉強しようかなぁと思いまして。まずは、認証からかな、と。

無料の暗号化とユーザー認証で、Elasticsearchクラスターを安全に保つ | Elastic Blog

SSL、TLS、HTTPSを設定してElasticsearch/Kibana/Beats/Logstashを安全に保つ | Elastic Blog

Elasticsearchをシングルノードで使うか、クラスタを構成するかで、X-Packのセキュリティに関する要件が変わるようなので、
今回はシングルノードで認証・認可に限定して試してみたいと思います。

This requirement applies to clusters with more than one node and to clusters with a single node that listens on an external interface. Single-node clusters that use a loopback interface do not have this requirement. For more information, see Encrypting communications.

Configuring security in Elasticsearch | Elasticsearch Reference [7.5] | Elastic

環境

今回の環境は、こちら。

$ java --version
openjdk 11.0.5 2019-10-15
OpenJDK Runtime Environment (build 11.0.5+10-post-Ubuntu-0ubuntu1.118.04)
OpenJDK 64-Bit Server VM (build 11.0.5+10-post-Ubuntu-0ubuntu1.118.04, mixed mode, sharing)


$ curl localhost:9200
{
  "name" : "ubuntu1804.localdomain",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "ZY8nisNbQZmYufnGTBi79Q",
  "version" : {
    "number" : "7.5.2",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "8bec50e1e0ad29dad5653712cf3bb580cd1afcdf",
    "build_date" : "2020-01-15T12:11:52.313576Z",
    "build_snapshot" : false,
    "lucene_version" : "8.3.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Elasticsearch 7.5.2です。

設定は、まずはこんな感じで。

$ sudo grep -vE '^ *#|^$' /etc/elasticsearch/elasticsearch.yml
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: 0.0.0.0
discovery.type: "single-node"

X-Pack Securityを有効にして、認証・認可に関する設定を行う

まずは、X-PackのSecurityを有効にする必要があります。

認証・認可に関する設定の流れは、こちらに書いています。

Configuring security in Elasticsearch | Elasticsearch Reference [7.5] | Elastic

Basicサブスプリクションでも、すべてのX-Pack Securityに関する機能が使えるわけではないですが、ある程度は利用することができます。

サブスクリプション | Elastic Stackプロダクトとサポート | Elastic

X-Pack Securityに関する設定は、こちら。

Security settings in Elasticsearch | Elasticsearch Reference [7.5] | Elastic

認証・認可、SSL/TLSに関するドキュメントは、こちら。

User authentication | Elasticsearch Reference [7.5] | Elastic

User authorization | Elasticsearch Reference [7.5] | Elastic

Encrypting communications | Elasticsearch Reference [7.5] | Elastic

とりあえず、認証・認可の設定を行ってみましょう。

まずは、X-Pack Securityを有効にします。

xpack.security.enabled: true

Elasticsearchを再起動します。

$ sudo systemctl restart elasticsearch

この時点で、Elasticsearchにアクセスするのに認証が必要になっています。

$ curl localhost:9200?pretty
{
  "error" : {
    "root_cause" : [
      {
        "type" : "security_exception",
        "reason" : "missing authentication credentials for REST request [/?pretty]",
        "header" : {
          "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
        }
      }
    ],
    "type" : "security_exception",
    "reason" : "missing authentication credentials for REST request [/?pretty]",
    "header" : {
      "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
    }
  },
  "status" : 401
}

ステータスコード401が返却されました。

次に、ビルドインユーザーのパスワード設定をします。

elasticsearch-setup-passwords | Elasticsearch Reference [7.5] | Elastic

ビルドインユーザーとは、こちらに書かれているユーザーのことです。

Built-in users | Elasticsearch Reference [7.5] | Elastic

「elastic」が管理ユーザー、その他は、たとえばLogstashやBeatsからElasticsearchに接続する際に使用するユーザーです。

パスワードは、今回は「interactive」を指定して、自分で明示します。

$ sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive

「interactive」ではなく「auto」にすると、ビルトインユーザーのパスワードが自動生成されます。

また「-u」オプションで、別のホストだったり、アクセスするプロトコルをHTTPSに変えるといった指定の仕方もしたりします。

$ sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive -u https://[elasticsearch-host]:9200

で、パスワード設定。今回は、一律「password」にしました。

Initiating the setup of passwords for reserved users elastic,apm_system,kibana,logstash_system,beats_system,remote_monitoring_user.
You will be prompted to enter passwords as the process progresses.
Please confirm that you would like to continue [y/N]y


Enter password for [elastic]: 
Reenter password for [elastic]: 
Enter password for [apm_system]: 
Reenter password for [apm_system]: 
Enter password for [kibana]: 
Reenter password for [kibana]: 
Enter password for [logstash_system]: 
Reenter password for [logstash_system]: 
Enter password for [beats_system]: 
Reenter password for [beats_system]: 
Enter password for [remote_monitoring_user]: 
Reenter password for [remote_monitoring_user]: 
Changed password for user [apm_system]
Changed password for user [kibana]
Changed password for user [logstash_system]
Changed password for user [beats_system]
Changed password for user [remote_monitoring_user]
Changed password for user [elastic]

「elastic」ユーザーを使って、再度Elasticsearchにアクセスすると、今度はアクセス可能になっています。

$ curl -u elastic:password localhost:9200?pretty
{
  "name" : "ubuntu1804.localdomain",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "ZY8nisNbQZmYufnGTBi79Q",
  "version" : {
    "number" : "7.5.2",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "8bec50e1e0ad29dad5653712cf3bb580cd1afcdf",
    "build_date" : "2020-01-15T12:11:52.313576Z",
    "build_snapshot" : false,
    "lucene_version" : "8.3.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

ビルトインユーザーの情報は、「.security」インデックスに入っているみたいです。

How the built-in users work

$ curl -u elastic:password localhost:9200/_cat/indices?v
health status index       uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .security-7 y1BdDpirSX2g-hYkJp6uhg   1   0          6            0     20.1kb         20.1kb

今回は必須ではありませんが、Realmの設定方法も少し見てみましょう。

ここでは、Native Realmを見てみます。Native Realmは、REST APIやKibanaを使ってユーザーを管理することができるRealmで、
もっとも簡単なものになります。

Native user authentication | Elasticsearch Reference [7.5] | Elastic

Native Realmに関する設定は、こちら。

Native realm setting

ドキュメントに習って、Native Realmを最初に確認するようにしてみましょう。ここで指定している「reaml1」というのは、任意で
指定するRealmの名前みたいです。

xpack.security.enabled: true
xpack.security.authc.realms:
  native:
    realm1:
      order: 0

Realmの設定は、Nodeに関する情報を取得すると見ることができました。

$ curl -u elastic:password localhost:9200/_nodes?pretty

次に、権限設定をしてみましょう。クラスタ、インデックスに関する権限があるようです。

Security privileges | Elasticsearch Reference [7.5] | Elastic

REST APIを使って、ロールやユーザーの作成などを行うことができます。

Security APIs | Elasticsearch Reference [7.5] | Elastic

最初に、あるインデックスパターンに対する管理者的なロールを作成してみます。ロールの内容はJSONで指定し、ロール名は
URLパスの末尾で指定する形です。

$ curl -XPOST -u elastic:password  -H 'Content-Type: application/json' 'localhost:9200/_security/role/my-index-admin-role' -d '{
  "indices" : [
    {
      "names" : [ "my-index*" ],
      "privileges" : [ "all" ]
    },
    {
      "names" : [ ".kibana*" ],
      "privileges" : [ "manage", "read", "index" ]
    }
  ]
}
'

インデックスに関する権限を指定し、「my-index*」というパターンに対してすべての権限を、「.kibana」に関しては「manage」、
「read」、「index」権限(ドキュメントのサンプルのまま)を与えます。

次に、「my-index*」パターンに対して、参照のみが可能なロールを作成してみます。

$ curl -XPOST -u elastic:password  -H 'Content-Type: application/json' 'localhost:9200/_security/role/my-index-read-only-role' -d '{
  "indices" : [
    {
      "names" : [ "my-index*" ],
      "privileges" : [ "read" ]
    }
  ]
}
'

これらのロールを持ったユーザーを、それぞれ作成します。ロールと同じく、ユーザーの情報はJSONで指定して、ユーザー名はURLの
末尾になります。

$ curl -XPOST -u elastic:password -H 'Content-Type: application/json' 'localhost:9200/_security/user/admin-user' -d '{
  "password" : "admin-password",
  "full_name" : "Admin User",
  "email" : "admin@example.com",
  "roles" : [ "my-index-admin-role" ]
}
'

$ curl -XPOST -u elastic:password -H 'Content-Type: application/json' 'localhost:9200/_security/user/read-only-user' -d '{
  "password" : "read-only-password",
  "full_name" : "ReadOnly User",
  "email" : "read_only@example.com",
  "roles" : [ "my-index-read-only-role" ]
}
'

では、「my-index-1」というインデックスに対して、ドキュメントを登録してみましょう。

ユーザー指定なしでアクセス。

$ curl -XPUT -H 'Content-Type: application/json' 'localhost:9200/my-index-1/_doc/1?pretty' -d'
{
  "name": "Taro"
}
'

こちらは、認証していないのでエラーになります。

{
  "error" : {
    "root_cause" : [
      {
        "type" : "security_exception",
        "reason" : "missing authentication credentials for REST request [/my-index-1/_doc/1?pretty]",
        "header" : {
          "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
        }
      }
    ],
    "type" : "security_exception",
    "reason" : "missing authentication credentials for REST request [/my-index-1/_doc/1?pretty]",
    "header" : {
      "WWW-Authenticate" : "Basic realm=\"security\" charset=\"UTF-8\""
    }
  },
  "status" : 401
}

管理者ロールを持ったユーザーでドキュメントを登録してみます。

$ curl -XPUT -u admin-user:admin-password -H 'Content-Type: application/json' 'localhost:9200/my-index-1/_doc/1?pretty' -d'
{
  "name": "Taro"
}
'

こちらは成功します。

{
  "_index" : "my-index-1",
  "_type" : "_doc",
  "_id" : "1",
  "_version" : 1,
  "result" : "created",
  "_shards" : {
    "total" : 2,
    "successful" : 1,
    "failed" : 0
  },
  "_seq_no" : 0,
  "_primary_term" : 1
}

参照は、管理者ロールを持ったユーザー、読み取り権限のみのロールを持ったユーザーのいずれでも可能です。

$ curl -u admin-user:admin-password localhost:9200/my-index-1/_doc/1?pretty


$ curl -u read-only-user:read-only-password localhost:9200/my-index-1/_doc/1?pretty

読み取り権限のみのロールを持ったユーザーで、ドキュメントの登録を試みてみましょう。

$ curl -XPUT -u read-only-user:read-only-password -H 'Content-Type: application/json' 'localhost:9200/my-index-1/_doc/2?pretty' -d'
{
  "name": "Jiro"
}
'

認証はできているけれど、書き込み権限がないのでエラーになりました。

{
  "error" : {
    "root_cause" : [
      {
        "type" : "security_exception",
        "reason" : "action [indices:data/write/index] is unauthorized for user [read-only-user]"
      }
    ],
    "type" : "security_exception",
    "reason" : "action [indices:data/write/index] is unauthorized for user [read-only-user]"
  },
  "status" : 403
}

ステータスコードも、403ですし。

ユーザーに指定したロール(に含まれる権限)が、有効になっていることが確認できましたね。

監査ログ

あと、監査ログに関する設定もあるみたいですが、今回はパス。

Enabling audit logging | Elasticsearch Reference [7.5] | Elastic

まとめ

Elasticsearchで、シングルノードにおけるX-Pack Securityの有効化と、認証・認可を試してみました。

とりあえず、基礎的なことはわかった気がするので、今度はクラスタを構成したり、SSL/TLSまわりに踏み込んでみようかなと
思います。