tag:crieit.net,2005:https://crieit.net/tags/Bigtop/feed 「Bigtop」の記事 - Crieit Crieitでタグ「Bigtop」に投稿された最近の記事 2021-06-04T05:02:28+09:00 https://crieit.net/tags/Bigtop/feed tag:crieit.net,2005:PublicArticle/17358 2021-06-04T05:01:46+09:00 2021-06-04T05:02:28+09:00 https://crieit.net/posts/apache-bigtop-hive-server2-enable-doas hive.server2.enable.doAs がよく分からなかったので Apache Bigtop で調べてみた <p><code>hive.server2.enable.doAs</code> の設定によって何がどう変わるかよく分からなかったので <a target="_blank" rel="nofollow noopener" href="https://bigtop.apache.org/">Apache Bigtop</a> を使って調べてみました。</p> <p><code>hive.server2.enable.doAs</code> だと長くて煩雑なので以下では適宜 doAs と略しています。</p> <h1 id="まとめ"><a href="#%E3%81%BE%E3%81%A8%E3%82%81">まとめ</a></h1> <p>先にまとめ。調べた結果を基に書いていますが、厳密な裏付けはありません(ソースを読んで調べたりはしていません)。</p> <ul> <li>proxy user というしくみがある <ul> <li><a target="_blank" rel="nofollow noopener" href="https://hadoop.apache.org/docs/r2.8.5/hadoop-project-dist/hadoop-common/Superusers.html">Apache Hadoop 2.8.5 – Proxy user - Superusers Acting On Behalf Of Other Users</a></li> <li>hiveserver2 のプロセスを実行しているユーザではなく、<br /> 他のユーザになりすましてジョブの submit や HDFS へのアクセスを行うしくみ</li> <li>(Hive ではなく)Hadoop の機能</li> <li>core-site.xml の <code>hadoop.proxyuser.〜</code> で設定する</li> <li><code>hive.server2.enable.doAs</code> が false の場合、なりすましを行わず、<br /> hiveserver2 のプロセスを実行しているユーザで操作が実行される</li> </ul></li> <li>なりすましを行うには、下記の両方が必要 <ul> <li>OSのユーザとして存在している</li> <li>core-site.xml の proxyuser の設定に対象ユーザが含まれている(※1)</li> </ul></li> <li>beeline の場合は、なりすましたいユーザ名を <code>-n</code> オプションで指定する</li> <li>なりすましを行うと、HDFS上で作られるデータベースやテーブルのディレクトリ、データファイルの所有者がそのユーザになる</li> </ul> <p><code>hive.server2.enable.doAs</code> で設定しているのは要するに何なのかということで言えば、「Hadoop の proxy user 機能を利用するかどうか」と思ってよさそうな挙動でした。なので、利用する場合は proxy user についても知る必要があります。</p> <p>※1 <a target="_blank" rel="nofollow noopener" href="https://hadoop.apache.org/docs/r2.8.5/hadoop-project-dist/hadoop-common/Superusers.html">Apache Hadoop 2.8.5 – Proxy user - Superusers Acting On Behalf Of Other Users</a> によれば、ホストによる指定、グループによる指定、ユーザによる指定を組み合わせて指定できるようです。</p> <h1 id="バージョンなど"><a href="#%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%81%AA%E3%81%A9">バージョンなど</a></h1> <p>Bigtop は下記の時点の master を使っています。</p> <pre><code>34e0bd7182c713b16dce9a4bdc803c8ed7fb9eb3 Thu Jun 11 09:01:26 2020 +0000 </code></pre> <ul> <li>Hadoop 2.8.5</li> <li>Hive 2.3.3</li> </ul> <h1 id="一応公式の説明"><a href="#%E4%B8%80%E5%BF%9C%E5%85%AC%E5%BC%8F%E3%81%AE%E8%AA%AC%E6%98%8E">一応公式の説明</a></h1> <p><a target="_blank" rel="nofollow noopener" href="https://cwiki.apache.org/confluence/display/Hive/Setting+Up+HiveServer2">Setting Up HiveServer2 - Apache Hive - Apache Software Foundation</a></p> <blockquote> 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. </blockquote> <p>impersonate は「なりすます」という意味。エラーメッセージでも出てきます。</p> <h1 id="調査1: doAsの設定による違い"><a href="#%E8%AA%BF%E6%9F%BB1%3A+doAs%E3%81%AE%E8%A8%AD%E5%AE%9A%E3%81%AB%E3%82%88%E3%82%8B%E9%81%95%E3%81%84">調査1: doAsの設定による違い</a></h1> <h2 id="準備"><a href="#%E6%BA%96%E5%82%99">準備</a></h2> <p>設定を変えてプロビジョニングしなおすのを繰り返すやり方だと時間がかかってしまうので、Bigtop のリポジトリをクローンしたディレクトリを2つ用意して true/false それぞれの設定にします。</p> <p>デフォルトでは true なので、false の方のディレクトリのみ <code>hive-site.xml</code> を修正。</p> <pre><code class="diff">--- 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> </code></pre> <p><code>config_centos-7.yaml</code> を修正して Hive コンポーネントを追加。</p> <pre><code class="diff">--- 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] </code></pre> <p>設定の変更はこれだけ。</p> <hr /> <p>単一ノードで create します。</p> <pre><code>time ./docker-hadoop.sh -C config_centos-7.yaml --create 1 </code></pre> <p>これで Hadoop と Hive が使えるようになります。Bigtop すばらしい……ありがたや……。</p> <hr /> <p>コンテナに入る。</p> <pre><code>./docker-hadoop.sh --exec 1 bash </code></pre> <p>以下、コンテナ内の作業。</p> <hr /> <p>testuser というユーザがすでに存在しているので、そっちにスイッチします。<br /> (こういう用途で使うために用意されているものなのか分かっていませんが、とりあえず一般ユーザのつもりで使います)</p> <pre><code>su - testuser </code></pre> <h2 id="接続"><a href="#%E6%8E%A5%E7%B6%9A">接続</a></h2> <p>beeline で hiverserver2 に接続</p> <pre><code>beeline -u "jdbc:hive2://localhost:10000" </code></pre> <ul> <li>doAs=false の場合: 接続に成功する。</li> <li>doAs=true の場合: 接続に失敗して次のようなメッセージが出ます(適宜改行を加えています)。</li> </ul> <pre><code>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) </code></pre> <p>この場合は <code>-n</code> オプションでユーザ名を指定すると接続できるようになります。</p> <pre><code>beeline -u "jdbc:hive2://localhost:10000" -n testuser </code></pre> <hr /> <p>ちなみに、Bigtop の既定の設定では hiveserver2 は hive ユーザで実行されますが、hiveserver2 を root ユーザで実行すると次のようなメッセージになります。</p> <pre><code>User: root is not allowed to impersonate anonymous (state=08S01,code=0) ^^^^ ここが変わる </code></pre> <p>「hiveserver2 の実行ユーザが他のユーザになりすます」ということが試みられているようです。</p> <hr /> <p>OSに存在しないユーザ名を指定した場合</p> <pre><code>beeline -u "jdbc:hive2://localhost:10000" -n nobody </code></pre> <ul> <li>doAs=false の場合: 接続に成功する。</li> <li>doAs=true の場合: 接続に失敗する。</li> </ul> <p>doAs=false の場合、 <code>-n</code> オプションによる指定はいずれにせよ無視されるということでしょうか。</p> <h2 id="create databse"><a href="#create+databse">create databse</a></h2> <h3 id="doAs=true の場合"><a href="#doAs%3Dtrue+%E3%81%AE%E5%A0%B4%E5%90%88">doAs=true の場合</a></h3> <pre><code>$ 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 </code></pre> <p>所有者=testuser でデータベースのディレクトリが作られました。</p> <h3 id="doAs=false の場合"><a href="#doAs%3Dfalse+%E3%81%AE%E5%A0%B4%E5%90%88">doAs=false の場合</a></h3> <p>一応 <code>-n testuser</code> を付けてみます。</p> <pre><code>$ 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 </code></pre> <p>やはり <code>-n</code> の指定は無視され、所有者=hive でディレクトリが作られました。</p> <h2 id="create table + insert"><a href="#create+table+%2B+insert">create table + insert</a></h2> <h3 id="doAs=true の場合"><a href="#doAs%3Dtrue+%E3%81%AE%E5%A0%B4%E5%90%88">doAs=true の場合</a></h3> <pre><code>$ 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 </code></pre> <p>insert 時に <code>/user</code> のパーミッションで怒られました。<br /> ちなみに <code>test1</code> テーブルは 所有者=testuser で作られています。</p> <pre><code>$ 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 </code></pre> <p><code>hdfs:///user</code> に実行権限を付けて再度 insert。</p> <pre><code># 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'); </code></pre> <p>今度は成功しました。</p> <pre><code>$ 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 </code></pre> <p>データは所有者=testuser で作られています。</p> <h3 id="doAs=false の場合"><a href="#doAs%3Dfalse+%E3%81%AE%E5%A0%B4%E5%90%88">doAs=false の場合</a></h3> <pre><code>$ beeline -u "jdbc:hive2://localhost:10000" -n testuser use test_db1; create table test1 (name string); insert into test1 values ('foo'), ('bar'); </code></pre> <p>こちらはエラーになりませんでした。</p> <pre><code>$ 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 </code></pre> <p>テーブルのディレクトリとデータは所有者=hive で作られています。</p> <h2 id="create external table + insert"><a href="#create+external+table+%2B+insert">create external table + insert</a></h2> <h3 id="doAs=true の場合"><a href="#doAs%3Dtrue+%E3%81%AE%E5%A0%B4%E5%90%88">doAs=true の場合</a></h3> <p><code>table_ext</code> というテーブルを作り、<code>/user/testuser</code> の下にデータを置くことにします。</p> <pre><code>$ hdfs dfs -ls /user ... drwx------ - testuser hadoop 0 2020-06-27 09:54 /user/testuser ... </code></pre> <pre><code>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'); </code></pre> <pre><code>$ 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 </code></pre> <h3 id="doAs=false の場合"><a href="#doAs%3Dfalse+%E3%81%AE%E5%A0%B4%E5%90%88">doAs=false の場合</a></h3> <p>こちらは <code>hdfs:///user/testuser/</code> ディレクトリが存在しなかったので、<code>hdfs:///tmp/</code> の下にデータを置くことにします。</p> <pre><code>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'); </code></pre> <pre><code>$ 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 </code></pre> <h1 id="調査2: OSのユーザとproxy userの関係"><a href="#%E8%AA%BF%E6%9F%BB2%3A+OS%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%A8proxy+user%E3%81%AE%E9%96%A2%E4%BF%82">調査2: OSのユーザとproxy userの関係</a></h1> <p>doAs=false の場合の挙動はなんとなく分かってきましたが、doAs=true の場合のOSのユーザとの関係がよく分からないので、こんどはそこを調べてみます。</p> <p>Hadoop の proxy user というしくみが関わっているようだったので、次の3パターンでどうなるか試します。</p> <ul> <li><code>user_os</code>: OS のユーザのみ存在</li> <li><code>user_proxyuser</code>: proxy user の設定のみ</li> <li><code>user_both</code>: OS のユーザが存在し、かつ proxy user の設定もあり <ul> <li>おそらく testuser と同等</li> </ul></li> </ul> <p>データの配置場所が変わるだけだと思われたので外部テーブルについては省略。</p> <hr /> <p>設定ファイルを修正。下記は master からの差分です。Puppet に詳しくないので、 testuser を grep したりして当たりを付けて適当に修正しました。</p> <pre><code class="diff">--- 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] </code></pre> <p>あと、調査1のときと同様に <code>hdfs:///user</code> のパーミッションを変更しておきます。</p> <pre><code># 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 </code></pre> <h2 id="OSユーザあり、proxy user 設定なし"><a href="#OS%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%82%E3%82%8A%E3%80%81proxy+user+%E8%A8%AD%E5%AE%9A%E3%81%AA%E3%81%97">OSユーザあり、proxy user 設定なし</a></h2> <pre><code># 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) </code></pre> <p>接続できない。</p> <h2 id="OSユーザなし、proxy user 設定あり"><a href="#OS%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%AA%E3%81%97%E3%80%81proxy+user+%E8%A8%AD%E5%AE%9A%E3%81%82%E3%82%8A">OSユーザなし、proxy user 設定あり</a></h2> <p>testuser を使います。</p> <pre><code># 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) </code></pre> <p>接続できない。</p> <h2 id="OSユーザあり、proxy user 設定あり"><a href="#OS%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%82%E3%82%8A%E3%80%81proxy+user+%E8%A8%AD%E5%AE%9A%E3%81%82%E3%82%8A">OSユーザあり、proxy user 設定あり</a></h2> <pre><code># 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'); </code></pre> <p>insert まで成功しました。</p> <pre><code>$ 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 </code></pre> <p>それぞれ <code>user_both</code> で作られています。testuser と同等の操作ができるようです。</p> <h2 id="OSユーザあり、proxy user 設定なし / グループのみ変更"><a href="#OS%E3%83%A6%E3%83%BC%E3%82%B6%E3%81%82%E3%82%8A%E3%80%81proxy+user+%E8%A8%AD%E5%AE%9A%E3%81%AA%E3%81%97+%2F+%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E3%81%AE%E3%81%BF%E5%A4%89%E6%9B%B4">OSユーザあり、proxy user 設定なし / グループのみ変更</a></h2> <p>user_os の場合接続の時点で失敗しましたが、user_os を proxy user で設定されているグループに所属させるとどうでしょうか。ためしに <code>users</code> というグループでやってみます。</p> <pre><code># 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 </code></pre> <p>接続できました。insert までやってみます。</p> <pre><code class="sql">create database user_os_db; use user_os_db; create table table1 (name string); insert into table1 values ('foo'), ('bar'); </code></pre> <pre><code>$ 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 </code></pre> <p>所有者=user_os で作られました。なるほど。</p> sonota486