数据工程面试:如何保护 Parquet 中的敏感列?
题干与适用场景
数据湖中的 Parquet 文件同时包含邮箱、支付标识、地区和可公开统计指标。对象存储、元数据服务和计算集群由不同团队管理;授权作业需要只读取必要列,未授权读者不能看到敏感值或可推断身份的元数据。请设计列级加密和密钥管理方案,说明页脚、列索引、谓词下推、密钥轮换、旧读者兼容与故障恢复。
Apache Parquet 的 Modular Encryption 把文件拆成页、页头、列索引、偏移索引、Bloom filter 和页脚等模块分别保护,仍可保留列投影、谓词下推、编码和压缩能力。强回答要区分“加密数据”“保护元数据”“控制密钥访问”和“证明读写正确”四个边界。
面试官考察点
- 能否解释列密钥、页脚密钥、数据密钥和主密钥的关系。
- 是否知道仅加密敏感列仍可能暴露 schema、统计信息或列名。
- 能否在 encrypted footer 与 plaintext footer 之间说明安全性、兼容性和迁移成本。
- 是否理解 AES-GCM 的完整性与 AAD 防替换作用,以及 CTR 页面模式的限制。
- 是否能把 KMS、授权、轮换、备份、查询失败和审计串成可执行方案。
普通回答会说“用 AES-256 加密文件”;强回答会证明哪些 Parquet 模块被保护、谁能拿到哪把钥匙,以及旧读者和谓词下推分别付出什么代价。
回答前需要澄清的问题
- 需要隐藏整个 schema、行数和统计信息,还是只需保护列值?这决定是否必须加密 footer。
- 哪些作业、租户和列可以共同访问?这决定列密钥分组与 KMS 授权边界。
- 查询引擎和 PyArrow/Parquet 库版本是否支持 Modular Encryption?否则读写链路不能直接切换。
- 旧读者是否必须继续读取未加密列?这决定是否采用 plaintext footer 过渡模式。
- 文件是不可变分区还是会被覆盖、复制和回放?这决定 AAD 文件身份、轮换与重放检测。
30 秒回答框架
“我先决定是否保护 footer 和统计信息,再按敏感列划分访问域。文件数据使用随机 DEK,DEK 由 KMS 管理的 MEK 或 KEK 封装;列页、页头、索引和必要的列元数据使用列密钥,footer 单独保护。默认优先 AES-GCM,因为它同时提供机密性和完整性,并用绑定文件与模块身份的 AAD 防止跨文件替换。若旧读者必须访问公开列,可以短期使用 plaintext footer,但明确它会暴露部分元数据;敏感数据和高风险 schema 则使用 encrypted footer。上线前验证 KMS 授权、密钥轮换、谓词下推、错误恢复、旧读者行为和篡改测试。”
分步骤深入解答
1. 先列出需要保护的 Parquet 模块
Parquet 不是一个只有数据区的黑盒。页和页头承载列值,column index、offset index 和 Bloom filter 可能透露范围或值分布,footer 还包含 schema、行数、排序、统计和 key-value metadata。只加密列页而留下所有元数据,仍可能泄露客户类型或时间范围。
file
├── row-group
│ └── column chunk
│ ├── dictionary/data pages
│ ├── page headers
│ ├── column index
│ ├── offset index
│ └── bloom-filter modules
└── footer / FileMetaData先按威胁模型决定保护集合:低敏列可保持可读以支持旧工具;敏感列及其统计、schema 和文件身份需要更严格的 footer 与列元数据保护。这个决策比单独选择 AES 密钥长度更重要。
2. 设计信封加密与访问边界
每个文件或列使用随机数据加密密钥(DEK),由主密钥(MEK)或密钥加密密钥(KEK)封装。MEK 保留在组织的 KMS 中,作业通过短期身份获取解封权限;对象存储只保存密文和必要的 key metadata,不保存明文主密钥。
authorized job -> KMS policy -> unwrap DEK -> decrypt footer/columns
object storage -> ciphertext + key metadata only按租户、数据域或敏感等级划分列密钥,避免一个作业拿到整张表的解密权限。密钥 metadata 只能是 KMS key ID、封装材料标识或外部引用;它不是秘密本身,但会影响审计与轮换。轮换主密钥时优先重新封装 DEK;不可变文件不应因为换 MEK 就重写全部数据页。
3. 在 encrypted footer 与 plaintext footer 之间选择
encrypted footer 隐藏 schema、行数、列名、排序信息和更多列元数据,安全边界完整,但所有读取敏感文件的读者都必须支持模块加密。Parquet 文件会使用 PARE magic bytes,让旧读者立即知道它不能按普通 PAR1 文件解析。
plaintext footer 仍允许旧版本读者看到部分元数据并读取未加密列;敏感列的数据页不能被旧读者读取,footer 还会以签名方式保护完整性。它适合有明确迁移期限的过渡,不适合把统计信息也视为敏感的场景。
迁移计划应按读者矩阵逐个验证:查询引擎是否能发现加密列、未授权访问是否失败、只读公开列是否仍能下推谓词,以及旧读者是否会把异常误判为损坏文件。
4. 选择算法并绑定 AAD
AES-GCM 同时提供加密与认证标签;AAD 可把表名、分区、文件版本和模块位置绑定到密文,阻止攻击者把同一密钥下的旧文件、别的分区或别的 row group 模块替换进当前文件。随机 nonce 必须对同一密钥保持唯一,密钥调用次数也要有跨 writer 的预算。
Parquet 还定义 AESGCMCTRV1:非页模块使用 GCM,而数据页使用 CTR 以换取吞吐;CTR 页本身不提供 GCM 的认证完整性。因此,安全要求包含页面篡改检测时应优先 AESGCM_V1,不能只比较 CPU 速度。
5. 保留查询能力并定义失败路径
加密发生在压缩后的页和其他模块上,格式仍可表达列投影、谓词下推、编码和压缩。查询规划器可以先读取可见 footer 或索引,再只请求有权限的列;但如果 footer 或 column index 被加密,规划器必须具备相应解密权限,不能假设“只查公开列”就完全不需要密钥。
解密失败、KMS 超时、权限撤销、AAD 不匹配和认证标签错误必须分别记录。错误处理不能自动改用明文路径,也不能把所有失败都归为文件损坏。读取服务应保留文件 ID、key metadata、算法版本和审计主体,但不记录 DEK、明文列值或完整密钥材料。
6. 验证轮换、篡改与灾备
测试至少包括:未授权读敏感列、授权读公开列、授权读敏感列、替换旧文件、交换两个 row group、修改密文页、KMS 拒绝、密钥轮换后回读和跨区域灾备。对每个测试记录预期错误类型、是否读取到明文和审计事件。
数据恢复要同时备份加密文件、key metadata、KMS 密钥版本映射和 AAD 文件身份。只恢复对象存储而没有 KMS 权限会得到不可读文件;只恢复 KMS 而丢失 AAD 前缀也可能无法验证文件身份。轮换作业要有旧密钥保留窗口,等所有快照、回放和备份验证完成后再销毁。
高质量示范回答
“我会先明确威胁模型:是否隐藏 schema、行数和统计,以及哪些作业可以访问哪些列。Parquet Modular Encryption 保护的不只是列页,还可以保护页头、column index、offset index、Bloom filter 和 footer。我会为文件或列生成随机 DEK,由 KMS 中的 MEK/KEK 封装;作业只通过短期身份获得解封权限,文件里只保存可审计的 key metadata。
安全边界完整时使用 encrypted footer;若旧读者必须读取公开列,可以在有期限的迁移期使用 plaintext footer,但明确它会暴露部分元数据。算法优先 AES-GCM,用 AAD 绑定表、分区、文件版本和模块位置,防止密文替换;不会因为 CTR 页面更快就忽略其页面完整性限制。上线前我会验证列投影和谓词下推、KMS 拒绝、AAD 篡改、密钥轮换、跨区域恢复和旧读者行为,并确认日志没有 DEK、明文或密钥材料。这个方案把加密、授权、查询和恢复分成可测试的边界。”
常见错误
- 只给 Parquet 文件做存储层加密 → 获得对象存储权限的读者仍能读取所有列 → 按列、footer 和模块设计访问边界。
- 只加密敏感页,不管 footer → schema、统计和行数可能暴露敏感信息 → 按威胁模型选择 encrypted footer 或明确 plaintext footer 的泄露范围。
- 把 DEK 当作长期主密钥 → 单个文件泄露会扩大轮换和撤销影响 → 用 KMS MEK/KEK 封装随机 DEK。
- 忽略 AAD → 同一密钥下的旧文件或其他分区可能被替换 → 绑定文件和模块身份,并测试交换攻击。
- 把 AESGCMCTR_V1 当成全量认证 → CTR 页面可能没有 GCM 页面认证 → 按完整性要求选择算法并验证篡改错误。
- 轮换后立即删除旧密钥 → 快照、备份和回放任务无法恢复 → 保留版本映射和受控旧密钥窗口。
追问及应对
公开列需要继续支持旧版读者,怎么迁移?
先用 plaintext footer 保护敏感列数据页,同时让旧读者只读公开列;记录它们暴露的 schema 和统计范围。设定升级期限,完成新读者覆盖与回放测试后再切 encrypted footer,并保留回滚文件版本。
如何防止把另一分区的密文页拷进当前文件?
为文件、表、分区、row group 和模块构造稳定的 AAD 身份。读取时 AAD 不匹配应触发认证失败;测试同一密钥下交换旧版本、不同分区和不同列页,确认全部被拒绝。
KMS 每次读页都会产生延迟吗?
不要把 KMS 调用放在每个页的热路径。使用 KMS 解封 DEK 或 KEK,再在受控进程内缓存短生命周期材料;限制缓存范围和 TTL,轮换或权限撤销时主动失效,并监控 KMS 错误与缓存命中。
为什么不能只使用 AES-CTR 获得更高吞吐?
CTR 不提供认证完整性,页面被修改时可能无法发现。若威胁模型要求检测篡改,使用 AES-GCM;只有在明确接受完整性取舍且有外层校验时,才评估 CTR 模式。
如何证明谓词下推没有绕过授权?
在授权和未授权身份下分别执行只查公开列、过滤敏感列和投影敏感列的查询,检查规划器请求的模块与 KMS 权限。审计应能关联查询、文件、列、key metadata 和拒绝原因,不能只看最终返回行数。