HDFS パーミッションガイド

概要

Hadoop分散ファイルシステム(HDFS)は、ファイルとディレクトリに対するパーミッションモデルを実装しており、POSIXモデルの多くを共有しています。各ファイルとディレクトリには、所有者とグループが関連付けられています。ファイルまたはディレクトリには、所有者であるユーザー、グループのメンバーである他のユーザー、およびその他のすべてのユーザーに対して、個別のパーミッションがあります。ファイルの場合、ファイルを読み取るにはrパーミッションが必要であり、ファイルに書き込むまたは追加するにはwパーミッションが必要です。ディレクトリの場合、ディレクトリのコンテンツを一覧表示するにはrパーミッションが必要であり、ファイルまたはディレクトリを作成または削除するにはwパーミッションが必要であり、子ディレクトリにアクセスするにはxパーミッションが必要です。

POSIXモデルとは対照的に、実行可能ファイルの概念がないため、ファイルにsetuidビットやsetgidビットはありません。ディレクトリの場合、簡素化のため、setuidビットやsetgidビットはディレクトリにもありません。スティッキービットはディレクトリに設定でき、スーパーユーザー、ディレクトリオナー、またはファイルオーナー以外のユーザーがディレクトリ内のファイルの削除または移動を妨げます。ファイルにスティッキービットを設定しても効果はありません。ファイルまたはディレクトリのパーミッションはまとめてモードと呼ばれます。一般的に、モードを表して表示するためのUnixの慣習が使用され、この説明では8進数の使用を含みます。ファイルまたはディレクトリが作成されると、その所有者はクライアントプロセスのユーザーIDになり、そのグループは親ディレクトリのグループになります(BSDルール)。

HDFSは、特定の名前付きユーザーまたは名前付きグループに対してより詳細なルールでファイルパーミッションを拡張するために、POSIX ACL(アクセス制御リスト)のオプションサポートも提供しています。ACLについては、このドキュメントの後半で詳しく説明します。

HDFSにアクセスする各クライアントプロセスには、ユーザー名とグループリストで構成される2つの部分からなるIDがあります。HDFSがクライアントプロセスによってアクセスされたファイルまたはディレクトリfooのパーミッションチェックを行う必要がある場合、

  • ユーザー名がfooの所有者と一致する場合、所有者パーミッションがテストされます。
  • グループリストのメンバーのいずれかとfooのグループが一致する場合、グループパーミッションがテストされます。
  • それ以外の場合は、fooのその他のパーミッションがテストされます。

パーミッションチェックが失敗した場合、クライアント操作は失敗します。

ユーザーID

Hadoop 0.22以降、Hadoopは、hadoop.security.authenticationプロパティで指定された、ユーザーIDを決定するための2つの異なる動作モードをサポートしています。

  • simple

    この動作モードでは、クライアントプロセスのIDはホストオペレーティングシステムによって決定されます。Unixライクシステムでは、ユーザー名は`whoami`と同等です。

  • kerberos

    Kerberized操作では、クライアントプロセスのIDはKerberosクレデンシャルによって決定されます。たとえば、Kerberized環境では、ユーザーはkinitユーティリティを使用してKerberosチケット付与チケット(TGT)を取得し、klistを使用して現在のプリンシパルを確認できます。KerberosプリンシパルをHDFSユーザー名にマッピングする際、プライマリを除くすべてのコンポーネントは削除されます。たとえば、プリンシパルtodd/foobar@CORP.COMPANY.COMは、HDFSでは単純なユーザー名toddとして動作します。

動作モードに関係なく、ユーザーIDメカニズムはHDFS自体とは外部的です。HDFSには、ユーザーIDの作成、グループの確立、またはユーザー資格情報の処理のためのプロビジョンはありません。

グループマッピング

上記のようにユーザー名が決定されると、グループのリストは、hadoop.security.group.mappingプロパティによって構成されたグループマッピングサービスによって決定されます。詳細については、Hadoopグループマッピングを参照してください。

パーミッションチェック

各HDFS操作は、ファイルの所有権、グループメンバーシップ、またはその他のパーミッションを通じて付与された特定のパーミッション(READ、WRITE、EXECUTEの組み合わせ)をユーザーが持っていることを要求します。操作は、最終コンポーネントだけでなく、パスの複数のコンポーネントでパーミッションチェックを実行する場合があります。さらに、一部の操作はパスの所有者のチェックに依存します。

すべての操作には、トラバーサルアクセスが必要です。トラバーサルアクセスは、最終パスコンポーネントを除く、パスのすべての既存コンポーネントに対するEXECUTEパーミッションを要求します。たとえば、/foo/bar/bazにアクセスする操作の場合、呼び出し元は//foo、および/foo/barに対するEXECUTEパーミッションを持っている必要があります。

次の表は、パスの各コンポーネントに対してHDFSによって実行されるパーミッションチェックについて説明しています。

  • 所有権:呼び出し元がパスの所有者かどうかを確認するかどうか。通常、所有権またはパーミッションメタデータを変更する操作は、呼び出し元が所有者であることを要求します。
  • 親:要求されたパスの親ディレクトリ。たとえば、パス/foo/bar/bazの場合、親は/foo/barです。
  • 先祖:要求されたパスの最後の既存のコンポーネント。たとえば、パス/foo/bar/bazの場合、/foo/barが存在する場合は、先祖パスは/foo/barです。/fooが存在するが/foo/barが存在しない場合は、先祖パスは/fooです。
  • 最終:要求されたパスの最後のコンポーネント。たとえば、パス/foo/bar/bazの場合、最終パスコンポーネントは/foo/bar/bazです。
  • サブツリー:ディレクトリであるパスについては、ディレクトリ自体とそのすべての子供サブディレクトリを再帰的に処理します。たとえば、buzbooという2つのサブディレクトリを持つパス/foo/bar/bazの場合、サブツリーは/foo/bar/baz/foo/bar/baz/buz、および/foo/bar/baz/booです。
操作 所有権 先祖 最終 サブツリー
append NO N/A N/A WRITE N/A
concat NO [2] WRITE (ソース) N/A READ (ソース)、WRITE (宛先) N/A
create NO N/A WRITE WRITE [1] N/A
createSnapshot YES N/A N/A N/A N/A
delete NO [2] WRITE N/A N/A READ、WRITE、EXECUTE
deleteSnapshot YES N/A N/A N/A N/A
getAclStatus NO N/A N/A N/A N/A
getBlockLocations NO N/A N/A READ N/A
getContentSummary NO N/A N/A N/A READ、EXECUTE
getFileInfo NO N/A N/A N/A N/A
getFileLinkInfo NO N/A N/A N/A N/A
getLinkTarget NO N/A N/A N/A N/A
getListing NO N/A N/A READ、EXECUTE N/A
getSnapshotDiffReport NO N/A N/A READ READ
getStoragePolicy NO N/A N/A READ N/A
getXAttrs NO N/A N/A READ N/A
listXAttrs NO EXECUTE N/A N/A N/A
mkdirs NO N/A WRITE N/A N/A
modifyAclEntries YES N/A N/A N/A N/A
removeAcl YES N/A N/A N/A N/A
removeAclEntries YES N/A N/A N/A N/A
removeDefaultAcl YES N/A N/A N/A N/A
removeXAttr NO [2] N/A N/A WRITE N/A
rename NO [2] WRITE (ソース) WRITE (宛先) N/A N/A
renameSnapshot YES N/A N/A N/A N/A
setAcl YES N/A N/A N/A N/A
setOwner YES [3] N/A N/A N/A N/A
setPermission YES N/A N/A N/A N/A
setReplication NO N/A N/A WRITE N/A
setStoragePolicy NO N/A N/A WRITE N/A
setTimes NO N/A N/A WRITE N/A
setXAttr NO [2] N/A N/A WRITE N/A
切り詰め NO N/A N/A WRITE N/A

[1] create時の最終パスコンポーネントに対するWRITEアクセスは、上書きオプションを使用し、かつそのパスに既存のファイルが存在する場合のみ必要です。

[2] 親ディレクトリに対するWRITE権限をチェックする操作は、スティッキービットが設定されている場合、所有権もチェックします。

[3] setOwnerを呼び出してファイルの所有者を変更するには、HDFSスーパーユーザーアクセスが必要です。HDFSスーパーユーザーアクセスはグループの変更には必要ありませんが、呼び出し元はファイルの所有者であり、指定されたグループのメンバーである必要があります。

実装の理解

各ファイルまたはディレクトリオペレーションは、完全なパス名をNameNodeに渡し、各操作に対してパスに沿って権限チェックが適用されます。クライアントフレームワークは、ユーザーIDをNameNodeへの接続に暗黙的に関連付けるため、既存のクライアントAPIへの変更の必要性を減らします。ファイルに対するある操作が成功した場合でも、ファイルまたはパス上のいくつかのディレクトリが存在しなくなるため、操作を繰り返すと失敗する可能性があるのは、常に当てはまっていました。たとえば、クライアントがファイルの読み取りを開始すると、最初にNameNodeに要求を行い、ファイルの最初のブロックの場所を検出します。追加のブロックを見つけるために実行された2番目の要求は失敗する可能性があります。一方、ファイルを削除しても、既にファイルのブロックを知っているクライアントによるアクセスは取り消されません。権限を追加することで、クライアントのファイルへのアクセスは要求間で取り消される可能性があります。繰り返しますが、権限を変更しても、既にファイルのブロックを知っているクライアントのアクセスは取り消されません。

ファイルシステムAPIへの変更

パスパラメーターを使用するすべてのメソッドは、パーミッションチェックが失敗した場合、AccessControlExceptionをスローします。

新しいメソッド

  • public FSDataOutputStream create(Path f, FsPermission permission, boolean overwrite, int bufferSize, short replication, long blockSize, Progressable progress) throws IOException;
  • public boolean mkdirs(Path f, FsPermission permission) throws IOException;
  • public void setPermission(Path p, FsPermission permission) throws IOException;
  • public void setOwner(Path p, String username, String groupname) throws IOException;
  • public FileStatus getFileStatus(Path f) throws IOException;は、パスに関連付けられたユーザー、グループ、およびモードをさらに返します。

新規ファイルまたはディレクトリのモードは、設定パラメーターとして設定されたumaskによって制限されます。既存のcreate(path, …)メソッド(パーミッションパラメーターなし)を使用する場合、新規ファイルのモードは0666 & ^umaskになります。新しいcreate(path, permission, …)メソッド(パーミッションパラメーターP付き)を使用する場合、新規ファイルのモードはP & ^umask & 0666になります。既存のmkdirs(path)メソッド(パーミッションパラメーターなし)を使用して新しいディレクトリを作成する場合、新しいディレクトリのモードは0777 & ^umaskになります。新しいmkdirs(path, permission)メソッド(パーミッションパラメーターP付き)を使用する場合、新しいディレクトリのモードはP & ^umask & 0777になります。

アプリケーションシェルの変更

新しい操作

  • chmod [-R] mode file ...

    ファイルのモードを変更できるのは、ファイルの所有者またはスーパーユーザーのみです。

  • chgrp [-R] group file ...

    chgrpを呼び出すユーザーは、指定されたグループに属し、ファイルの所有者であるか、スーパーユーザーである必要があります。

  • chown [-R] [owner][:[group]] file ...

    ファイルの所有者は、スーパーユーザーのみが変更できます。

  • ls file ...

  • lsr file ...

    出力は、所有者、グループ、およびモードを表示するように再フォーマットされます。

スーパーユーザー

スーパーユーザーは、NameNodeプロセス自体と同じIDを持つユーザーです。簡単に言えば、NameNodeを起動した場合は、スーパーユーザーになります。スーパーユーザーは、権限チェックがスーパーユーザーに対して決して失敗しないため、何でもできます。誰がスーパーユーザーであったかの永続的な概念はありません。NameNodeが起動されると、プロセスIDによって現在のスーパーユーザーが決まります。HDFSスーパーユーザーは、NameNodeホストのスーパーユーザーである必要はなく、すべてのクラスタが同じスーパーユーザーである必要もありません。また、個人用のワークステーションでHDFSを実行する実験者は、設定なしで、そのインストールのスーパーユーザーになります。

さらに、管理者は、設定パラメーターを使用して、特別なグループを識別できます。設定されている場合、このグループのメンバーもスーパーユーザーになります。

Webサーバー

デフォルトでは、WebサーバーのIDは設定パラメーターです。つまり、NameNodeには実際のユーザーのIDに関する概念はありませんが、Webサーバーは、管理者によって選択されたユーザーのID(ユーザーとグループ)を持っているかのように動作します。選択されたIDがスーパーユーザーと一致しない場合、名前空間の一部はWebサーバーからアクセスできない可能性があります。

ACL(アクセス制御リスト)

従来のPOSIXパーミッションモデルに加えて、HDFSはPOSIX ACL(アクセス制御リスト)もサポートしています。ACLは、ユーザーとグループの自然な組織階層とは異なるパーミッション要件を実装するのに役立ちます。ACLは、ファイルの所有者とファイルのグループだけでなく、特定の名前付きユーザーまたは名前付きグループに対して異なるパーミッションを設定する方法を提供します。

デフォルトでは、ACLのサポートが有効になっており、NameNodeはACLの作成を許可しています。ACLのサポートを無効にするには、NameNodeの設定でdfs.namenode.acls.enabledをfalseに設定します。

ACLは、ACLエントリのセットで構成されています。各ACLエントリは特定のユーザーまたはグループに名前を付け、その特定のユーザーまたはグループに対する読み取り、書き込み、実行のパーミッションを許可または拒否します。例えば

   user::rw-
   user:bruce:rwx                  #effective:r--
   group::r-x                      #effective:r--
   group:sales:rwx                 #effective:r--
   mask::r--
   other::r--

ACLエントリは、タイプ、オプションの名前、およびパーミッション文字列で構成されます。表示目的で、各フィールド間の区切り文字として「:」が使用されます。この例では、ファイル所有者は読み取り書き込みアクセス権を持ち、ファイルグループは読み取り実行アクセス権を持ち、その他は読み取りアクセス権を持っています。これは、ファイルのパーミッションビットを654に設定することと同じです。

さらに、名前付きユーザーbruceと名前付きグループsalesの2つの拡張ACLエントリがあり、両方ともフルアクセスが許可されています。マスクは、すべての名前付きユーザーエントリと名前付きグループエントリ、および名前なしグループエントリに付与されるパーミッションをフィルタリングする特別なACLエントリです。この例では、マスクには読み取りパーミッションのみがあり、いくつかのACLエントリの有効なパーミッションがそれに応じてフィルタリングされていることがわかります。

すべてのACLにはマスクが必要です。ユーザーがACLの設定時にマスクを提供しない場合、マスクは、マスクによってフィルタリングされるすべてのエントリのパーミッションの和集合を計算することによって自動的に挿入されます。

ACLを持つファイルでchmodを実行すると、実際にはマスクのパーミッションが変更されます。マスクはフィルターとして機能するため、これにより、グループエントリのみを変更し、他の拡張ACLエントリを欠損させる可能性があるのではなく、すべての拡張ACLエントリのパーミッションが効果的に制約されます。

このモデルでは、「アクセスACL」(パーミッションチェック中に適用するルールを定義する)と「デフォルトACL」(作成時に新しい子ファイルまたはサブディレクトリが自動的に受信するACLエントリを定義する)も区別されています。例えば

   user::rwx
   group::r-x
   other::r-x
   default:user::rwx
   default:user:bruce:rwx          #effective:r-x
   default:group::r-x
   default:group:sales:rwx         #effective:r-x
   default:mask::r-x
   default:other::r-x

ディレクトリのみがデフォルトACLを持つことができます。新しいファイルまたはサブディレクトリが作成されると、その親のデフォルトACLがそのアクセスACLに自動的にコピーされます。新しいサブディレクトリは、それを独自のデフォルトACLにもコピーします。このように、デフォルトACLは、新しいサブディレクトリが作成されるにつれて、ファイルシステムツリーの任意の深いレベルにコピーされます。

新しい子のアクセスACLの正確なパーミッション値は、モードパラメーターによるフィルタリングの対象となります。022のデフォルトのumaskを考慮すると、これは通常、新しいディレクトリの場合は755、新しいファイルの場合は644です。モードパラメーターは、名前なしユーザー(ファイル所有者)、マスク、およびその他のコピーされたパーミッション値をフィルタリングします。この特定の例では、モード755で新しいサブディレクトリを作成すると、このモードフィルタリングは最終結果に影響しません。ただし、モード644でファイルを作成することを考慮すると、モードフィルタリングにより、新しいファイルのACLは、名前なしユーザー(ファイル所有者)に対して読み取り書き込み、マスクに対して読み取り、その他に対して読み取りが許可されます。このマスクは、名前付きユーザーbruceと名前付きグループsalesの有効なパーミッションが読み取りのみであることも意味します。

新しいファイルまたはサブディレクトリが作成された時点でコピーが行われることに注意してください。親のデフォルトACLのその後の変更は、既存の子には影響しません。

デフォルトACLには、名前なしユーザー(ファイル所有者)、名前なしグループ(ファイルグループ)、その他のエントリを含む、必要なすべての最小ACLエントリが含まれている必要があります。ユーザーがデフォルトACLの設定時にこれらのエントリの1つを提供しない場合、アクセスACLから対応するパーミッション、またはアクセスACLがない場合はパーミッションビットをコピーすることによって、エントリが自動的に挿入されます。デフォルトACLにもマスクが必要です。上記のように、マスクが指定されていない場合、マスクは、マスクによってフィルタリングされるすべてのエントリのパーミッションの和集合を計算することによって自動的に挿入されます。

特定のファイルまたはディレクトリに対して無制限の数のACLエントリを持つことはできないことに注意してください。アクセスとデフォルトのエントリに対して最大数は32で、合計で64です。

ACLを持つファイルについて検討する場合、パーミッションチェックのアルゴリズムは次のように変更されます。

  • ユーザー名がファイルの所有者と一致する場合、所有者パーミッションがテストされます。

  • そうでない場合、ユーザー名が名前付きユーザーエントリの1つの名前と一致する場合、これらのパーミッションがテストされ、マスクパーミッションによってフィルタリングされます。

  • そうでない場合、ファイルのグループがグループリストのメンバーのいずれかと一致し、これらのパーミッションがマスクによってフィルタリングされてアクセスが許可される場合、これらのパーミッションが使用されます。

  • そうでない場合、グループリストのメンバーと一致する名前付きグループエントリがあり、これらのパーミッションがマスクによってフィルタリングされてアクセスが許可される場合、これらのパーミッションが使用されます。

  • そうでない場合、ファイルグループまたは名前付きグループエントリのいずれかがグループリストのメンバーと一致するが、それらのパーミッションのいずれによってもアクセスが許可されなかった場合、アクセスは拒否されます。

  • それ以外の場合は、ファイルのその他のパーミッションがテストされます。

ベストプラクティスは、従来のパーミッションビットを使用してほとんどのパーミッション要件を実装し、少数の例外的なルールでパーミッションビットを拡張するために、より少ない数のACLを定義することです。ACLを持つファイルは、パーミッションビットのみを持つファイルと比較して、NameNodeのメモリに余分なコストがかかります。

ACLファイルシステムAPI

新しいメソッド

  • public void modifyAclEntries(Path path, List<AclEntry> aclSpec) throws IOException;
  • public void removeAclEntries(Path path, List<AclEntry> aclSpec) throws IOException;
  • public void public void removeDefaultAcl(Path path) throws IOException;
  • public void removeAcl(Path path) throws IOException;
  • public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException;
  • public AclStatus getAclStatus(Path path) throws IOException;

ACLシェルコマンド

  • hdfs dfs -getfacl [-R] <path>

    ファイルとディレクトリのアクセス制御リスト(ACL)を表示します。ディレクトリにデフォルトのACLがある場合、getfaclはデフォルトのACLも表示します。

  • hdfs dfs -setfacl [-R] [-b |-k -m |-x <acl_spec> <path>] |[--set <acl_spec> <path>]

    ファイルとディレクトリのアクセス制御リスト(ACL)を設定します。

  • hdfs dfs -ls <args>

    lsの出力が、ACLを持つファイルまたはディレクトリのパーミッション文字列に「+」文字を追加します。

    これらのコマンドの詳細については、ファイルシステムシェルのドキュメントを参照してください。

設定パラメータ

  • dfs.permissions.enabled = true

    trueの場合、ここに記載されているパーミッションシステムを使用します。falseの場合、パーミッションチェックは無効になりますが、その他の動作は変わりません。パラメータ値を切り替えても、ファイルやディレクトリのモード、所有者、グループは変更されません。パーミッションが有効か無効かに関係なく、chmod、chgrp、chown、setfaclは常にパーミッションをチェックします。これらの関数はパーミッションのコンテキストでのみ有効であり、後方互換性の問題は発生しません。さらに、これにより、管理者は通常のパーミッションチェックを有効にする前に、所有者とパーミッションを確実に設定できます。

  • dfs.web.ugi = webuser,webgroup

    ウェブサーバーで使用されるユーザー名。これをスーパーユーザーの名前に設定すると、すべてのウェブクライアントがすべてを見ることができます。「other」パーミッションを使用して見えるもののみをウェブクライアントが表示できるようにするには、これを使用されていないIDに変更します。カンマ区切りのリストに追加のグループを追加できます。

  • dfs.permissions.superusergroup = supergroup

    スーパーユーザーのグループ名。

  • fs.permissions.umask-mode = 0022

    ファイルとディレクトリを作成する際に使用されるumask。設定ファイルでは、10進数の値18を使用できます。

  • dfs.cluster.administrators = ACL-for-admins

    ACLとして指定されたクラスタの管理者。これは、HDFSのデフォルトサーブレットなどにアクセスできるユーザーを制御します。

  • dfs.namenode.acls.enabled = true

    HDFS ACL(アクセス制御リスト)のサポートを有効にするにはtrueに設定します。デフォルトでは、ACLは有効になっています。ACLが無効になっている場合、NameNodeはACLを設定しようとするすべての試みを拒否します。

  • dfs.namenode.posix.acl.inheritance.enabled

    POSIXスタイルのACL継承を有効にするにはtrueに設定します。デフォルトで有効になっています。これが有効になっており、互換性のあるクライアントからの作成リクエストの場合、NameNodeは親ディレクトリからのデフォルトACLを作成モードに適用し、クライアントumaskを無視します。デフォルトACLが見つからない場合は、クライアントumaskを適用します。