MySQL透明加密概述
透明加密TDE
透明加密,是指文件在使用过程中自动的进行加密解密,无需用户干预,用户实际上是无感的。存储的文件在磁盘上始终是密文,一旦离开使用环境,加密的文件无法打开或打开是乱码,从而起到保护文件内容的效果。
MySQL透明加密功能
MySQL提供透明加密功能,对数据文件进行加密,可以加密的文件包括:
- Innodb引擎的数据文件(表加密/redo log加密/undo log加密)
- Binlog/Relay log文件
- 持久化的系统变量文件
- 审计日志文件(企业版特性)
在不影响MySQL实例使用、对用户数据库操作无感的情况下,对存储文件进行加密/解密操作。
MySQL透明加密分析
以Innodb引擎的表加密为例,对MySQL的透明加密进行分析。
密钥管理组件
MySQL提供密钥管理组件来获取并维护透明加密使用的密钥,密钥管理组件以插件(Keyring Plugin)的方式装载在MySQL实例中。
在MySQL Server层,Keyring Plugin通过与不同的密钥管理服务器进行交互,生成、获取密钥并对密钥进行管理。在Innodb引擎层,通过Keyring插件提供的标准接口(包括generate key、fetch key等)提供加密使用的密钥。
当前MySQL实现的Keyring插件包括:
- keyring_file(开源版本):基于本地文件的密钥管理插件
- keyring_encrypted_file(企业版):基于本地文件的密钥管理插件,文件为加密文件。
- keyring_okv(企业版):基于Key Management Interoperability Protocol (KMIP) 协议的密钥管理插件。
- keyring_aws(企业版):基于Amazon Web Services Key Management 的密钥管理插件。
- keyring_hashicorp(企业版):基于hashicorp vault的密钥管理插件
- keyring_oci(企业版):基于Oracle Cloud Infrastructure Vault的密钥管理插件
大多数为企业版定制的Keyring插件,这里可以根据实际的KMS(Key Management service)来定制Keyring插件。
Innodb表加密
Innodb引擎的表解密使用二次加密的方式进行加密,通过Keyring插件获取到的密钥并不直接用来加密数据,而是用来对数据加密的密钥进行加密。
加密使用
Innodb引擎表可以在创建表时指定表加密:
mysql> CREATE TABLE t1 (c1 INT) ENCRYPTION = 'Y';
或者通过修改表的属性来指定表加密:
mysql> ALTER TABLE t1 ENCRYPTION = 'Y';
当指定表加密时,需要至少装载了一种Keyring插件,来获取密钥。如果未装载任何Keyring插件会执行DDL失败。
mysql> CREATE TABLE t1 (c1 INT) ENCRYPTION = 'Y';
ERROR 3185 (HY000): Can't find master key from keyring, please check in the server log if a keyring plugin is loaded and initialized successfully.
密钥获取
Innodb引擎表加密使用二次加密的方式,涉及到两个密钥:
- 数据加密密钥:用来对表中的记录进行加密;
- 密钥加密密钥:用来对数据加密密钥进行加密的密钥;
数据加密密钥是在创建表或者修改表加密属性时随机生成的密钥:
# 在初始化表的文件内存结构时,随机生成用来加密的密钥
fsp_header_init
| fsp_header_fill_encryption_info
| Encryption::random_value(space->encryption_key);
| Encryption::random_value(space->encryption_iv);
密钥加密密钥是通过Keyring插件获取的外部输入的密钥,对随机生成的数据加密密钥进行加密,并持久化到文件中:
fsp_header_init
| fsp_header_fill_encryption_info
# 1 通过keyring插件获取密钥
| Encryption::get_master_key(&master_key_id …
# 2 缓存随机生成的数据加密密钥
| memcpy(key_info,space->encryption_key, ENCRYPTION_KEY_LEN);
| memcpy(key_info,space->encryption_iv, ENCRYPTION_KEY_LEN);
# 3 对密钥进行加密
| my_aes_encrypt(key_info,ENCRYPTION_KEY_LEN * 2, ptr, …
数据加密
在第一次使用加密表时,需要通过Keyring插件获取外部密钥,通过外部密钥将文件中的数据加密密钥进行解密,并缓存到实例中,用于后续对数据进行加密/解密:
fsp_header_get_encryption_key
| fsp_header_decode_encryption_info
# 1. 通过keyring插件获取密钥
| Encryption::get_master_key(master_key_id …
# 2. 使用外部密钥对文件中的数据加密密钥进行解密
# 缓存在内容中,用于后续数据的加密和解密
| my_aes_decrypt( … key_info …
对于表中的数据文件进行加密/解密,只有在IO操作时进行,所有存放在内存的数据页(PAGE)均为解密后的明文数据:
fil_io
# 使用space中暂存的数据加密密钥
| req_type.encryption_key(space->encryption_key …
# 1. IO读操作
| os_file_read(req_type, node->handle, buf, offset, len)
# 2. IO写操作
| os_file_write( req_type, node->name, node->handle …
总结
MySQL透明加密功能总结如下:
- MySQL通过Keyring插件与外部进行交互,提供给用户自定义密钥输入的接口。
- 在Innodb引擎的表加密中,使用二次加密的方式进行加密。
- 数据加密密钥为内部随机生成的密钥(RANDOM KEY)。
- 外部输入的密钥(INPUT KEY)只用来加密数据加密密钥(RANDOM KEY)。
- 加密后的数据加密密钥和加密后的数据一同存放在表文件中
透明加密的原理图如下: