

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# Hive の Parquet モジュラー暗号化
<a name="hive-parquet-modular-encryption"></a>

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

ファイルの暗号化やストレージレイヤーの暗号化など、これまでサポートされていたセキュリティと整合性のソリューションについては、「Amazon EMR Management Guide」の「[Encryption Options](https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-data-encryption-options.html)」で説明されています。これらのソリューションは Parquet ファイルにも使用できますが、統合された Parquet 暗号化メカニズムの新機能を活用することで、列レベルへのきめ細かなアクセスが可能になり、パフォーマンスとセキュリティも向上します。この機能について詳しくは、Apache GitHub のページ「[Parquet Modular Encryption](https://github.com/apache/parquet-format/blob/master/Encryption.md)」を参照してください。

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

## 使用例
<a name="usage-examples"></a>

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

1. ドキュメント [PARQUET-1373: 暗号化キー管理ツール](https://docs.google.com/document/d/1bEu903840yb95k9q2X-BlsYKuXoygE4VnMDl9xz_zhk/edit)で説明されているように、 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;
       }
   }
   ```

1. 「 *AWS Key Management Service デベロッパーガイド*」の「キー[の作成](https://docs.aws.amazon.com/kms/latest/developerguide/create-keys.html)」で説明されているように、フッターの AWS KMS 暗号化キーと、IAM ロールがアクセスできる列を作成します。デフォルトの IAM ロールは EMR\$1ECS\$1default です。

1. Amazon EMR クラスター上の Hive アプリケーションで、[Apache Hive Resources ドキュメント](https://cwiki.apache.org/confluence/display/Hive/LanguageManual+Cli#LanguageManualCli-HiveResources)で説明されているように、`ADD JAR` ステートメントを使用して上記のクライアントを追加します。ステートメントの例を以下に示します。

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

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

   ```
   aws s3 cp 's3://location-to-custom-jar' /usr/lib/hive/auxlib 
   ```

1. 以下の設定を行います。

   ```
   set parquet.crypto.factory.class=org.apache.parquet.crypto.keytools.PropertiesDrivenCryptoFactory;
   set parquet.encryption.kms.client.class=org.apache.parquet.crypto.keytools.AwsKmsClient;
   ```

1. 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;
   ```

1.  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;
   ```

1. 最後のステートメントでは次の例外が発生するはずです。

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