背景介绍
为了保障数据安全,MySQL 在 5.7 版本就支持了 InnoDB 表空间加密,之前写了一篇月报介绍过,参考InnoDB 表空间加密。文章开头也提到过,MariaDB 除了对表空间加密,也可以对 redo log 和 binlog 加密,本质上 redo log 和 binlog 中也保存着明文的数据,如果文件被拖走数据也有丢失的风险,因此在 MySQL 8.0 中也支持两种日志的加密,本文介绍 Binlog 的加密方式,建议先了解一下表空间加密,更容易理解。
使用方式
首先需要在 DB 启动的时候加载 Keyring,关于 Keyring 可以参考官方文档 或者上个小节提到的表空间加密的月报。
[mysqld]
early-plugin-load=keyring_file.so
控制是否对 Binlog 文件加密的开关是:binlog_encryption ,此开关可以动态打开或者关闭,修改会引起一次 Binlog rotate。需要用户具有 BINLOG_ENCRYPTION_ADMIN 权限。
mysql> set global binlog_encryption = ON;
配置完成后新的 Binlog 文件就是加密的了,加密是文件级别的,可以查看具体哪个文件被加密了:
mysql> show binary logs;
+------------------+-----------+-----------+| Log_name | File_size | Encrypted |
+------------------+-----------+-----------+| mysql-bin.000001 | 178 | No |
| mysql-bin.000002 | 178 | No |
| mysql-bin.000003 | 202 | No |
| mysql-bin.000004 | 714 | Yes |
| mysql-bin.000005 | 178 | No |
| mysql-bin.000006 | 178 | No |
| mysql-bin.000007 | 856 | No |
| mysql-bin.000008 | 707 | Yes |
+------------------+-----------+-----------+
原理解析
同样为了支持 Key rotate,秘钥分为 master key 和 file password, 其中 master key 保存在 keyring 中,用来加密 file password, 这样每次 key rotate 的时候,只需要用新的 master key 把所有 Binlog 文件的 file password 重新加密一遍即可。
如图所示,master key 的密文是保存在 Keyring 中的,明文是固定的格式: MySQLReplicationKey_{UUID}_{SEQ_NO} , 其中 SEQ_NO 是每次 Key rotate 的时候自增的。因为由明文获得 Keyring 中的密文是不可逆的加密,因此明文简单点也不要紧,我们需要保证的是 Keyring 的安全。
filepassword 是保存在每个 Binlog 文件的头部的,文件头部新增的数据格式如下:
这部分是不加密的,一个文件是否加密是用 Magic num 来确定的,(0xFE62696E) 不加密, (0xFD62696E), 加密。每次打开一个文件的时候,都先判断 Magic num,确定是否需要解密。Version 不用多解释,数据格式高低版本兼容的时候用的到。Encryption Key Id 保存的就是 master key 的明文。File Password 就是加密过之后的 filepassword。IV 是从 OpenSSL 中随机生成的,解密算法需要 key 和 IV。
<