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