Hive の Parquet モジュラー暗号化 - Amazon EMR

Hive の Parquet モジュラー暗号化

Parquet モジュラー暗号化では、列レベルのアクセス制御と暗号化が可能になり、Parquet ファイル形式で保存されたデータのプライバシーとデータ整合性が強化されます。この機能は、リリース 6.6.0 以降の Amazon EMR Hive で使用できます。

ファイルの暗号化やストレージレイヤーの暗号化など、これまでサポートされていたセキュリティと整合性のソリューションについては、「Amazon EMR Management Guide」の「Encryption Options」で説明されています。これらのソリューションは Parquet ファイルにも使用できますが、統合された Parquet 暗号化メカニズムの新機能を活用することで、列レベルへのきめ細かなアクセスが可能になり、パフォーマンスとセキュリティも向上します。この機能について詳しくは、Apache GitHub のページ「Parquet Modular Encryption」を参照してください。

ユーザーは Hadoop 設定を使用して Parquet のリーダーとライターに設定を渡します。ユーザーがリーダーとライターを設定して暗号化を有効にしたり、高度な機能を切り替えたりするための詳細な設定については、「PARQUET-1854: Properties-driven Interface to Parquet Encryption Management」に記載されています。

使用例

次の例では、暗号化キーの管理に AWS KMS を使用する Hive テーブルの作成と書き込みについて説明しています。

  1. ドキュメント「PARQUET-1373: Encryption Key Management Tools」で説明されているように、AWS KMS サービス用の KMSClient を実装します。次の例は、実装スニペットを示しています。

    package org.apache.parquet.crypto.keytools; import com.amazonaws.AmazonClientException; import com.amazonaws.AmazonServiceException; import com.amazonaws.regions.Regions; import com.amazonaws.services.kms.AWSKMS; import com.amazonaws.services.kms.AWSKMSClientBuilder; import com.amazonaws.services.kms.model.DecryptRequest; import com.amazonaws.services.kms.model.EncryptRequest; import com.amazonaws.util.Base64; import org.apache.hadoop.conf.Configuration; import org.apache.parquet.crypto.KeyAccessDeniedException; import org.apache.parquet.crypto.ParquetCryptoRuntimeException; import org.apache.parquet.crypto.keytools.KmsClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; public class AwsKmsClient implements KmsClient { private static final AWSKMS AWSKMS_CLIENT = AWSKMSClientBuilder .standard() .withRegion(Regions.US_WEST_2) .build(); public static final Logger LOG = LoggerFactory.getLogger(AwsKmsClient.class); private String kmsToken; private Configuration hadoopConfiguration; @Override public void initialize(Configuration configuration, String kmsInstanceID, String kmsInstanceURL, String accessToken) throws KeyAccessDeniedException { hadoopConfiguration = configuration; kmsToken = accessToken; } @Override public String wrapKey(byte[] keyBytes, String masterKeyIdentifier) throws KeyAccessDeniedException { String value = null; try { ByteBuffer plaintext = ByteBuffer.wrap(keyBytes); EncryptRequest req = new EncryptRequest().withKeyId(masterKeyIdentifier).withPlaintext(plaintext); ByteBuffer ciphertext = AWSKMS_CLIENT.encrypt(req).getCiphertextBlob(); byte[] base64EncodedValue = Base64.encode(ciphertext.array()); value = new String(base64EncodedValue, Charset.forName("UTF-8")); } catch (AmazonClientException ae) { throw new KeyAccessDeniedException(ae.getMessage()); } return value; } @Override public byte[] unwrapKey(String wrappedKey, String masterKeyIdentifier) throws KeyAccessDeniedException { byte[] arr = null; try { ByteBuffer ciphertext = ByteBuffer.wrap(Base64.decode(wrappedKey.getBytes(StandardCharsets.UTF_8))); DecryptRequest request = new DecryptRequest().withKeyId(masterKeyIdentifier).withCiphertextBlob(ciphertext); ByteBuffer decipheredtext = AWSKMS_CLIENT.decrypt(request).getPlaintext(); arr = new byte[decipheredtext.remaining()]; decipheredtext.get(arr); } catch (AmazonClientException ae) { throw new KeyAccessDeniedException(ae.getMessage()); } return arr; } }
  2. 「AWS Key Management Service 開発者ガイド」の「Creating keys」で説明されているように、アクセス権を持つ IAM ロールを含むフッターと列の AWS KMS 暗号化キーを作成します。デフォルトの IAM ロールは EMR_ECS_default です。

  3. Amazon EMR クラスター上の Hive アプリケーションで、Apache Hive Resources ドキュメントで説明されているように、ADD JAR ステートメントを使用して上記のクライアントを追加します。ステートメントの例を以下に示します。

    ADD JAR 's3://location-to-custom-jar';

    別の方法として、ブートストラップアクションを使用して JAR を Hive の auxlib に追加する方法があります。ブートストラップアクションに追加する行の例を以下に示します。

    aws s3 cp 's3://location-to-custom-jar' /usr/lib/hive/auxlib
  4. 以下の設定を行います。

    set parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory; set parquet.encryption.kms.client.class=org.apache.parquet.crypto.keytools.AwsKmsClient;
  5. Parquet 形式の Hive テーブルを作成し、SERDEPROPERTIES で AWS KMS キーを指定し、そこにデータを挿入します。

    CREATE TABLE my_table(name STRING, credit_card STRING) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe’ WITH SERDEPROPERTIES ( 'parquet.encryption.column.key’=<aws-kms-key-id-for-column-1>: credit_card’, 'parquet.encryption.footer.key’='<aws-kms-key-id-for-footer>’) STORED AS parquet LOCATION “s3://<bucket/<warehouse-location>/my_table”; INSERT INTO my_table SELECT java_method ('org.apache.commons.lang.RandomStringUtils','randomAlphabetic',5) as name, java_method ('org.apache.commons.lang.RandomStringUtils','randomAlphabetic',10) as credit_card from (select 1) x lateral view posexplode(split(space(100),' ')) pe as i,x; select * from my_table;
  6. AWS KMS キーにアクセスできない (例えば IAM ロールのアクセスが拒否された) 外部テーブルを同じ場所に作成すると、データを読み取ることができないことを確認します。

    CREATE EXTERNAL TABLE ext_table (name STRING, credit_card STRING) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe’ STORED AS parquet LOCATION “s3://<bucket>/<warehouse-location>/my_table”; SELECT * FROM ext_table;
  7. 最後のステートメントでは次の例外が発生するはずです。

    Failed with exception java.io.IOException:org.apache.parquet.crypto.KeyAccessDeniedException: Footer key: access denied