前
TXSQL 是腾讯基础架构部数据库团队自研的 MySQL 分支, 对腾讯云以及众多的内部业务提供了强大的数据库内核支撑相比原生的 MySQL,TXSQL 在 BINLOG 复制和 InnoDB 存储引擎方面做了很多的优化, 另外在 Server 层面也做了大量的工作因此 TXSQL 拥有更好的性能, 更好的稳定性和可维护性, 以及更多的企业级特性本文将对加密和审计这两个企业级特性进行详细的解读
一加密
这里的加密是指对存储在磁盘上数据的进行加密对数据的通信进行加密 MySQL 很早就开始支持了数据的加密操作是可以脱离数据库进行的, 比如用户在插入一条数据时, 对该数据进行加密; 检索数据时, 再对该数据进行解密操作这样做存在两个问题: 其一, 加密数据在数据库中的查询效率低下: 加密数据在数据库中很难进行相似性 (like) 查询, 以及进行范围查询其二, 加密密钥的安全性问题由用户保证: 密钥由用户维护和管理, 增加了安全的风险和维护的难度
1.1 MySQL 数据加密
MySQL 在 5.7 版本推出数据加密功能: 透明数据加密 (Transparent Data Encryption) 透明加密是指数据的加解密操作对用户透明用户在创建加密表时, 不用指定加密密钥数据在写盘时加密, 在读盘时解密目前透明数据加密只支持 InnoDB 存储引擎下面的语句创建了一个加密表:
CREATE TABLE t1 (c1 INT) ENGINE=InnoDB ENCRYPTION='Y';
其中, ENCRYPTION='Y'表示对该表的数据进行加密那么数据是如何进行加解密的呢?
1.1.1 两层密钥体系
我们在创建加密表的时候, 会自动生成一个随机的表空间密钥 (Tablespace Key) 数据由表空间密钥保护当我们在加密表中插入一条记录, 记录以明文插入到缓冲区 (Buffer Pool) 的数据页中当数据页要写盘时, 通过表空间密钥, 对该页上的所有数据记录进行加密后再写盘当请求的数据页不在缓冲区时, 数据页从磁盘读入, 通过表空间密钥, 对数据页中所有记录进行解密之后, 加入到缓冲区中一句话: 数据页在缓冲区中是明文, 在磁盘上是密文另外数据加密采用的加密算法是 AES256
表空间密钥是如何保存的? MySQL 有一个全局的主密钥 (Master Key), 主密钥有对应的 ID(Master Key ID) 表空间密钥由主密钥保存当表空间密钥生成后, 通过主密钥加密, 写入到表空间的第一个数据页中, 和加密后的表空间密钥一同保存的还有主密钥的 ID 当表空间第一次打开时, 读取第一个数据页, 通过主密钥 ID, 得到主密钥; 然后通过主密钥对表空间密钥进行解密
当系统运行之后, 第一次创建加密表之前, 全局的主密钥为空创建加密表时, 当主密钥为空, InnoDB 会自动生成一个主密钥 ID, 由固定前缀加 server uuid 以及序号组成通过主密钥管理接口, 为主密钥 ID 生成一个对应的主密钥
1.1.2 KEYRING 密钥管理框架
主密钥的管理则是通过 MySQL 的 KEYRING 插件框架进行的主要有四个接口:
- l my_key_fetch
- my_bool
- my_key_fetch(const char *key_id, const char **key_type, const char* user_id,
- void **key, size_t *key_len);
- l my_key_generate
- my_bool
- my_key_generate(const char *key_id, const char *key_type,
- const char *user_id, size_t key_len);
- l my_key_remove
- l my_key_store
我们可以把 KEYRING 框架理解为一个简单的 Key-Value 的 store 上述 InnoDB 内部生成主密钥的过程是通过调用 my_key_generate 和 my_key_fetch 完成
MySQL 社区版本提供 KEYRING 插件的一个简单的文件实现: KEYRING_FILE 密钥保存在文件中, 通常叫 keyring_file 这种实现方式非常不安全当加密的表空间文件和 keyring_file 一同被拷贝出去, 那么加密的表空间文件是可以正常读取的
MySQL 商业版提供 KEYRING 插件的另外一种实现: KEYRING_OKV 密钥保存在 ORACLE Key Vault 中, 确保密钥的安全性
1.2 TXSQL 数据加密
在 TXSQL 中, 我们沿用 MySQL 的透明加密体系, 提供 KEYRING 插件的另外一种实现: KEYRING_KMS 将 KEYRING 与企业级的 KMS(Key Management Service) 集成
KMS 是腾讯云一项保护数据及密钥安全的密钥服务服务涉及的各个流程均采用高安全性协议通信, 保证服务高安全; 提供分布式集群管理和热备份, 保证服务高可靠和高可用 KMS 也采用的是两层密钥体系 KMS 涉及两类密钥, 即用户主密钥 (CMK) 与数据密钥 (Datakey) 用户主密钥用于加密数据密钥或密码证书配置文件等小包数据 (最多 4KB) 数据密钥用于加密业务数据海量的业务数据在存储或通信过程中使用数据密钥以对称加密的方式加密, 而数据密钥又通过用户主密钥采用非对称加密方式加密保护
通过 API 调用 KMS 接口时, 首先创建用户主密钥; 然后创建数据密钥 CMK 的个数限制为 128, 而数据密钥则无此限制在 KEYRING_KMS 实现上, MySQL 的主密钥和 KMS 的数据密钥对应由于 KMS 接口的限制和实际需要, 我们只实现了 KEYRING 的两个接口: my_key_generate 和 my_key_fetch
我们依然保留 MySQL 两层密钥体系, 我们只是用 KMS 来实现了主密钥的管理, 但没有使用 KMS 来进行数据的加密主要考虑有两点: 一是系统可用性方面的考虑, 比如万一 KMS 短时不可用, 那么加密数据将无法访问; 二是系统性能方面的考虑, 所有数据的加解密都通过 KMS, 加解密效率和网络开销无疑对系统影响巨大
1.2.1 Key Generate
在 KEYRING_KMS 中, 我们同样有一个本地文件, 用来存储密钥 ID 和加密后的数据密钥这个加密后的数据密钥是由 KMS 返回, 所以解密这个数据密钥也需要通过 KMS 来做在下图的流程中, 我们通过固定的 CMK 别名 (alias) 来获取或创建 CMK, 然后产生数据密钥, 将加密后的数据密钥保存在本地文件中
1.2.2 Key Fetch
获取密钥首先根据密钥 ID 从文件中读取加密后的数据密钥, 再通过 KMS 对数据密钥进行解密, 获取密钥明文 KMS 进行解密时, 只需要提供密文, 不要需要其他信息获取密钥明文成功之后, 我们对密钥明文进行了缓存, 减少对 KMS 的访问
1.2.3 基于角色的访问控制
在用户开启加密功能时, 在 CAM 中, 为用户创建了一个可以访问 KMS 的角色(role), 并将此角色的权限授予指定的控制台用户我们通过访问 CAM 获取临时证书(secret key, secret id,token), 通过临时证书来访问 KMS 其中 CAM 是腾讯云提供的访问控制服务
如果不采用角色访问控制, 在开启加密的时候, 需要用户提供自己的证书其一, 用户体验差, 其二, 用户证书的安全性差
还有一点值得注意: InnoDB 中使用的主密钥是可以轮换的通过如下语句进行轮换:
ALTER INSTANCE ROTATE INNODB MASTER KEY;
主密钥的轮换过程:
1. 产生新的主密钥 ID;
2. 获取新的主密钥(key generate);
3. 对所有加密表空间, 执行步骤 4,5
4. 对加密的表空间, 用旧的主密钥解密表空间密钥;
5. 用新的主密钥加密表空间密钥
主密钥的轮换, 进一步提高了系统的安全性
通过以上介绍, 我们可以看到, TXSQL 透明数据加密, 将 KMS 和 CAM 有机的结合在一起, 对访问控制, 密钥管理和数据加密等各个环节进行严格把控, 为用户在腾讯云上提供了一个完整安全可靠的数据加密解决方案
二审计
数据库审计也是数据库安全的重要一环所谓审计, 就是对用户在数据库中的操作和行为进行记录, 基于这些记录, 可以进行审查分析我们可以通过审计记录来对一个非法操作进行追查; 对数据库性能和运行状态进行(也可以通过系统监控获得); 可以对用户的访问模式进行跟踪建模等等这些事后的分析可以帮助我们发现数据库运行过程中的风险, 发出告警, 以及采取必要的干预措施
2.1 MySQL 审计
MySQL 同样提供了一个审计插件 (Audit Plugin) 框架在框架内部主要处理函数为:
int (*event_notify)(MYSQL_THD, mysql_event_class_t, const void *);
在 Server 层面, 从系统启动, 用户登录, 到 SQL 执行的各个节点, 以事件的方式, 通知审计插件进行记录以下是事件类型的例子:
- MYSQL_AUDIT_CONNECTION_PRE_AUTHENTICATE
- MYSQL_AUDIT_CONNECTION_CONNECT
- MYSQL_AUDIT_CONNECTION_DISCONNECT
- MYSQL_AUDIT_CONNECTION_DISCONNECT
- MYSQL_AUDIT_COMMAND_START
- MYSQL_AUDIT_COMMAND_END
MySQL 社区版只提供审计插件的范例, 而在 MySQL 商业版中提供企业级审计功能
2.2 TXSQL 审计
TXSQL 的重要用户有对审计功能的迫切需求: 用户需要对数据库操作进行事后的跟踪和分析我们利用审计插件框架, 综合考虑功能和性能, 提供了一套全新的审计解决方案
2.2.1 审计架构
上图是我们整个审计框架的示意图
用户连接 (session) 产生的审计记录被写入到一片固定的内存中; 专门的写盘线程 (Flush Thread) 将内存中的审计记录写入到审计文件中 (Audit File); 审计代理(Audit Agent) 则读取审计文件, 将审计记录发送到审计日志中心: CTSDB 集群进行集中存储其中, 一个 TXSQL 实例对应一个写盘线程, 一个审计代理服务多个 TXSQL 实例, 一台物理机上只有一个审计代理
CTSDB 是腾讯基础架构部数据库团队研发的时间序列数据库 (目前可以在腾讯云上申请试用) 审计数据又恰好是时间序列数据选择 CTSDB 来存储审计数据带来的好处有: 其一数据压缩率高; 其二数据吞吐量大; 其三数据分析能力强完全满足我们在高压力情况下, 对审计数据的处理和分析能力
2.2.2 审计日志格式
我们采用 json 格式对审计日志传输记录的内容有时间戳, 影响的行数, 执行的时间, 错误码, 规则号, 主机, 实例名, 用户名, 数据库名, 过滤策略名, SQL 语句, 以及 SQL 类型等
2.2.3 审计过滤规则
考虑到审计日志量巨大, 提供过滤规则就很必要我们提供如下过滤规则
1. 主机 IP, 用户名, 数据库名, 表名可以使用 include, exclude, =, <>, regex 进行过滤;
2. SQL 语句可以使用 include, exclude, regex 进行过滤;
3. SQL 类型可以使用 =, <>进行过滤;
4. 影响函数和之行时间可以使用>, <,>=, <=, = 进行过滤
2.2.4 审计性能
为了减少审计带来的性能损失, 我们只对命令执行完之后的结果进行审计这样就省去了很大一部分的审计日志根据我们的测试, 打开审计并进行全量审计 (Audit all) 时, 系统性能损失 9%; 打开审计并且不进行审计 (Audit null) 时, 性能损失约为 3%
三小结
TXSQL 在实现加密和审计这两个企业级特性, 是对用户需求的积极响应在实现上, 也充分结合与腾讯云内其他平台进行结合, 提供一站式的解决方案为了给用户提供性能更好, 功能更强, 可用性更高的数据库服务, TXSQL 一直在努力另外, TXSQL 关于加密和审计的开源工作也在进行着中, 已经初步和 MariaDB 达成了相关合作, 在不久的将来里, 这两个企业级的功能就能与大家在开源版本中见面
来源: https://www.thinksaas.cn/group/topic/838869/