表

加密

师成师成· 更新于 2026-09-28· 阅读 10 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

加密

Iceberg 表加密可保护不可信存储中表数据的机密性与完整性。data、delete、manifest 和 manifest list 文件在发送到存储后端之前会被加密并进行防篡改保护。

metadata.json 文件不包含数据或统计信息,因此不会被加密。

目前,Hive 和 REST 目录支持对使用 Parquet 和 Avro 数据格式的表进行加密。

启用表加密需要两个参数:

  1. 指定 KMS(密钥管理服务)的目录属性。可以使用 encryption.kms-type 指定预定义的 KMS 客户端(aws、azure 或 gcp),或使用 encryption.kms-impl 配合自定义 KMS 客户端的类路径。
  2. 表属性 encryption.key-id,用于指定加密和解密该表所使用的主密钥 ID。主密钥由 KMS 存储和管理。

有关表加密的更多详情,请参阅「附录:内部机制概览」小节。

示例

spark-sql --packages org.apache.iceberg:iceberg-spark-runtime-4.1_2.13:1.11.0\
    --conf spark.sql.extensions=org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions \
    --conf spark.sql.catalog.spark_catalog=org.apache.iceberg.spark.SparkSessionCatalog \
    --conf spark.sql.catalog.spark_catalog.type=hive \
    --conf spark.sql.catalog.local=org.apache.iceberg.spark.SparkCatalog \
    --conf spark.sql.catalog.local.type=hive \
    --conf spark.sql.catalog.local.encryption.kms-type=aws
CREATE TABLE local.db.table (id bigint, data string) USING iceberg
TBLPROPERTIES ('encryption.key-id'='<master-key-id>');

插入的数据将被自动加密,

INSERT INTO local.db.table VALUES (1, 'a'), (2, 'b'), (3, 'c');

要验证加密效果,可以在命令行中使用以下方式转储数据文件、清单文件和清单列表文件的内容

hexdump -C <path/to/file> | more

Parquet 文件必须以 “PARE” 魔法字符串开头(PARquet Encrypted footer 模式),manifest/list 文件必须以 “AGS1” 魔法字符串开头(Aes Gcm Stream version 1)。

查询到的数据将被自动解密,

SELECT * FROM local.db.table;

目录服务安全要求

  1. 目录服务必须确保 encryption.key-id 属性在表的整个生命周期内不会被修改或删除。

  2. 为了正常工作,Iceberg 表加密要求目录服务实现不能直接从 metadata.json 文件中获取元数据,前提是这些文件被无保护地存放在易受篡改的存储中:

    • 目录服务可以将元数据保存在受信任的独立对象存储中。
    • 目录服务可以操作存放在防篡改存储中的 metadata.json 文件。
    • 目录服务可以使用校验和技术来验证存放在易受篡改存储中的 metadata.json 文件的完整性(校验和必须保存在单独的受信任存储中)。

密钥管理客户端

目前,Iceberg 提供了适用于 AWS、GCP 和 Azure KMS 系统的客户端。通过实现 org.apache.iceberg.encryption.KeyManagementClient 接口,可以为其他密钥管理系统构建自定义客户端。

该接口包含以下主要方法:

  /**
   * Initialize the KMS client with given properties.
   *
   * @param properties kms client properties (taken from catalog properties)
   */
  void initialize(Map<String, String> properties);

  /**
   * Wrap a secret key, using a wrapping/master key which is stored in KMS and referenced by an ID.
   * Wrapping means encryption of the secret key with the master key, and adding optional
   * KMS-specific metadata that allows the KMS to decrypt the secret key in an unwrapping call.
   *
   * @param key a secret key being wrapped
   * @param wrappingKeyId a key ID that represents a wrapping key stored in KMS
   * @return wrapped key material
   */
  ByteBuffer wrapKey(ByteBuffer key, String wrappingKeyId);

  /**
   * Unwrap a secret key, using a wrapping/master key which is stored in KMS and referenced by an
   * ID.
   *
   * @param wrappedKey wrapped key material (encrypted key and optional KMS metadata, returned by
   *     the wrapKey method)
   * @param wrappingKeyId a key ID that represents a wrapping key stored in KMS
   * @return raw key bytes
   */
  ByteBuffer unwrapKey(ByteBuffer wrappedKey, String wrappingKeyId);

附录:内部机制概述

标准 Iceberg 加密管理器会为每个数据文件和删除文件生成一个加密密钥和一个唯一的文件 ID("AAD 前缀")。该生成过程在工作节点上执行,使用安全随机数生成器。对于 Parquet 数据文件,这些参数会被传递给 Parquet 原生模块化加密机制。对于 Avro 数据文件,这些参数会被传递给 AES GCM 流式加密机制。

父清单文件在 key_metadata 字段中存储每个数据文件和删除文件的加密密钥与 AAD 前缀。对于 Avro 数据表,数据文件的长度也会添加到 key_metadata 中。清单文件由 AES GCM 流式加密机制加密,所使用的加密密钥和 AAD 前缀由标准加密管理器生成。该生成过程在驱动节点上执行,使用安全随机数生成器。

父清单列表文件在 key_metadata 字段中存储每个清单文件的加密密钥、AAD 前缀和文件长度。清单列表文件由 AES GCM 流式加密机制加密,所使用的加密密钥和 AAD 前缀由标准加密管理器生成。

清单列表的加密密钥、AAD 前缀和文件长度被打包到一个密钥元数据对象中。该对象会被序列化,并使用"密钥加密密钥"(KEK)进行加密,加密时以 KEK 的创建时间戳作为 AES GCM 的 AAD。KEK 及其唯一的 KEK_ID 由安全随机数生成器生成。对于每个快照,用于加密清单列表密钥元数据的加密密钥的 KEK_ID 会保存在表元数据快照结构的 key-id 字段中。加密后的清单列表密钥元数据保存在表元数据结构的 encryption-keys 列表中。

KEK 通过 KMS 客户端由表主密钥加密,加密结果保存在表元数据结构的 encryption-keys 列表中。KEK 会在 NIST SP 800-57 规范允许的期限内重复使用,之后进行轮换——生成新的 KEK 和 KEK_ID,用于加密新的清单列表密钥元数据对象。新的 KEK 由表主密钥加密,并存储在表元数据结构的 encryption-keys 列表中。之前的 KEK 会被保留,以便表的现有快照仍能访问。

评论

登录后参与评论

正在加载评论…