如何为Mongo客户端字段级加密轮换KMS加密密钥
MongoDB 客户端字段级加密(CSFLE)密钥轮换实操说明
直接给结论:CSFLE有成熟可行的密钥轮换方案,不需要从零手写全量加解密逻辑,但不同密钥层级的轮换操作逻辑差异很大,部分场景确实需要在窗口期保留新旧密钥的访问权限,不是所有轮换都要重跑全量业务数据。
- 先理清楚CSFLE的两层信封加密结构,很多人找不到对应轮换方案,本质是混淆了两层密钥的定位:
- 第一层是客户主密钥(CMK):也就是绝大多数合规要求里年度轮换的根密钥,一般托管在KMS服务中,从来不直接加密业务字段数据
- 第二层是数据加密密钥(DEK):实际用来加密表中字段值的工作密钥,本身会被CMK加密后,存储在Mongo内部的key vault专用集合里
- 针对CMK的年度轮换(90%以上的合规轮换需求都属于这一类):完全不需要重加密存量业务数据
你只需要生成新的CMK,调用驱动自带的密钥重包装接口,用新CMK重新加密key vault里的所有存量DEK,替换掉DEK原来的密文存储即可。因为业务字段的密文本身是用DEK加密的,DEK的明文内容全程没有变化,只是加密DEK的根密钥换了,所以业务数据完全不需要动,整个过程不需要解密任何业务字段,对线上业务几乎无感知。 - 针对DEK的轮换(一般只有DEK疑似泄露、加密算法到期等特殊场景才需要做):
这个场景确实需要在轮换窗口期同时持有新旧两套密钥(包括解密旧DEK所需的CMK访问权限),但不需要手写底层解密、重加密逻辑:- 先在客户端加密配置中添加新生成的DEK作为默认加密密钥,同时保留旧DEK的解密权限
- 之后配置后台批量任务逐批扫描存量集合:读出文档时驱动会自动用旧DEK解密加密字段,写回时驱动会自动用当前默认的新DEK重新加密对应字段
- 等全集合扫描完成、校验所有存量字段都已经用新DEK完成重加密后,再把旧DEK标记为禁用、逐步回收旧密钥的访问权限即可
- 实操避坑点:
- 绝对不要在轮换流程全量校验通过前撤销旧密钥的访问权限,否则历史加密数据会直接无法解密
- CMK轮换完成后要逐一校验所有DEK都已经用新CMK完成重包装,再下线旧CMK,否则会导致DEK无法解锁、全量加密数据不可读
- 重加密存量数据时要控制批量扫描的速率和批次大小,避免瞬间打满集群IO、CPU影响线上正常业务
内容的提问来源于stack exchange,提问作者Pat
相关产品推荐
相关产品推荐

