数据库内核月报 - 2015 / 02

MariaDB · 特性分析· 表/表空间加密

Google向MariaDB 10.1.13(暂未Release)贡献了这个补丁,可以对表/表空间进行加密。

加密过的表可以防止某些非授权用户访问或偷取磁盘然后通过访问原始数据文件来偷取数据。当然,假设你已经把密钥文件存储在另一个系统上。但是,使用加密可能会降低差不多10%的性能。目前,只有XtraDB/InnoDB引擎能完全支持加密。

MariaDB在InnoDB/XtraDB中支持两种方式的加密:

Table encryption(表级加密): 只有在创建时指定 PAGE_ENCRYPTION=1 的表才被加密。

Tablespace encryption(表空间加密): 当前实例下的任何文件都被加密(包括日志文件)。

MariaDB中所有的加密算法都是基于AES的。但是你可以在启动的时候使用 –encryption-algorithm=name 来指定具体哪种基于AES的加密算法,有这些可选:

选项 描述
none 默认值。不进行任何加密。
aes_cbc 建议值。这是大部分欧洲政府接受的算法。
aes_ctr 一种新的块加密模式,Google自己开发的,并且在他们的MariaDB实例中使用的算法。
aes_ecb 这种加密模式用于内部计数器计算。你可以用它来加密,但它不能提供强保密性。

密钥的管理

为了保护加密过的数据,密钥必须另外保存,不要跟数据文件放在一个地方。默认情况下,MariaDB支持两种密钥管理方式,都是以Plugin的方式实现的。

1) file_key_management_plugin

file_key_management_plugin 是一个密钥管理插件,可以从文件中读取密钥。这个插件有如下配置选项:

file_key_management_plugin_filename=path-to-key-file: 密钥文件存放的位置

file_key_management_plugin_filekey: 一个可选的Key,用来解密密钥文件

一个my.cnf配置的例子:

[mysqld]
encryption-algorithm = aes_cbc
file_key_management_plugin_filename = /home/mdb/keys.enc
file_key_management_plugin_filekey = secret

这个密钥文件(/home/mdb/keys.enc)包含了AES密钥。128, 192 或 256位密钥都可以支持。ID有16个字节。 一个密钥文件内容的例子如下:

1;F5502320F8429037B8DAEF761B189D12;770A8A65DA156D24EE2A093277530142

1是密钥的标识,在建表的时候可以指定使用哪个密钥; 接着是16字节的ID,最后是一个16字节的AES密钥。密钥标识可以从0~255,但是0号密钥是保留给InnoDB日志文件使用的,不要在建表的时候用。

密钥文件本身同样可以加密,file_key_management_plugin_filekey定义的密钥可以用来解密密钥文件。OpenSSL命令行工具可以用来创建密钥文件。例如:

openssl enc –aes-256-cbc –md sha1 –k secret –in keys.txt –out keys.enc
openssl enc –aes-256-cbc –md sha1 –k <initialPwd> –in secret –out secret.enc

如果密钥文件在启动的时候读取不到(例如没提供解密密钥文件的Key),那么加密功能不再被支持,也无法访问被加密过的表。

2) example_key_management_plugin

为了获得真正高强度的加密,密钥必须周期性的变更。

example_key_management_plugin 是一个实现的例子。用你自己的密钥管理系统替换这个插件,可以创建一个非常安全的系统,例如从远程服务器来获取密钥。Google内部就是这么做的。

当然,example_key_management_plugin 仅仅是一个例子,你要根据它来编写你自己的Plugin!

加密数据

1)表级加密

表级加密意味着你可以选择哪些表需要加密。这可以让你在速度和安全性之间获得平衡。

要使用表级加密,你要这样做:

  • 设置 encryption-algorithm 选择你需要的加密算法;
  • 载入 file-key-management-plugin 插件或者其他相似的插件,添加 enable-file-key-management-plugin 到你的my.cnf文件。

要加密一个表,你需要在CREATE/ALTER TABLE 语句中使用新的参数:

选项 可选值 描述
PAGE_ENCRYPTION 0 或 1 1是启用这个功能,0是关闭
PAGE_ENCRYPTION_KEY 0-255 密钥表示。这个值表示用那个密钥。

例如:

CREATE TABLE T (id int, value varchar(255)) PAGE_ENCRYPTION=1 PAGE_ENCRYPTION_KEY=17;

这个建表语句会创建一个表T,使用标识为17的密钥加密。

ALTER TABLE T PAGE_ENCRYPTION=1 PAGE_ENCRYPTION_KEY=18;

更改表T使用标识为18的密钥来加密。如果你之前加密过这张表,那会首先解密这张表再重新加密。

ALTER TABLE T page_encryption=0;

关闭表T的加密功能。如果之前是加密的,那这个操作会做解密。

2) 表空间加密

要使用加密表空间,需要这样做:

  • 设置 encryption-algorithm 来选择加密算法;
  • 设置 innodb-encrypt-tables 为 1;
  • 载入 file-key-management-plugin 插件或者其他相似的插件,添加 enable-file-key-management-plugin 到你的 my.cnf 文件;
  • 启用 innodb-tablespaces-encryption 插件;
  • 启用 innodb-tablespaces-scrubbing 插件。

有下列变量可以配置加密项:

变量 可选值 描述
innodb-encrypt-tables Boolean (0 or 1) 是否在存储引擎加密所有表
innodb-encryption-rotate-key-age 秒数 如果获取到了新密钥多久更新一次页面加密
innodb-encryption-rotation-iop IOPS数 后台使用多少IOPS来做页面加密更新
innodb-encryption-threads 线程数 用多少个后台线程来做页面加密更新和清理
innodb-background-scrub-data-check-interval 秒数 隔多久检查空间是否需要清理
innodb-background-scrub-data-compressed Boolean (0 or 1) 打开通过后台线程来清理压缩数据
innodb-background-scrub-data-interval 秒数 隔多久调用一次清理
innodb-background-scrub-data-uncompressed Boolean (0 or 1) 打开通过后台线程来清理未压缩数据

清理(Scrubbing)意味着有一个后台线程定期的扫描所有的表并且对所有页面升级压缩密钥。

配置表空间加密的示例 my.cnf:

[mysqld]
encryption-algorithm=aes_ctr
innodb-tablespaces-encryption
innodb-tablespaces-scrubbing
innodb-encrypt-tables
innodb-encryption-threads=4

加密和压缩

加密和压缩(配合FusionIO使用的功能,之前的月报介绍过)可以同时使用。这可以让MariaDB先压缩数据然后再做加密,这种情况下可以很大的节省存储空间,并且数据更难被解密。