HDFSは、透過的なエンドツーエンド暗号化を実装しています。一度設定すると、特別なHDFSディレクトリから読み書きされるデータは、ユーザーアプリケーションコードを変更することなく、透過的に暗号化および復号化されます。この暗号化はエンドツーエンドでもあり、データはクライアントによってのみ暗号化および復号化できることを意味します。HDFSは、暗号化されていないデータや暗号化されていないデータ暗号化キーを保存したり、アクセスしたりすることはありません。これは、保存時の暗号化(ディスクなどの永続的なメディア上のデータ)と転送中の暗号化(たとえば、データがネットワーク上を移動しているとき)という、暗号化に対する2つの一般的な要件を満たします。
暗号化は、従来のデータ管理ソフトウェア/ハードウェアスタックのさまざまなレイヤーで実行できます。特定のレイヤーで暗号化を選択すると、異なる利点と欠点があります。
アプリケーションレベルの暗号化。これは最も安全で最も柔軟なアプローチです。アプリケーションは、暗号化されるものを究極的に制御し、ユーザーの要件を正確に反映できます。ただし、これを行うアプリケーションを作成するのは困難です。また、暗号化をサポートしていない既存のアプリケーションの顧客にとってはオプションではありません。
データベースレベルの暗号化。そのプロパティの点で、アプリケーションレベルの暗号化に似ています。ほとんどのデータベースベンダーは、何らかの形式の暗号化を提供しています。ただし、パフォーマンスの問題が発生する可能性があります。1つの例は、インデックスを暗号化できないことです。
ファイルシステムレベルの暗号化。このオプションは、高性能、アプリケーションの透過性を提供し、通常は簡単にデプロイできます。ただし、一部のアプリケーションレベルのポリシーをモデル化することはできません。たとえば、マルチテナントアプリケーションでは、エンドユーザーに基づいて暗号化したい場合があります。データベースでは、単一のファイル内に保存されている各列に対して異なる暗号化設定が必要になる場合があります。
ディスクレベルの暗号化。展開が簡単で高性能ですが、非常に柔軟性がありません。物理的な盗難に対する保護のみを目的としています。
HDFSレベルの暗号化は、このスタックのデータベースレベルとファイルシステムレベルの暗号化の間に適合します。これには多くのプラスの効果があります。HDFS暗号化は優れたパフォーマンスを提供でき、既存のHadoopアプリケーションは暗号化されたデータ上で透過的に実行できます。また、HDFSには、ポリシーを決定する際に、従来のファイルシステムよりも多くのコンテキストがあります。
HDFSレベルの暗号化は、ファイルシステムレベル以下の攻撃(いわゆる「OSレベルの攻撃」)も防ぎます。データはすでにHDFSによって暗号化されているため、オペレーティングシステムとディスクは暗号化されたバイトのみを操作します。
データ暗号化は、多くの異なる政府、金融、規制機関によって要求されています。たとえば、医療業界にはHIPAA規制、カード決済業界にはPCI DSS規制、米国政府にはFISMA規制があります。HDFSに組み込まれた透過的な暗号化により、組織はこれらの規制に準拠しやすくなります。
暗号化はアプリケーションレベルでも実行できますが、HDFSに統合することで、既存のアプリケーションは変更なしで暗号化されたデータを操作できます。この統合アーキテクチャは、より強力な暗号化ファイルセマンティクスと他のHDFS機能とのより良い連携を意味します。
透過的な暗号化のために、HDFSに新しい抽象化を導入します。それが暗号化ゾーンです。暗号化ゾーンは、書き込み時にコンテンツが透過的に暗号化され、読み取り時に透過的に復号化される特別なディレクトリです。各暗号化ゾーンは、ゾーンの作成時に指定された単一の暗号化ゾーンキーに関連付けられています。暗号化ゾーン内の各ファイルには、独自のデータ暗号化キー(DEK)があります。DEKはHDFSによって直接処理されることはありません。代わりに、HDFSは暗号化されたデータ暗号化キー(EDEK)のみを処理します。クライアントはEDEKを復号化し、その後、後続のDEKを使用してデータを読み書きします。HDFSデータノードは、暗号化されたバイトのストリームを表示するだけです。
暗号化の非常に重要なユースケースは、「オンに切り替え」、ファイルシステム全体で全てのファイルが暗号化されるようにすることです。ファイルシステムの異なる部分で異なる暗号化ゾーンキーを使用する柔軟性を失うことなく、この強力な保証をサポートするために、HDFSはネストされた暗号化ゾーンを許可します。暗号化ゾーンが作成された後(たとえば、ルートディレクトリ/
)、ユーザーは、異なるキーを使用して、その子孫ディレクトリ(たとえば、/home/alice
)にさらに多くの暗号化ゾーンを作成できます。ファイルのEDEKは、最も近い祖先の暗号化ゾーンの暗号化ゾーンキーを使用して生成されます。
暗号化キーを管理するには、新しいクラスターサービスが必要です。それがHadoop Key Management Server(KMS)です。HDFS暗号化のコンテキストでは、KMSは3つの基本的な責任を果たします。
保存された暗号化ゾーンキーへのアクセスを提供
NameNodeに保存するために、新しい暗号化されたデータ暗号化キーを生成
HDFSクライアントが使用するために暗号化されたデータ暗号化キーを復号化
KMSについては、以下で詳しく説明します。
暗号化ゾーンに新しいファイルを作成する場合、NameNodeはKMSに暗号化ゾーンのキーで暗号化された新しいEDEKを生成するように要求します。EDEKは、NameNode上のファイルのメタデータの一部として永続的に保存されます。
暗号化ゾーン内のファイルを読み取る場合、NameNodeはクライアントにファイルのEDEKと、EDEKの暗号化に使用された暗号化ゾーンキーのバージョンを提供します。その後、クライアントはKMSにEDEKの復号化を要求します。これには、クライアントが暗号化ゾーンキーのバージョンにアクセスする権限を持っていることを確認することが含まれます。それが成功した場合、クライアントはDEKを使用してファイルの内容を復号化します。
読み取りパスと書き込みパスに関する上記のすべてのステップは、DFSClient、NameNode、KMS間の対話を通じて自動的に行われます。
暗号化されたファイルデータとメタデータへのアクセスは、通常のHDFSファイルシステムのパーミッションによって制御されます。これは、HDFSが侵害された場合(例えば、HDFSスーパーユーザーアカウントへの不正アクセスによって)、悪意のあるユーザーは暗号文と暗号化されたキーにのみアクセスできることを意味します。ただし、暗号化ゾーンキーへのアクセスは、KMSとキーストア上の別のパーミッションセットによって制御されるため、これはセキュリティ上の脅威にはなりません。
KMSは、HDFSデーモンおよびクライアントの代わりに、バックエンドのキーストアとインターフェイスするプロキシです。バックエンドのキーストアとKMSの両方が、Hadoop KeyProvider APIを実装しています。詳細については、KMSドキュメントを参照してください。
KeyProvider APIでは、各暗号化キーに一意のキー名があります。キーはロールオーバーされる可能性があるため、キーには複数のキーバージョンを持たせることができ、各キーバージョンには独自のキーマテリアル(暗号化および復号化中に使用される実際の秘密バイト)があります。暗号化キーは、キー名でフェッチしてキーの最新バージョンを返すか、特定のキーバージョンでフェッチできます。
KMSは、暗号化された暗号化キー(EEK)の作成と復号化を可能にする追加機能を実装しています。EEKの作成と復号化は、すべてKMS上で行われます。重要なのは、EEKの作成または復号化を要求するクライアントは、EEKの暗号化キーを扱うことはないということです。新しいEEKを作成するために、KMSは新しいランダムキーを生成し、指定されたキーで暗号化し、EEKをクライアントに返します。EEKを復号化するために、KMSはユーザーが暗号化キーへのアクセス権を持っていることを確認し、それを使用してEEKを復号化し、復号化された暗号化キーを返します。
HDFS暗号化のコンテキストでは、EEKは暗号化されたデータ暗号化キー(EDEK)であり、データ暗号化キー(DEK)はファイルデータの暗号化と復号化に使用されます。通常、キーストアは、エンドユーザーがDEKの暗号化に使用されるキーにのみアクセスできるように構成されています。これは、HDFSユーザーは暗号化されていない暗号化キーにアクセスできないため、EDEKをHDFSで安全に保存および処理できることを意味します。
必要な前提条件は、KMSのインスタンスと、KMSのバックエンドキーストアです。詳細については、KMSドキュメントを参照してください。
KMSがセットアップされ、NameNodeとHDFSクライアントが正しく構成されると、管理者はhadoop key
およびhdfs crypto
コマンドラインツールを使用して、暗号化キーを作成し、新しい暗号化ゾーンをセットアップできます。既存のデータは、distcpのようなツールを使用して新しい暗号化ゾーンにコピーすることで暗号化できます。
暗号化ゾーンへの読み取りと書き込みを行う際に使用される暗号化キーと対話するときに使用するKeyProvider。HDFSクライアントは、NamenodeからgetServerDefaults経由で返されるプロバイダーパスを使用します。namenodeがキープロバイダーのURIの返却をサポートしていない場合、クライアントのconfが使用されます。
特定の暗号コーデックのプレフィックス。特定の暗号コーデック(例:EXAMPLECIPHERSUITE)の実装クラスのカンマ区切りリストが含まれます。最初の実装が利用可能な場合は使用され、それ以外はフォールバックされます。
デフォルト:org.apache.hadoop.crypto.OpensslAesCtrCryptoCodec, org.apache.hadoop.crypto.JceAesCtrCryptoCodec
AES/CTR/NoPaddingの暗号コーデック実装のカンマ区切りリスト。最初の実装が利用可能な場合は使用され、それ以外はフォールバックされます。
デフォルト:AES/CTR/NoPadding
暗号コーデックの暗号スイート。
デフォルト:なし
CryptoCodecで使用されるJCEプロバイダー名。
デフォルト:8192
CryptoInputStreamおよびCryptoOutputStreamで使用されるバッファーサイズ。
デフォルト:100
暗号化ゾーンを一覧表示するとき、バッチで返されるゾーンの最大数。バッチで段階的にリストをフェッチすると、namenodeのパフォーマンスが向上します。
crypto
コマンドラインインターフェース使用法:[-createZone -keyName <キー名> -path <パス>]
新しい暗号化ゾーンを作成します。
パス | 作成する暗号化ゾーンのパス。空のディレクトリである必要があります。このパスの下にゴミ箱ディレクトリがプロビジョニングされます。 |
キー名 | 暗号化ゾーンに使用するキーの名前。大文字のキー名はサポートされていません。 |
使用法:[-listZones]
すべての暗号化ゾーンを一覧表示します。スーパーユーザー権限が必要です。
使用法:[-provisionTrash -path <パス>]
暗号化ゾーンのゴミ箱ディレクトリをプロビジョニングします。
パス | 暗号化ゾーンのルートへのパス。 |
使用法:[-getFileEncryptionInfo -path <パス>]
ファイルから暗号化情報を取得します。これは、ファイルが暗号化されているかどうか、および暗号化に使用されたキー名/キーバージョンを調べるために使用できます。
パス | 暗号化情報を取得するファイルのパス。 |
使用法:[-reencryptZone <アクション> -path <ゾーン>]
暗号化ゾーンを反復処理し、KeyProviderのreencryptEncryptedKeysインターフェースを呼び出して、キープロバイダーの暗号化ゾーンキーの最新バージョンを使用してすべてのファイルのEDEKをバッチで再暗号化することにより、暗号化ゾーンを再暗号化します。スーパーユーザー権限が必要です。
再暗号化は、スナップショットの不変の性質により、スナップショットには適用されないことに注意してください。
アクション | 実行する再暗号化アクション。-start または-cancel のいずれかである必要があります。 |
パス | 暗号化ゾーンのルートへのパス。 |
再暗号化はHDFSのNameNodeのみの操作であるため、NameNodeに集中的な負荷がかかる可能性があります。クラスタへの許容可能なスループットの影響に応じて、次の構成を変更して、NameNodeへのストレスを制御できます。
dfs.namenode.reencrypt.batch.size | 再暗号化のためにKMSに送信されるバッチ内のEDEKの数。各バッチは、ネームシステムの読み取り/書き込みロックを保持しているときに処理され、バッチ間でスロットリングが発生します。以下の構成を参照してください。 |
dfs.namenode.reencrypt.throttle.limit.handler.ratio | 再暗号化中に保持される読み取りロックの割合。1.0はスロットリングなしを意味します。0.5は、再暗号化がその総処理時間の最大50%まで読み取りロックを保持できることを意味します。負の値または0は無効です。 |
dfs.namenode.reencrypt.throttle.limit.updater.ratio | 再暗号化中に保持される書き込みロックの割合。1.0はスロットリングなしを意味します。0.5は、再暗号化がその総処理時間の最大50%まで書き込みロックを保持できることを意味します。負の値または0は無効です。 |
使用法:[-listReencryptionStatus]
すべての暗号化ゾーンの再暗号化情報を一覧表示します。スーパーユーザー権限が必要です。
これらの手順では、通常のユーザーまたはHDFSスーパーユーザーとして実行していることを前提としています。環境に合わせて必要に応じてsudo
を使用してください。
# As the normal user, create a new encryption key hadoop key create mykey # As the super user, create a new empty directory and make it an encryption zone hadoop fs -mkdir /zone hdfs crypto -createZone -keyName mykey -path /zone # chown it to the normal user hadoop fs -chown myuser:myuser /zone # As the normal user, put a file in, read it out hadoop fs -put helloWorld /zone hadoop fs -cat /zone/helloWorld # As the normal user, get encryption information from the file hdfs crypto -getFileEncryptionInfo -path /zone/helloWorld # console output: {cipherSuite: {name: AES/CTR/NoPadding, algorithmBlockSize: 16}, cryptoProtocolVersion: CryptoProtocolVersion{description='Encryption zones', version=1, unknownValue=null}, edek: 2010d301afbd43b58f10737ce4e93b39, iv: ade2293db2bab1a2e337f91361304cb3, keyName: mykey, ezKeyVersionName: mykey@0}
distcpの一般的なユースケースの1つは、バックアップと災害復旧の目的でクラスタ間でデータを複製することです。これは通常、HDFSスーパーユーザーであるクラスタ管理者によって実行されます。
HDFS暗号化を使用する場合にこの同じワークフローを有効にするために、ファイルシステムの基になるブロックデータへのスーパーユーザーの直接アクセスを可能にする新しい仮想パスプレフィックス/.reserved/raw/
を導入しました。これにより、スーパーユーザーは暗号化キーにアクセスする必要なく、データの復号化と再暗号化のオーバーヘッドを回避して、データをdistcpできます。また、ソースと宛先のデータがバイト単位で同一になることも意味します。これは、データが新しいEDEKで再暗号化されている場合には当てはまりません。
/.reserved/raw
を使用して暗号化されたデータをdistcpする場合、-pxフラグを使用して拡張属性を保持することが重要です。これは、暗号化されたファイル属性(EDEKなど)が/.reserved/raw
内の拡張属性を通じて公開され、ファイルを復号化できるように保持する必要があるためです。これは、distcpが暗号化ゾーンルート以上で開始された場合、宛先に暗号化ゾーンが存在しない場合は、自動的に宛先に暗号化ゾーンを作成することを意味します。ただし、管理者は潜在的な不測の事態を避けるために、宛先クラスタに同一の暗号化ゾーンを最初に作成することをお勧めします。
デフォルトでは、distcpはファイルシステムによって提供されるチェックサムを比較して、データが宛先に正常にコピーされたことを検証します。暗号化されていない場所または暗号化された場所から暗号化された場所にコピーする場合、基になるブロックデータは宛先で暗号化するために新しいEDEKが使用されるため異なるため、ファイルシステムのチェックサムは一致しません。この場合、チェックサムの検証を回避するために、-skipcrccheckおよび-update distcpフラグを指定します。
HDFSは、暗号化ゾーンの境界を越えたファイルとディレクトリの名前変更を制限します。これには、暗号化されたファイル/ディレクトリを暗号化されていないディレクトリに名前変更すること(例:hdfs dfs mv /zone/encryptedFile /home/bob
)、暗号化されていないファイルまたはディレクトリを暗号化ゾーンに名前変更すること(例:hdfs dfs mv /home/bob/unEncryptedFile /zone
)、および2つの異なる暗号化ゾーン間で名前変更すること(例:hdfs dfs mv /home/alice/zone1/foo /home/alice/zone2
)が含まれます。これらの例では、/zone
、/home/alice/zone1
、および/home/alice/zone2
は暗号化ゾーンであり、/home/bob
は暗号化ゾーンではありません。名前変更は、ソースパスと宛先パスが同じ暗号化ゾーンにあるか、両方のパスが暗号化されていない(暗号化ゾーン内にない)場合にのみ許可されます。
この制限により、セキュリティが強化され、システム管理が大幅に簡素化されます。暗号化ゾーン下のすべてのファイルEDEKは、暗号化ゾーンキーで暗号化されます。したがって、暗号化ゾーンキーが侵害された場合は、すべての脆弱なファイルを特定して再暗号化することが重要です。これは、暗号化ゾーンで最初に作成されたファイルをファイルシステムの任意の場所に名前変更できる場合、根本的に困難です。
上記のルールに従うために、各暗号化ゾーンには、「ゾーンディレクトリ」の下に独自の.Trash
ディレクトリがあります。たとえば、hdfs dfs rm /zone/encryptedFile
の後、encryptedFile
はユーザーのホームディレクトリの下の.Trash
ディレクトリではなく、/zone/.Trash
に移動します。暗号化ゾーン全体が削除されると、「ゾーンディレクトリ」はユーザーのホームディレクトリの下の.Trash
ディレクトリに移動します。
暗号化ゾーンがルートディレクトリ(例えば、/
ディレクトリ)である場合、ルートディレクトリのゴミ箱パスは、ユーザーのホームディレクトリの下の.Trash
ディレクトリではなく、/.Trash
になります。また、ルートディレクトリ内のサブディレクトリまたはサブファイルの名前変更の挙動は、このセクションの冒頭で言及されている/zone
のような一般的な暗号化ゾーンの挙動と一貫性を保ちます。
Hadoop 2.8.0より前のcrypto
コマンドは、.Trash
ディレクトリを自動的にプロビジョニングしません。Hadoop 2.8.0より前に暗号化ゾーンが作成され、その後クラスターがHadoop 2.8.0以上にアップグレードされた場合、-provisionTrash
オプション(例:hdfs crypto -provisionTrash -path /zone
)を使用してゴミ箱ディレクトリをプロビジョニングできます。
これらの悪用は、攻撃者がクラスターマシン(つまり、データノードとネームノード)からハードドライブへの物理的なアクセス権を取得していることを前提としています。
データ暗号化キーを含むプロセスのスワップファイルへのアクセス。
これだけでは、暗号化されたブロックファイルへのアクセスも必要となるため、平文が漏洩することはありません。
これは、スワップを無効にする、暗号化されたスワップを使用する、またはキーがスワップアウトされないようにmlockを使用することで軽減できます。
暗号化されたブロックファイルへのアクセス。
これらの悪用は、攻撃者がクラスターマシン(つまり、データノードとネームノード)へのルートシェルアクセス権を取得していることを前提としています。悪意のあるルートユーザーは、暗号化キーと平文を保持するプロセスのメモリ内状態にアクセスできるため、これらの悪用の多くはHDFSでは対処できません。これらの悪用に対する唯一の軽減策は、ルートシェルアクセスを慎重に制限および監視することです。
暗号化されたブロックファイルへのアクセス。
DEK、委任トークン、平文を取得するためにクライアントプロセスのメモリをダンプします。
転送中の暗号化キーと暗号化されたデータをスニッフィングするためにネットワークトラフィックを記録します。
暗号化されたブロックデータを取得するためにデータノードプロセスのメモリをダンプします。
暗号化されたデータ暗号化キーを取得するためにネームノードプロセスのメモリをダンプします。
これらの悪用は、攻撃者がHDFSを侵害しているが、ルートまたはhdfs
ユーザーシェルアクセス権を持っていないことを前提としています。
暗号化されたブロックファイルへのアクセス。
-fetchImageを介した、暗号化ゾーンと暗号化されたファイルメタデータ(暗号化されたデータ暗号化キーを含む)へのアクセス。
不正なユーザーは、アクセス権を持つファイルのキーを収集し、後でそれらのファイルの暗号化されたデータを復号化するために使用できます。ユーザーがそれらのファイルへのアクセス権を持っていたため、すでにファイルの内容にアクセスできました。これは、定期的なキーローリングポリシーを通じて軽減できます。既存のファイルのEDEKが新しいバージョンのキーを使用するようにするために、キーローリング後には通常、reencryptZoneコマンドが必要です。
完全なキーローリングと再暗号化の手動手順を以下に示します。これらの手順は、キー管理者またはHDFSスーパーユーザーとして実行していることを前提としています。
# As the key admin, roll the key to a new version hadoop key roll exposedKey # As the super user, re-encrypt the encryption zone. Possibly list zones first. hdfs crypto -listZones hdfs crypto -reencryptZone -start -path /zone # As the super user, periodically check the status of re-encryption hdfs crypto -listReencryptionStatus # As the super user, get encryption information from the file and double check it's encryption key version hdfs crypto -getFileEncryptionInfo -path /zone/helloWorld # console output: {cipherSuite: {name: AES/CTR/NoPadding, algorithmBlockSize: 16}, cryptoProtocolVersion: CryptoProtocolVersion{description='Encryption zones', version=2, unknownValue=null}, edek: 2010d301afbd43b58f10737ce4e93b39, iv: ade2293db2bab1a2e337f91361304cb3, keyName: exposedKey, ezKeyVersionName: exposedKey@1}