hive.server2.enable.doAs がよく分からなかったので Apache Bigtop で調べてみた

hive.server2.enable.doAs の設定によって何がどう変わるかよく分からなかったので Apache Bigtop を使って調べてみました。

hive.server2.enable.doAs だと長くて煩雑なので以下では適宜 doAs と略しています。


まとめ

先にまとめ。 調べた結果を基に書いていますが、厳密な裏付けはありません (ソースを読んで調べたりはしていません)。

  • proxy user というしくみがある
    • Apache Hadoop 2.8.5 – Proxy user - Superusers Acting On Behalf Of Other Users
    • hiveserver2 のプロセスを実行しているユーザではなく、 他のユーザになりすましてジョブの submit や HDFS へのアクセスを行うしくみ
    • (Hive ではなく)Hadoop の機能
      • core-site.xmlhadoop.proxyuser.〜 で設定する
    • hive.server2.enable.doAs が false の場合、なりすましを行わず、 hiveserver2 のプロセスを実行しているユーザで操作が実行される
  • なりすましを行うには、下記の両方が必要
    • OSのユーザとして存在している
    • core-site.xml の proxyuser の設定に対象ユーザが含まれている(※1)
  • beeline の場合は、なりすましたいユーザ名を -n オプションで指定する
  • なりすましを行うと、HDFS上で作られるデータベースやテーブルのディレクトリ、データファイルの所有者がそのユーザになる

hive.server2.enable.doAs で設定しているのは要するに何なのかということで言えば、「Hadoop の proxy user 機能を利用するかどうか」と思ってよさそうな挙動でした。なので、利用する場合は proxy user についても知る必要があります。

※1 Apache Hadoop 2.8.5 – Proxy user - Superusers Acting On Behalf Of Other Users によれば、ホストによる指定、グループによる指定、ユーザによる指定を組み合わせて指定できるようです。

バージョンなど

Bigtop は下記の時点の master を使っています。

34e0bd7182c713b16dce9a4bdc803c8ed7fb9eb3
Thu Jun 11 09:01:26 2020 +0000

一応公式の説明

Setting Up HiveServer2 - Apache Hive - Apache Software Foundation

Impersonation

By default HiveServer2 performs the query processing as the user who submitted the query. But if the following parameter is set to false, the query will run as the user that the hiveserver2 process runs as.

hive.server2.enable.doAs – Impersonate the connected user, default true.

impersonate は「なりすます」という意味。エラーメッセージでも出てきます。

調査1: doAsの設定による違い

準備

設定を変えてプロビジョニングしなおすのを繰り返すやり方だと時間がかかってしまうので、Bigtop のリポジトリをクローンしたディレクトリを2つ用意して true/false それぞれの設定にします。

デフォルトでは true なので、false の方のディレクトリのみ hive-site.xml を修正。

--- a/bigtop-deploy/puppet/modules/hadoop_hive/templates/hive-site.xml
+++ b/bigtop-deploy/puppet/modules/hadoop_hive/templates/hive-site.xml
@@ -81,7 +81,7 @@
 
 <property>
    <name>hive.server2.enable.doAs</name>
-   <value>true</value>
+   <value>false</value>
 </property>
 
 <property>

config_centos-7.yaml を修正して Hive コンポーネントを追加。

--- a/provisioner/docker/config_centos-7.yaml
+++ b/provisioner/docker/config_centos-7.yaml
@@ -19,6 +19,6 @@ docker:
 
 repo: "http://repos.bigtop.apache.org/releases/1.4.0/centos/7/$basearch"
 distro: centos
-components: [hdfs, yarn, mapreduce]
+components: [hdfs, yarn, mapreduce, hive]
 enable_local_repo: false
 smoke_test_components: [hdfs, yarn, mapreduce]

設定の変更はこれだけ。


単一ノードで create します。

time ./docker-hadoop.sh -C config_centos-7.yaml --create 1

これで Hadoop と Hive が使えるようになります。 Bigtop すばらしい……ありがたや……。


コンテナに入る。

./docker-hadoop.sh --exec 1 bash

以下、コンテナ内の作業。


testuser というユーザがすでに存在しているので、そっちにスイッチします。 (こういう用途で使うために用意されているものなのか分かっていませんが、とりあえず一般ユーザのつもりで使います)

su - testuser

接続

beeline で hiverserver2 に接続

beeline -u "jdbc:hive2://localhost:10000"
  • doAs=false の場合: 接続に成功する。
  • doAs=true の場合: 接続に失敗して次のようなメッセージが出ます(適宜改行を加えています)。
Error: Could not open client transport with JDBC Uri: 
jdbc:hive2://localhost:10000: Failed to open new session: 
java.lang.RuntimeException: 
org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): 
User: hive is not allowed to impersonate anonymous (state=08S01,code=0)

この場合は -n オプションでユーザ名を指定すると接続できるようになります。

beeline -u "jdbc:hive2://localhost:10000" -n testuser

ちなみに、Bigtop の既定の設定では hiveserver2 は hive ユーザで実行されますが、hiveserver2 を root ユーザで実行すると次のようなメッセージになります。

User: root is not allowed to impersonate anonymous (state=08S01,code=0)
      ^^^^
      ここが変わる

「hiveserver2 の実行ユーザが他のユーザになりすます」ということが試みられているようです。


OSに存在しないユーザ名を指定した場合

beeline -u "jdbc:hive2://localhost:10000" -n nobody
  • doAs=false の場合: 接続に成功する。
  • doAs=true の場合: 接続に失敗する。

doAs=false の場合、 -n オプションによる指定はいずれにせよ無視されるということでしょうか。

create databse

doAs=true の場合

$ beeline -u "jdbc:hive2://localhost:10000" -n testuser

create database test_db1;
  => 成功する

$ hdfs dfs -ls /user/hive/warehouse
Found 1 items
drwxrwxrwx   - testuser hadoop          0 2020-06-27 05:38 /user/hive/warehouse/test_db1.db

所有者=testuser でデータベースのディレクトリが作られました。

doAs=false の場合

一応 -n testuser を付けてみます。

$ beeline -u "jdbc:hive2://localhost:10000" -n testuser

create database test_db1;
  => 成功する

$ hdfs dfs -ls /user/hive/warehouse
Found 1 items
drwxrwxrwx   - hive hadoop          0 2020-06-27 05:41 /user/hive/warehouse/test_db1.db

やはり -n の指定は無視され、所有者=hive でディレクトリが作られました。

create table + insert

doAs=true の場合

$ beeline -u "jdbc:hive2://localhost:10000" -n testuser

use test_db1;
create table test1 (name string);
insert into test1 values ('foo'), ('bar');

Error: org.apache.hive.service.cli.HiveSQLException: Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask. Permission denied: user=testuser, access=WRITE, inode="/user":hdfs:hadoop:drwxr-xr-x

insert 時に /userパーミッションで怒られました。 ちなみに test1 テーブルは 所有者=testuser で作られています。

$ hdfs dfs -ls /user/hive/warehouse/test_db1.db
Found 1 items
drwxrwxrwx   - testuser hadoop          0 2020-06-27 09:48 /user/hive/warehouse/test_db1.db/test1

hdfs:///user に実行権限を付けて再度 insert。

# sudo -u hdfs hdfs dfs -chmod 777 /user
$ beeline -u "jdbc:hive2://localhost:10000" -n testuser

use test_db1;
insert into test1 values ('foo'), ('bar');

今度は成功しました。

$ hdfs dfs -ls /user/hive/warehouse/test_db1.db/test1
Found 1 items
-rwxrwxrwx   3 testuser hadoop          8 2020-06-27 09:55 /user/hive/warehouse/test_db1.db/test1/000000_0

$ hdfs dfs -text /user/hive/warehouse/test_db1.db/test1/000000_0
foo
bar

データは所有者=testuser で作られています。

doAs=false の場合

$ beeline -u "jdbc:hive2://localhost:10000" -n testuser

use test_db1;
create table test1 (name string);
insert into test1 values ('foo'), ('bar');

こちらはエラーになりませんでした。

$ hdfs dfs -ls /user/hive/warehouse/test_db1.db
Found 1 items
drwxrwxrwx   - hive hadoop          0 2020-06-27 09:58 /user/hive/warehouse/test_db1.db/test1

$ hdfs dfs -ls /user/hive/warehouse/test_db1.db/test1
Found 1 items
-rwxrwxrwx   3 hive hadoop          8 2020-06-27 09:58 /user/hive/warehouse/test_db1.db/test1/000000_0

テーブルのディレクトリとデータは所有者=hive で作られています。

create external table + insert

doAs=true の場合

table_ext というテーブルを作り、 /user/testuser の下にデータを置くことにします。

$ hdfs dfs -ls /user
...
drwx------   - testuser hadoop          0 2020-06-27 09:54 /user/testuser
...
beeline -u "jdbc:hive2://localhost:10000" -n testuser

use test_db1;
create external table table_ext (name string)
  location '/user/testuser/table_ext/';
insert into table table_ext values ('foo'), ('bar');
$ hdfs dfs -ls /user/testuser/
Found 2 items
drwx------   - testuser hadoop          0 2020-06-27 10:22 /user/testuser/.staging
drwx------   - testuser hadoop          0 2020-06-27 10:22 /user/testuser/table_ext


$ hdfs dfs -ls /user/testuser/table_ext
Found 1 items
-rwx------   3 testuser hadoop          8 2020-06-27 10:22 /user/testuser/table_ext/000000_0

$ hdfs dfs -text /user/testuser/table_ext/000000_0
foo
bar

doAs=false の場合

こちらは hdfs:///user/testuser/ ディレクトリが存在しなかったので、 hdfs:///tmp/ の下にデータを置くことにします。

beeline -u "jdbc:hive2://localhost:10000" -n testuser

use test_db1;
create external table table_ext (name string)
  location '/tmp/table_ext/';
insert into table table_ext values ('foo'), ('bar');
$ hdfs dfs -ls /tmp/
Found 3 items
drwxrwxrwx   - mapred mapred          0 2020-06-27 04:55 /tmp/hadoop-yarn
drwx-wx-wx   - hive   hadoop          0 2020-06-27 04:56 /tmp/hive
drwxrwxrwt   - hive   hadoop          0 2020-06-27 10:29 /tmp/table_ext

$ hdfs dfs -ls /tmp/table_ext
Found 1 items
-rwxrwxrwt   3 hive hadoop          8 2020-06-27 10:29 /tmp/table_ext/000000_0

$ hdfs dfs -text /tmp/table_ext/000000_0
foo
bar

調査2: OSのユーザとproxy userの関係

doAs=false の場合の挙動はなんとなく分かってきましたが、 doAs=true の場合のOSのユーザとの関係がよく分からないので、こんどはそこを調べてみます。

Hadoop の proxy user というしくみが関わっているようだったので、 次の3パターンでどうなるか試します。

  • user_os: OS のユーザのみ存在
  • user_proxyuser: proxy user の設定のみ
  • user_both: OS のユーザが存在し、かつ proxy user の設定もあり
    • おそらく testuser と同等

データの配置場所が変わるだけだと思われたので外部テーブルについては省略。


設定ファイルを修正。下記は master からの差分です。 Puppet に詳しくないので、 testuser を grep したりして当たりを付けて適当に修正しました。

--- a/bigtop-deploy/puppet/manifests/cluster.pp
+++ b/bigtop-deploy/puppet/manifests/cluster.pp
@@ -159,7 +159,7 @@ $roles_map = {
 
 class hadoop_cluster_node (
   $hadoop_security_authentication = hiera("hadoop::hadoop_security_authentication", "simple"),
-  $bigtop_real_users = [ 'jenkins', 'testuser', 'hudson' ],
+  $bigtop_real_users = [ 'jenkins', 'testuser', 'hudson', 'user_os', 'user_both' ],
   $cluster_components = ["all"]
   ) {

--- a/bigtop-deploy/puppet/modules/hadoop/manifests/init.pp
+++ b/bigtop-deploy/puppet/modules/hadoop/manifests/init.pp
@@ -20,7 +20,7 @@ class hadoop ($hadoop_security_authentication = "simple",
   $hadoop_storage_dirs = split($::hadoop_storage_dirs, ";"),
   $proxyusers = {
     oozie => { groups => 'hudson,testuser,root,hadoop,jenkins,oozie,hive,httpfs,users', hosts => "*" },
-     hive => { groups => 'hudson,testuser,root,hadoop,jenkins,oozie,hive,httpfs,users', hosts => "*" },
+     hive => { groups => 'hudson,testuser,user_both,user_proxyuser,root,hadoop,jenkins,oozie,hive,httpfs,users', hosts => "*" },
    httpfs => { groups => 'hudson,testuser,root,hadoop,jenkins,oozie,hive,httpfs,users', hosts => "*" } },
   $generate_secrets = false,
   $kms_host = undef,

--- a/provisioner/docker/config_centos-7.yaml
+++ b/provisioner/docker/config_centos-7.yaml
@@ -19,6 +19,6 @@ docker:
 
 repo: "http://repos.bigtop.apache.org/releases/1.4.0/centos/7/$basearch"
 distro: centos
-components: [hdfs, yarn, mapreduce]
+components: [hdfs, yarn, mapreduce, hive]
 enable_local_repo: false
 smoke_test_components: [hdfs, yarn, mapreduce]

あと、調査1のときと同様に hdfs:///userパーミッションを変更しておきます。

# hdfs dfs -ls / | grep /user
drwxr-xr-x   - hdfs  hadoop          0 2020-06-28 03:13 /user
# sudo -u hdfs hdfs dfs -chmod 777 /user

OSユーザあり、proxy user 設定なし

# su - user_os

$ beeline -u "jdbc:hive2://localhost:10000" -n user_os

Error: Could not open client transport with JDBC Uri: jdbc:hive2://localhost:10000: Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hive is not allowed to impersonate user_os (state=08S01,code=0)

接続できない。

OSユーザなし、proxy user 設定あり

testuser を使います。

# su - testuser

$ beeline -u "jdbc:hive2://localhost:10000" -n user_proxyuser

Error: Could not open client transport with JDBC Uri: jdbc:hive2://localhost:10000: Failed to open new session: java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.security.authorize.AuthorizationException): User: hive is not allowed to impersonate user_proxyuser (state=08S01,code=0)

接続できない。

OSユーザあり、proxy user 設定あり

# su - user_both
$ beeline -u "jdbc:hive2://localhost:10000" -n user_both

create database user_both_db;
use user_both_db;
create table table1 (name string);
insert into table1 values ('foo'), ('bar');

insert まで成功しました。

$ hdfs dfs -ls /user/hive/warehouse/
Found 1 items
drwxrwxrwx   - user_both hadoop          0 2020-06-28 03:19 /user/hive/warehouse/user_both_db.db

$ hdfs dfs -ls /user/hive/warehouse/user_both_db.db/
Found 1 items
drwxrwxrwx   - user_both hadoop          0 2020-06-28 03:22 /user/hive/warehouse/user_both_db.db/table1

$ hdfs dfs -ls /user/hive/warehouse/user_both_db.db/table1
Found 1 items
-rwxrwxrwx   3 user_both hadoop          8 2020-06-28 03:22 /user/hive/warehouse/user_both_db.db/table1/000000_0

それぞれ user_both で作られています。 testuser と同等の操作ができるようです。

OSユーザあり、proxy user 設定なし / グループのみ変更

user_os の場合接続の時点で失敗しましたが、 user_os を proxy user で設定されているグループに所属させるとどうでしょうか。 ためしに users というグループでやってみます。

# id user_os
uid=1000(user_os) gid=1000(user_os) groups=1000(user_os)

# gpasswd -a user_os users
Adding user user_os to group users

# id user_os
uid=1000(user_os) gid=1000(user_os) groups=1000(user_os),100(users)

# su - user_os

$ beeline -u "jdbc:hive2://localhost:10000" -n user_os
  => OK

接続できました。 insert までやってみます。

create database user_os_db;
use user_os_db;
create table table1 (name string);
insert into table1 values ('foo'), ('bar');
$ hdfs dfs -ls /user/hive/warehouse/
Found 2 items
drwxrwxrwx   - user_both hadoop          0 2020-06-28 03:19 /user/hive/warehouse/user_both_db.db
drwxrwxrwx   - user_os   hadoop          0 2020-06-28 03:37 /user/hive/warehouse/user_os_db.db

$ hdfs dfs -ls /user/hive/warehouse/user_os_db.db/
Found 1 items
drwxrwxrwx   - user_os hadoop          0 2020-06-28 03:37 /user/hive/warehouse/user_os_db.db/table1

$ hdfs dfs -ls /user/hive/warehouse/user_os_db.db/table1
Found 1 items
-rwxrwxrwx   3 user_os hadoop          8 2020-06-28 03:37 /user/hive/warehouse/user_os_db.db/table1/000000_0

所有者=user_os で作られました。なるほど。