TT Lab
はじめる
学ぶ 学習パス コース

Apache Hadoop — 1つのPodにHDFSとYARNを立てて運用する

単純認証は名乗った名前をそのまま信じる

TT Labで続きを見る

一言でいうと

HDFSの権限チェックはPOSIXとほぼ同じで、ACLまで備えていますが、「あなたは誰か」をHDFSは判断しません。デフォルト設定であるシンプル認証では、クライアントが名乗る名前をそのまま信じるので、権限は、ミスを防ぐ仕組みであって、攻撃を防ぐ仕組みではありません。

なぜこの区別が必要なのか

権限には2つの問いが含まれています。あなたは誰か(認証)と、その人にこれが許可されるか(認可)です。HDFSは、後者の問いには丁寧に答えます。問題は前者の問いです。

HDFS権限ガイドは、ユーザーの識別方式をhadoop.security.authenticationで選ぶと説明しています。core-default.xmlで、この値のデフォルトはsimpleで、説明には、カッコ付きで「認証なし」と付いています。simpleモードでは、クライアントプロセスの身元はホストのOSが決め、Unix系ならwhoamiの値です。ガイドは、さらに一歩踏み込んで、こう書いています。どのモードでも、ユーザーの身元を決める仕組みはHDFSの外にあり、HDFSの中には、ユーザーを作ったり、資格情報を処理したりする機能がありません。

そのため、このラボでは、環境変数HADOOP_USER_NAME=aliceを1つ指定するだけで、そのシェルはaliceになります。パスワードもありません。これがバグではなく設計であることを、セキュアモードのドキュメントがはっきりさせています。デフォルト設定では、すべてのネットワークアクセスを遮断して、攻撃者がクラスターに到達できないようにするのが運用者の役目であり、誰がデータにアクセスするかを制限したいなら、Kerberosで認証をかける必要があるというのです。

どう動くのか

権限ビット: ファイルとディレクトリごとに、所有者、グループ、そして所有者・グループのメンバー・その他のユーザーの3区分の権限があります。ファイルでrは読み取り、wは書き込みと追記です。ディレクトリでrは一覧表示、wは中に作成したり削除したりすること、xは子へのアクセスです。実行ファイルという概念がないので、setuid・setgidビットはありません。新しく作ったファイルの所有者はクライアントの身元で、グループは親ディレクトリのグループに従います(BSDルール)。ここでよく間違えます。Linuxのように、ユーザーのデフォルトグループが付くわけではありません。

チェックの順序: ユーザー名が所有者と同じなら、所有者の権限だけを見ます。そうでなければ、グループ一覧にファイルのグループがあるとき、グループの権限だけを見ます。どちらでもなければ、その他の権限を見ます。上で引っかかれば、下は見ません。また、すべての操作は、パスを通過できる必要があります。/foo/bar/bazに到達するには、/、/foo、/foo/barのすべてにxが必要です。

削除は親の仕事です: ガイドの操作別の表で、deleteはファイル自身ではなく親ディレクトリのwを要求します。ファイルが読み取り専用でも、ディレクトリに書き込めれば削除できるという意味です。全員が使う共有ディレクトリで、他人のファイルを削除できないようにするには、スティッキービットをかけます。スティッキービットがかかったディレクトリでは、スーパーユーザー、ディレクトリの所有者、ファイルの所有者だけが、その中のファイルを削除したり移動したりできます。

グループはNameNodeが決めます: ユーザー名はクライアントが言いますが、そのユーザーがどのグループに属するかは違います。グループマッピングのドキュメントは、HDFSでユーザーをグループに対応付ける処理がNameNodeで行われるので、NameNodeホストのシステム設定がグループ所属を決めると書いています。デフォルトの実装は、OSのグループ検索をそのまま使います。また、HDFSはファイルのユーザーとグループを、数値IDではなく文字列で保存します。そのため、financeグループがNameNodeのマシンになければ、クライアント側でいくらグループを作っても、HDFSは知りません。検索結果はデフォルトで300秒間キャッシュされるので、グループに人を入れた直後は、古い所属でチェックされることがあります。

スーパーユーザー: NameNodeプロセスと同じ身元がスーパーユーザーで、スーパーユーザーには権限チェックが失敗しません。hdfs-default.xmlのdfs.permissions.superusergroup(デフォルトはsupergroup)のメンバーも、スーパーユーザーです。NameNodeをrootで起動したこのラボでは、rootがスーパーユーザーです。

ACL(組織図とは違う例外を表現する)

権限ビットは「所有者1つ、グループ1つ」しか表現できません。財務フォルダーをfinanceグループに開き、監査担当のbob 1人にだけ読み取りを追加で与えたいなら、ビットではできません。そのためにACLがあります。dfs.namenode.acls.enabledは3.5.0でデフォルトtrueです。

hdfs dfs -chown alice:finance /proj/finance
hdfs dfs -chmod 750 /proj/finance
hdfs dfs -setfacl -m user:bob:r-x /proj/finance          # bob 에게 목록과 통과
hdfs dfs -setfacl -m default:user:bob:r-x /proj/finance  # 앞으로 만들 자식에게 상속
hdfs dfs -getfacl /proj/finance

ACLが付くと、チェックの順序に2つの段階が割り込みます。所有者の次に名前付きユーザーエントリを、グループの次に名前付きグループエントリを見ます。この2つと名前なしのグループエントリは、maskでもう一度絞り込まれます。maskは、拡張エントリが与えられる権限の上限です。ACLがあるファイルにchmodをすると、グループビットではなくmaskが変わる点が落とし穴です。chmod 7001回で、bobの読み取りが静かにブロックされます。

デフォルトACL(default ACL)はディレクトリにだけあり、新しい子が作られるときにコピーされます。ガイドは、コピーが作る瞬間にだけ行われ、あとで親のデフォルトACLを変えても、すでにある子は変わらないと書いています。そのため、既存のファイルに権限を与えるには、setfacl -Rで別に実行する必要があります。1つのファイルに付けられるエントリも、アクセスACL 32個、デフォルトACL 32個に制限され、ACLが付いたファイルはNameNodeのメモリをより多く使います。ガイドが勧める方式は、大部分を権限ビットで解決し、例外の少数だけをACLで上乗せすることです。

現場での姿

1つ目は、「権限をブロックしたのに、誰かが読んだ」ことです。シンプル認証のクラスターでは、誰でも自分の名前をaliceだと言えます。WebHDFSも、セキュリティがオフならuser.nameクエリの値をそのままユーザーとして受け取ります。権限は、同僚のミスを防ぐだけです。本当の境界が必要ならKerberosで、それまでは、ネットワークアクセス制御が唯一の塀です。

2つ目は、新しいファイルのグループが予想と違うことです。親ディレクトリのグループに従うからです。チームフォルダーのグループを先に正しく設定しておけば、その下の新しいファイルが自動的に従います。

3つ目は、グループに入れたのに、まだ拒否されることです。グループ所属は、クライアントではなくNameNode側で検索され、キャッシュされます。NameNodeのマシンにそのグループとメンバーがあるか、キャッシュがまだ古い値を持っていないかを確認します。

4つ目は、デフォルトACLをかけたのに、古いファイルはまだ読めないことです。継承は、作る瞬間のコピーです。すでにあったファイルには、別にかける必要があります。

5つ目は、権限チェックを切るのは解決策ではないことです。dfs.permissions.enabledをfalseにすると、チェックだけが切れて、モード・所有者・グループはそのまま残ります。ガイドは、この値に関係なく、chmod・chgrp・chown・setfaclは、常に権限をチェックすると書いています。

実務で本当に大切なこと

次のラボですること

財務フォルダーをalice所有、financeグループ、750で作り、aliceでファイルをアップロードします。環境変数1つでユーザーを切り替えて、bobが拒否されるのを見たあと、ACLでbob 1人にだけ読み取りを開いて、実際に読めるかを確認します。デフォルトACLをかけて、新しく作ったファイルがその権限を引き継ぐかを見て、スティッキービットをかけた共有フォルダーで他人のファイルを削除しようとして拒否されるところまで確認します。最後に、シンプル認証が防げないものと、Kerberosが必要な理由を、レポートに書きます。