环境:win10

插件:keyring_file

mysql:8.0

一、win10环境下的安装keyring_file插件

1、前言

从5.7.11开始,mysql开始支持物理表空间的加密,它使用两层加密架构。包括:主密钥(master key) 和 表空间加密密钥(tablespace key)。

主密钥用于加密加密密钥,加密后的加密密钥存储在表空间文件的header中。加密密钥用于加密数据。当用户想访问加密的表时,innoDB会先用 主密钥 对之前存储在表空间header中被加密的加密密钥进行解密,得到明文的加密密钥。再用 加密密钥 解密数据信息。加密密钥是不会被改变的(除非进行alter table testt encrytion=NO/YES)。而主密钥 可以通过以下命令随时改变

查看变更前keyring文件

mysql设置表空间 mysql表空间加密_mysql

执行主密钥变更命令

mysql> ALTER INSTANCE ROTATE INNODB MASTER KEY;
Query OK, 0 rows affected (0.01 sec)

再次查看变更后keyring文件 

mysql设置表空间 mysql表空间加密_表空间_02

2、配置my.ini
        如没有该文件,可在创建一个在MySQL安装目录或C:\下,文件添加如下内容,目录以实际为准,然后重启MySQL。

        win环境下的keyring_file.dll一般存放在MySQL服务安装目录下的lib\plugin。其中还有一个文件是keyring_file.so,该文件是Linux环境下的加密插件,如果Linux下需要的话,直接early-plugin-load=keyring_file.so即可。

[mysqld]
。。。其他配置。。
early-plugin-load=keyring_file.dll
keyring_file_data='D:\mysql-8.0.22\mysql-8.0.22-winx64\keyring'
 
# 其中keyring文件MySQL会自动创建,无需手动创建

Linux环境下配置

[mysqld]
。。。其他配置。。

plugin_dir=/usr/lib/mysql/plugin                  #插件路径,根据实际情况修改
early-plugin-load='keyring_file.so'               # 加密插件
keyring_file_data=/var/lib/mysql-keyring/keyring  # 路径不存在,需要创建
innodb_file_per_table=1                           # 只作用于独立表空间
 
# 其中keyring文件MySQL会自动创建,无需手动创建

注意:

plugin_dir和innodb_file_per_table需要配置,不配置,则插件无法正常启动。

至于为什么,还没搞清楚。我使用过版本8.0.18、版本8.0.29测试过,确实存在该问题。这个问题未完待续???

4、查看插件状态

mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS, PLUGIN_Type,PLUGIN_Library FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring_file';
+--------------+---------------+-------------+-----------------+
| PLUGIN_NAME  | PLUGIN_STATUS | PLUGIN_Type | PLUGIN_Library  |
+--------------+---------------+-------------+-----------------+
| keyring_file | ACTIVE        | KEYRING     | keyring_file.so |
+--------------+---------------+-------------+-----------------+
1 row in set (0.00 sec)

或者使用show plugins命令查看。

5、加解密数据表

mysql> use testdb;
Database changed
mysql> alter table testt encryption='Y';
Query OK, 3 rows affected (0.04 sec)
Records: 3  Duplicates: 0  Warnings: 0
 
mysql> SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS FROM INFORMATION_SCHEMA.TABLES WHERE CREATE_OPTIONS LIKE '%ENCRYPTION=''Y''%';
 
+--------------+------------+----------------+
| TABLE_SCHEMA | TABLE_NAME | CREATE_OPTIONS |
+--------------+------------+----------------+
| testdb       | testt      | ENCRYPTION='Y' |
+--------------+------------+----------------+
1 row in set (0.01 sec)

 
mysql> alter table testt encryption='N';
Query OK, 3 rows affected (0.03 sec)
Records: 3  Duplicates: 0  Warnings: 0

6、卸载keyring插件

mysql> UNINSTALL PLUGIN keyring_file;
Query OK, 0 rows affected (0.01 sec)
 
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring%';
 
Empty set (0.00 sec)

插件卸载后,服务重启,再次查询加密表数据会提示:

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.


二、关于表空间加密的一些思考。

        MySql社区版从5.7.11开始支持基于表的数据加密方案,模块名为keyring_file,支持加密整张表。这种是加密方式其实是基于文件加密的,一旦mysqld读取key启动后,将会解密整张表的数据,在mysql服务内,读取的数据都是解密后的,也就是说对客户端而言是无感知的。而这个key是本地存放的,mysql服务拥有读写这个key的权限。

  • 针对已有的项目面对客户的安全审查需求,要对mysql进行表加密吗?
  • 表加密影响性能吗?
  • 对主从复制有没有影响?加密后对业务系统有影响吗?
  • 对备份恢复有没有性能影像?
  • 大数据量情况下,加密解密耗时吗?
  • 加密后会增加存储空间占用吗?

        数据库的有些特性通常都是双刃剑,有利也有弊,当然要测试过才知道。

以客户现场业务数据库数据量为基准,做如下测试:

1:增删改查加密前和加密后的性能对比

2:主从复制加密后系统主流程功能验证

3:加密前和加密后备份恢复时间对比

4:加密,解密耗时测试

5:加密前加密后占用存储空间对比

        整个测试流程如下:

        1.把现场数据拷回来,再进行还原到两台相同配置的服务器(8核16G内存),一台服务器所有表未加密,一台服务器所有表都加密;

        2. 把现场业务系统的主要工作流的sql拿来,使用jmeter做并发性能测试对比;

        3.设置主从,测试加密情况下,主从同步是否正常,同步是否及时;

        考虑理论上应该没什么大问题,这里只简单的通过导入一个大批量插入数据的sql,来测试是否及时同步到从库。

        4.在对第二台服务器中的所有业务数据表进行加密时,顺便记录加密耗时,以及加密后的空间占用计算空间增长,以及解密耗时;

        5.分别测试加密和没有加密情况下的备份恢复时间。

经过两天的测试,基本结论如下:

1:表加密后业务系统的增删改查操作没有出现明显的性能降低

2:备份恢复的性能也没有明显的影响;

3:不影响主从复制,主从同步的及时性方面基本不受影响,没有出现明显的延迟;

4:空间增长方面,加密后反倒占用空间变小了;但是加密解密需较多的存储空间

         由于数据库中设置了innodb_file_per_table=1,每个表独占一个表空间,分别单独加密。很明显的看到加密后的文件反倒比加密前变小了,估计是加密过程中去掉了文件中的碎片?

        但是加密过程中需要有和原表文件大小差不多的空闲空间,否则加密会失败,解密也是一样。

        因为mysql表加密采用AES加密算法,实际上源文件不变,Mysql会新生成一个临时文件,把原表文件的数据,不断读取写入到新文件,直到加密完成,再删除原文件,把加密后的文件替换到原文件。解密也是一样。

        如果是单用户串行操作完成整个数据库的加密,可以简单的估算,加密解密额外需要的表空间大小为:需要加密的数据库中单个表文件占用空间最大的表,所占用的空间。

        例如一个300G的数据库中,最大的表占用70G,如果是串行加密所有的表,整个加密所需要的额外的磁盘空间为70G。解密也是同样如此。

        如果是多个会话并行执行加密操作,需要的空间就是各自需要加密的表中最大的表空间占用大小之和。

5:加密,解密非常耗时,在生产环境不可接受

        如果上面说的空间占用情况还可以接受,可耗时问题就让人觉得mysql的加密非常鸡肋了。测试下来,一个亿不到的业务量的情况下 整个系统的所有表加密完成时间需要整整一个晚上才行。

 测试数据如下:测试环境,8G内存,4核CPU

mysql设置表空间 mysql表空间加密_mysql_03

        同样是9千多万的数据量,业务表10比表5字段少很多,只是多了一个varchar(500)类型的字段,存储文件的磁盘完整路径的。然而加密耗时却多了几倍。

6:在不停止业务系统的情况下,加密加密不会阻塞数据查询操作,但是会阻塞增删改操作。

        根据执行时间直到加密解密操作完成才执行额外发起的增删改操作,成功或者超时,而对业务系统来说,多半都是会超时失败。

总结:

        mysql的 加密解密虽然不需要停机操作,但是会阻塞对数据库的增删改操作。要想快速完成加密解密操作,最好是先停止业务系统读写数据库,再执行。然而,加密解密的耗时决定了停机肯定会超出用户的能接受的停机时间!

        再来看安全性方面,虽然数据库文件是加密的,但是只要能有mysql服务的账户,访问数据都是自动解密的,加密的意义又在哪里呢?而对于加密key来说,熟悉mysql加密原理的,完全可以把key一定带走。可以预见,社区版的加密的安全性方面只不过是掩耳盗铃罢了!

        不知道大家的项目中是否也有数据库加密的需求呢?是否有别的更好的方式,在不购买企业版的情况下?