技術分享 | InnoDB 表空間加密

本文目錄:html

1、表空間加密概述mysql

  1. 應⽤場景
  2. 加密插件
  3. 加密限制
  4. 注意事項

2、加密表空間linux

  1. 安裝加密插件
  2. 配置表空間加密
  3. 查看錶空間被加密的表

3、更新 master encryption key
4、導⼊導出算法

  1. 案例

5、備份恢復sql

  1. innobackupex

6、參考文檔shell

表空間加密概述

從 5.7.11 開始,InnoDB 支持對獨立表空間進行靜態數據加密。該加密是在引擎內部數據頁級別的加密手段,在數據頁寫入文件系統時加密,從文件讀到內存中時解密,目前普遍使用的是 YaSSL/OpenSSL 提供的 AES 加密算法,加密先後數據頁大小不變,所以也稱爲透明加密。數據庫

它使用兩層加密密鑰架構,包括 master encryption key 和 tablespace key:vim

  • master encryption key 用於加密解密 tablespace key。當對一個表空間加密時,一個 tablespace key 會被加密並存儲在該表表空間的頭部
  • tablespace key 用於加密表空間文件。當訪問加密表空間時,後端

    • InnoDB 會先用 master encryption key 解密存儲在表空間中的加密 tablespace key,獲得明文的 tablespace key 後,再用 tablespace key 解密數據
  • tablespace key 解密後的明文信息基本不變(除非進行 alter table test_1 encrytion=NO, alter table test_1 encrytion=YES)。而 master key 能夠隨時改變(好比使用 ALTER INSTANCE ROTATE INNODB MASTER KEY;),這個稱爲 master key rotation。由於 tablespace key 的明文不會變,因此更新 master encryption key 以後只須要把 tablespace key 從新加密寫入第一個頁中便可。

應用場景

未配置表空間加密時,當發生相似拖庫操做時,數據很可能會泄漏。
配置表空間加密時,若是沒有加密時使用的 keyring(該文件由 keyring_file_data 參數設定),是讀取不到加密表空間數據的。因此當發生相似拖庫操做時,沒有相關的 keyring 文件時,數據基本不會泄漏的。這就要求存儲的 keyring 必定要嚴加保管,能夠採起如下措施來保存 keyring:安全

  • 避免將 keyring 文件與表空間文件放在一塊
  • keyring 文件所在目錄的權限須要嚴格控制
  • 使用 keyring_file 插件進行表空間加密時,keyring 文件是放在本地的,這個相對不夠安全。但能夠將其放到非本地中,須要時複製到相關目錄(好比重啓數據庫、更新 master encryption key,不須要時刪除該文件便可

加密插件

InnoDB 表空間加密依賴插件進行加密。企業版提供如下四種插件: keyring_file,keyring_encrypted_file,keyring_okv,keyring_aws。社區版目前只能使用 keyring_file 進行加密,本文僅介紹 keyring_file 插件:

  • 企業版更加安全。由於對密鑰也加密存儲了,而社區版的密鑰是放在本地存儲的,相對不夠安全
  • 企業版支持多種後端存儲密鑰,對數據加密自己沒區別

加密限制

1.AES 是惟一支持的加密算法。InnoDB 靜態表空間加密使用 Electronic Codebook (ECB) 加密模式來加密 tablespace key,使用 Cipher Block Chaining (CBC) 加密模式加密數據文件
2.ENCRYPTION 使用該 COPY 命令而不是 INPLACE 命令進行表空間的加密
3.僅支持對獨立表空間加密。不支持加密其餘表空間類型(如通用表空間和系統表空間)
4.不能將表從加密的獨立表空間移動或複製到不支持加密的表空間中
5.表空間加密僅對錶空間中的數據加密,不對 redo log,undo log,binary log 中的數據加密
6.不容許修改已加密的表的存儲引擎(修改成 innodb 存儲引擎則沒問題)

注意事項

1.==在建立了第一個加密表空間、master encryption key 更新先後都必須立馬備份密鑰環文件。由於主加密密鑰丟失後,加密表空間中的數據將沒法恢復。 因此加密表時,必須採起措施防止主加密密鑰丟失,好比定時備份該文件#F44336 #F44336==
2.從安全角度考慮,不建議將密鑰環數據文件與表空間數據文件放在同一目錄下
3.若是數據庫在正常操做期間退出或中止,必定要使用一樣的加密配置來重啓數據庫,不然會致使之前加密的表空間沒法訪問
4.當第一次對錶空間加密時(不管是新表加密仍是舊錶加密),將生成第一個主加密密鑰。但對於運行的數據庫,移除 keyring 後,依舊能夠建立、讀寫加密表空間(但在數據庫重啓或更新 master encryption key 後這些操做會失敗)
5.更新 master encryption key 前需確保 keyring 文件存在,若是不存在,則會更新失敗,從而致使讀寫、建立加密表均失敗
6.僅當主從都配置了表空間加密,表空間加密操做纔可能在主從中均執行成功

加密表空間

如下的測試案例是在以下環境進行的:

  • linux 版本:7.5
  • mysql 版本:MySQL 5.7.21
  • 加密插件:keyring_file

安裝加密插件

1.必須先安裝並配置加密插件。在啓動數據庫時使用 early-plugin-load 選項來指定使用的加密插件,並使用 keyring_file_data 定義加密插件存放密鑰環文件的路徑

- 須要提早建立好相關目錄並調整權限,否則可能會報錯

2.只能使用一個加密插件,不能同時使用多個加密插件
3.一旦在 MySQL 實例中建立了加密表,後續重啓該實例時,必須給 early-plugin-load 指定建立加密表時使用的的加密插件。若是不這樣作,則在啓動服務器和InnoDB恢復期間會致使錯誤
4.必須配置獨立表空間:innodb_file_per_table=1

-- vim my.cnf,在 [mysqld] 下添加如下參數
[mysqld]
early-plugin-load="keyring_file.so"
keyring_file_data=/opt/mysql/keyring/3306/keyring
innodb_file_per_table=1

-- 建立相關目錄及修改密鑰環文件所在目錄的權限
mkdir -p /opt/mysql/keyring/3306/
chown -R actiontech-universe:actiontech /opt/mysql/keyring/
chown -R actiontech-mysql:actiontech-mysql /opt/mysql/keyring/3306/

-- 查看插件是否加載
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE 'keyring_file';

配置表空間加密

如下以 mydata.test_1 表來進行測試

/*
1. 爲新表加密
2. 插入數據至新表
3. 取消表加密
4. 開啓表加密
5. 查看加密表
*/

mysql> CREATE TABLE mydata.test_1 (id INT primary key,age int) ENCRYPTION='Y';
Query OK, 0 rows affected (0.02 sec)

mysql> insert into test_1 select 9,9;
Query OK, 1 row affected (0.00 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE mydata.test_1 ENCRYPTION='N'; 
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> ALTER TABLE mydata.test_1 ENCRYPTION='Y';
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table mydata.test_1;select * from mydata.test_1;
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                               |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_1 | CREATE TABLE `test_1` (
  `id` int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ENCRYPTION='Y' |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.11 sec)

+----+------+
| id | age  |
+----+------+
|  9 |    9 |
+----+------+
1 row in set (0.00 sec)

/*
刪除當前的 keyring,使用備份的 keyring 恢復到原路徑並重啓,此時再查看 mydata.test_1 會查當作功。由於 mydata.test_1 加密解密用的 keyring 同樣
*/

[root@localhost ~]# rm -rf /opt/mysql/keyring/3306/keyring 
[root@localhost ~]# mv /root/keyring /opt/mysql/keyring/3306/
[root@localhost ~]# systemctl restart mysqld_3306
[root@localhost ~]# mysql -h10.186.63.90 -uroot -p -P3306 -e"show create table mydata.test_1;select * from mydata.test_1;"
Enter password: 
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table  | Create Table                                                                                                                                               |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_1 | CREATE TABLE `test_1` (
  `id` int(11) NOT NULL,
  `age` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ENCRYPTION='Y' |
+--------+------------------------------------------------------------------------------------------------------------------------------------------------------------+
+----+------+
| id | age  |
+----+------+
|  9 |    9 |
+----+------+

查看錶空間被加密的表

經過 ENCRYPTION 選項加密表空間時,表的加密信息會存放到 INFORMATION_SCHEMA.TABLES 的 CREATE_OPTIONS 字段中。因此能夠查詢該表來判斷表是否加密。

-- 查看加密的表:
SELECT TABLE_SCHEMA, TABLE_NAME, CREATE_OPTIONS FROM INFORMATION_SCHEMA.TABLES WHERE CREATE_OPTIONS LIKE '%ENCRYPTION%';

-- 查看未加密的表:
select concat(TABLE_SCHEMA,".",TABLE_NAME) from INFORMATION_SCHEMA.TABLES where (TABLE_SCHEMA,TABLE_NAME) not in (SELECT TABLE_SCHEMA,TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE CREATE_OPTIONS LIKE '%ENCRYPTION%' and table_schema not in ('information_schema','performance_schema','sys','mysql','universe')) and TABLE_SCHEMA in ('mydata');

更新 master encryption key

應按期更換 master encryption key,或者懷疑 master encryption key 已經泄露時便須要更換了。

更新 master encryption key 只會改變 master encryption key 並從新加密 tablespace keys,不會解密或者從新加密表空間。

由於 tablespace_key 的明文不會變,更新 master_key 以後只須要把 tablespace_key 從新加密寫入第一個頁中便可。

master encryption key 的變動是一個原子的、實例級操做,每次變動 master encryption key 時,MySQL 實例中全部的 tablespace key 都會被從新加密並保存到各自的表空間頭部。由於是原子操做,因此一旦開始更新,對全部 tablespace keys 的從新加密必須所有成功;

-- 手動更新 master encryption key,成功後不影響加密表的使用

[root@localhost ~]# ll /opt/mysql/keyring/3306/keyring 
-rw-r----- 1 mysql mysql 155 Apr 19 02:05 /opt/mysql/keyring/3306/keyring
[root@localhost ~]# mysql -h10.186.63.90 -uroot -p -P3306 -e"ALTER INSTANCE ROTATE INNODB MASTER KEY;"
Enter password: 
[root@localhost ~]# ll /opt/mysql/keyring/3306/keyring 
-rw-r----- 1 mysql mysql 283 Apr 19 02:24 /opt/mysql/keyring/3306/keyring
[root@localhost ~]# mysql -h10.186.63.90 -uroot -p -P3306 -e"select * from mydata.test_1;"
Enter password: 
+----+------+
| id | age  |
+----+------+
|  9 |    9 |
+----+------+

導入導出

爲了支持 Export/Import 加密表,引入了 transfer_key,在 export 的時候隨機生成一個 transfer_key,把現有的 tablespace_key 用 transfer_key 加密,並將二者同時寫入 table_name.cfp 的文件中,注意這裏 transfer_key 保存的是明文。Import 會讀取 transfer_key 用來解密,而後執行正常的 import 操做便可,一旦 import 完成,table_name.cfg 文件會被馬上刪除:

  • 導出加密表空間時,innodb 除了會生成 .cfg 元數據文件以外,還會生成 .cfp 文件,用於加密 tablespace key 的 transfer key。加密的 tablespace key 和 transfer key 存儲在 tablespace_name.cfp 文件
  • 導入加密表時,須要同時導入 tablespace_name.cfp 和加密表空間才行,InnoDB 經過 transfer key 來解密 tablespace_name.cfp 文件中的 tablespace key

導入導出流程以下:
1.目標庫:CREATE TABLE mydata.test_1 (id INT primary key,age int) ENCRYPTION='Y';,創建與源庫同名、同結構的表。
2.目標庫:ALTER TABLE test_1 DISCARD TABLESPACE;,此時會刪除 .ibd 文件
3.源庫:use test; FLUSH TABLES test_1 FOR EXPORT;,此時會產生 .cfg、.cfp 文件
4.目標庫:scp root@10.186.63.90:/opt/mysql/data/3306/mydata/test_1.{ibd,cfg.cfp} .
5.目標庫:chown actiontech-mysql:actiontech-mysql test_1*,複製文件後,須要修改用戶組及權限。
6.源庫:unlock tables;,此時會刪除 .cfg、.cfp 文件
7.目標庫:ALTER TABLE test_1 IMPORT TABLESPACE;,加載表 test_1

案例

源庫:10.186.63.90:3306
目標庫:10.186.63.91:3307

# 在目標庫中創建與源庫同名、同結構的表
[root@localhost ~]# fg
mysql -h10.186.63.91 -uroot -p -P3307    (wd: ~)
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database mydata;
Query OK, 1 row affected (0.01 sec)

mysql> CREATE TABLE mydata.test_1 (id INT primary key,age int) ENCRYPTION='Y';
Query OK, 0 rows affected (0.02 sec)

# 目標庫執行 DISCARD TABLESPACE
mysql> use mydata;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> ALTER TABLE test_1 DISCARD TABLESPACE;
Query OK, 0 rows affected (0.02 sec)

# 源庫執行 flush table ... fro export
[root@localhost ~]# fg
mysql -h10.186.63.90 -uroot -P3306 -p
mysql> use mydata;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+------------------+
| Tables_in_mydata |
+------------------+
| test_1           |
+------------------+
1 row in set (0.00 sec)

mysql> FLUSH TABLES test_1 FOR EXPORT;
Query OK, 0 rows affected (0.01 sec)

mysql> 
[1]+  Stopped                 mysql -h10.186.63.90 -uroot -P3306 -p


# 從源庫拷貝文件至目標庫
[root@localhost mydata]# scp root@10.186.63.90:/opt/mysql/data/3306/mydata/test_1.{ibd,cfg,cfp} .
root@10.186.63.90's password: 
test_1.ibd                                                                                         100%   96KB  41.0MB/s   00:00    
root@10.186.63.90's password: 
test_1.cfg                                                                                         100%  400   343.7KB/s   00:00    
root@10.186.63.90's password: 
test_1.cfp                                                                                         100%  100   132.7KB/s   00:00    
[root@localhost mydata]# ll
total 120
-rw-r----- 1 actiontech-mysql actiontech-mysql    67 Sep 28 05:49 db.opt
-rw-r----- 1 root             root               400 Sep 28 05:57 test_1.cfg
-rw-r----- 1 root             root               100 Sep 28 05:57 test_1.cfp
-rw-r----- 1 actiontech-mysql actiontech-mysql  8584 Sep 28 05:50 test_1.frm
-rw-r----- 1 root             root             98304 Sep 28 05:57 test_1.ibd

# 修改目標庫上文件的權限
[root@localhost mydata]# chown actiontech-mysql:actiontech-mysql *

# 源庫上執行 unlock tables
[root@localhost mydata]# fg
mysql -h10.186.63.90 -uroot -P3306 -p    (wd: ~)
mysql> use mydata;
Database changed
mysql> unlock tables;
Query OK, 0 rows affected (0.00 sec)

# 目標庫上執行 ALTER TABLE ... IMPORT TABLESPACE;
[root@localhost mydata]# fg
mysql -h10.186.63.91 -uroot -p -P3307    (wd: ~)
mysql> select * from mydata.test_1;
ERROR 1814 (HY000): Tablespace has been discarded for table 'test_1'
mysql> ALTER TABLE test_1 IMPORT TABLESPACE;
Query OK, 0 rows affected (0.05 sec)

mysql> select * from mydata.test_1;
Empty set (0.00 sec)

備份恢復

參考文檔
mysqlbackup 備份恢復
innobackupex 備份恢復

mysqlbackup innobackupex 都可以對加密表空間進行加密,只不過須要注意版本:

  • mysqlbackup 4.1.0 及更新的版本支持 MySQL 5.7.20 及更早版本的加密表空間備份;mysqlbackup 4.1.1 及更新版本則支持 MySQL 5.7 的加密表空間備份
  • innobackupex 支持加密表空間備份恢復的最小版本沒查到相關說明

這裏以 innobackupex 2.4.5 爲例進行加密表空間的備份恢復

innobackupex

innobackupex 備份加密表空間的注意事項:

  • innobackupex 僅支持使用 keyring_file、keyring_vault 插件加密表空間的備份
  • innobackupex 不會複製密鑰環文件到備份目錄中,因此須要手動複製密鑰環文件到配置文件指定的 keyring-file-data 路徑

    • 若是備份先後密鑰環文件不一樣,則在還原時應該使用舊的密鑰環文件

備份 10.186.63.90 中的數據至 10.186.63.91:3307

# 全量備份:加密表空間的全備的流程與常規的備份恢復基本同樣,只是須要額外指定一個參數:--keyring-file-data

mkdir /data2/all_backup
/data/urman-agent/bin/innobackupex --defaults-file=/opt/mysql/etc/3306/my.cnf --user=root --password=test -P3306 --socket=/opt/mysql/data/3306/mysqld.sock --parallel=8 --keyring-file-data=/opt/mysql/keyring/3306/keyring --no-timestamp /data2/all_backup

# apply-log 
/data/urman-agent/bin/innobackupex --apply-log --keyring-file-data=/opt/mysql/keyring/3306/keyring /data2/all_backup/

# 複製全備文件、keyring 文件至目標庫
rm -rf /opt/mysql/data/3307/* && rm -rf /opt/mysql/keyring/3307/keyring  && rm -rf /opt/mysql/log/redolog/3307/ib_logfile*
scp -r /data2/all_backup/ root@10.186.63.91:/data2/
scp /opt/mysql/keyring/3306/keyring root@10.186.63.91:/opt/mysql/keyring/3307

# copy back
/data/urman-agent//bin/innobackupex --defaults-file=/opt/mysql/etc/3307/my.cnf --copy-back --keyring-file-data=/opt/mysql/keyring/3307/keyring /data2/all_backup/

# 修改權限
chown actiontech-mysql:actiontech-mysql /opt/mysql/keyring/3307/keyring 
chown -R actiontech-mysql:actiontech-mysql /opt/mysql/data/3307/*
chown -R actiontech-mysql:actiontech-mysql /opt/mysql/log/redolog/*

# 啓動
systemctl start mysqld_3307
參考文檔
14.6.3.8 InnoDB Tablespace Encryption
InnoDB 表空間加密-原理篇
相關文章
相關標籤/搜索