4、TDE密钥体系:数据库加密密钥(DEK)、证书/主密钥(CMK)、密钥存储与保护机制

TDE 的密钥体系,说白了就是一把钥匙锁着一把钥匙。最底层那把锁住数据页的钥匙叫 DEK,上面一层用 CMK 来保护它。你想想看,如果所有密钥都明文存着,那加密还有什么意义?

我记得刚接手第一个 TDE 项目时,文档里画了个三层密钥塔,我当时觉得嵌套解密会影响性能。后来才发现,这个分层设计是为了让密钥轮换和权限分离变得可行。下面我拆开来说。

4.1 数据库加密密钥(DEK)

DEK 是直接加密数据页的对称密钥。长度通常 128 位或 256 位,AES 算法。它的特点是:

  • 数据库级别唯一:每个启用了 TDE 的数据库都有一份独立的 DEK。
  • 自动生成:在启用 TDE 时由 SQL Server 内部创建,不需要你手动指定。
  • 存储在数据文件中:DEK 本身会被 CMK 加密后写到数据库的 boot page 里。所以数据库文件即使被复制走,没有 CMK 也读不出 DEK。

这里有个坑:DEK 轮换不是直接替换 DEK,而是用新的 CMK 重新加密现有的 DEK。我在项目中遇到过,有人以为 DEK 轮换需要重建整个数据库——其实只要 ALTER DATABASE ENCRYPTION KEY 重新加密就行。

我的习惯:DEK 生成后立刻备份证书或密钥文件。不要等数据库跑起来了再去找备份路径,那时候可能已经忘了存在哪台机器上。

4.2 证书 / 主密钥(CMK)

CMK 是保护 DEK 的那把“主钥匙”。它可以是一个证书(包含非对称密钥对),也可以是一个存储在外部密钥管理器中的对称密钥。SQL Server 默认使用 CREATE CERTIFICATE 创建的证书作为 CMK。

CMK 的职责很简单:

  • 加密 DEK 的明文副本
  • 解密 DEK 到内存中用于数据页的加解密操作

CMK 本身又受数据库主密钥(DMK)或服务主密钥(SMK)保护。这个链条是这样的:

层级 密钥 保护对象 存储位置
Level 1 服务主密钥 SMK DMK / CMK 操作系统 DPAPI
Level 2 数据库主密钥 DMK 证书私钥 master 数据库
Level 3 证书 CMK DEK master 数据库
Level 4 数据库加密密钥 DEK 数据页 用户数据库 boot page

如果你用的是 Azure Key Vault 或硬件安全模块(HSM),CMK 可以托管在外部,SQL Server 只保留一个指针。这种方式的好处是:即便整个数据库服务器被攻破,CMK 仍安全地待在 HSM 里。我在一次审计中遇到过,客户要求 CMK 必须由第三方密钥管理系统生成,我们就是通过扩展密钥管理(EKM)接口对接的。

4.3 密钥存储与保护机制

密钥存储不能“所有鸡蛋放一个篮子里”。实际部署中,我建议至少考虑三个存储位置:

  1. 本地加密存储:SMK 通过 Windows DPAPI 加密,存放在本机。这只能做第一道防线。
  2. 备份文件:证书和私钥必须备份到安全位置(比如离线磁带或加密U盘)。备份命令如:
    BACKUP CERTIFICATE TDE_Cert TO FILE = 'C:\Backup\TDE_Cert.cer'
    WITH PRIVATE KEY (FILE = 'C:\Backup\TDE_Cert.pvk',
                      ENCRYPTION BY PASSWORD = 'Str0ng!Passw0rd');
  3. 外部密钥存储:HSM(如 Thales、Gemalto)或云密钥服务(AWS KMS、Azure Key Vault)。适合需要合规审计的场景。
曾经踩过的坑:某个项目里,DBA 把证书备份放在了数据库服务器同一块磁盘上。后来磁盘故障,证书连同数据一起丢了。恢复时才发现备份策略没覆盖 CMK。从那以后,我坚持证书备份必须放到异地,并且定期验证备份有效性。

保护机制还包括访问控制:只有具备 CONTROL SERVER 权限的账号才能操作 CMK。而且 CMK 的私钥默认不能导出(除非指定 WITH PRIVATE KEY 并且知道密码)。

4.4 密钥体系全景图

下面这张图把上面讲的层级、关系和保护路径串起来了。你可以把它当作一个速查手册:

TDE 密钥体系结构图 服务主密钥 SMK DPAPI 加密(系统级) 数据库主密钥 DMK 证书(CMK) HSM / 外部密钥存储 数据库加密密钥 DEK 数据页(AES 加密) 备份证书 + 私钥到安全位置

4.5 实践中的避坑指南

  • 证书过期:SQL Server 证书默认有效期一年。如果证书过期,DEK 解密会失败,数据库无法正常启动。我在项目里遇到过一次半夜报警,就是因为证书到期,而自动轮换脚本还没写好。建议用 CREATE CERTIFICATE ... WITH EXPIRY_DATE = '9999-12-31' 或配置自动续期。
  • 丢失私钥:恢复数据库时需要 CMK 的私钥。如果只备份了公钥 (.cer),DEK 解不出来。备份命令一定要带 WITH PRIVATE KEY,并且记住你设置的加密密码。
  • 跨服务器恢复:你不能把启用了 TDE 的数据库备份直接恢复到另一台服务器上,必须在那台服务器上创建相同的证书(基于备份文件)。
一句话总结密钥体系:DEK 保护数据页,CMK 保护 DEK,SMK/DMK 保护 CMK。每层独立,隔离风险。备份时千万记住:钥匙和锁芯不能放在同一个抽屉里。

有的团队会在同一个服务器上用同一个证书保护多个数据库的 DEK,你想想看,这样虽然管理方便,但一个数据库的泄露可能让攻击者间接获得解密其他数据库的能力。所以我个人倾向每个数据库使用独立的证书,通过命名区分,比如 TDE_Cert_DB_Sales、TDE_Cert_DB_HR。