Hive 中的 Parquet 模块化加密 - Amazon EMR
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Hive 中的 Parquet 模块化加密

Parquet 模块化加密提供列级访问控制和加密功能,以增强以 Parquet 文件格式存储的数据的隐私和数据完整性。Amazon EMR Hive 从版本 6.6.0 起提供此功能。

有关以前支持的安全性和完整性解决方案,包括文件加密或存储层加密的信息,详见《Amazon EMR 管理指南》中的 加密选项。这些解决方案可以用于 Parquet 文件,但是利用集成 Parquet 加密机制的新功能可以在列级别实现精细访问控制,并提高性能和安全性。有关此功能的更多信息,请访问 Apache github 页面 Parquet 模块化加密

用户使用 Hadoop 配置将配置传递给 Parquet 读取器和写入器。有关用户配置读取器和写入器以启用加密以及切换高级功能的详细配置,详见 PARQUET-1854:Parquet 加密管理的属性驱动接口

用法示例

以下示例涉及使用 Amazon KMS 创建加密密钥并写入 Hive 表以进行加密密钥管理。

  1. 如文档 PARQUET-1373:加密密钥管理工具中所述,为 Amazon 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. 按照Amazon Key Management Service 开发人员指南中的创建密钥中所述,为页脚以及您的 IAM 角色具有访问权限的列创建 Amazon KMS 加密密钥。默认 IAM 角色为 EMR_ECS_default。

  3. 按照 Apache Hive 资源文档 所述,在 Amazon EMR 集群上的 Hive 应用程序中,使用上述 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 中指定 Amazon 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. 验证当您在同一位置创建无法访问 Amazon 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