MySQL 8.0.13 で一般テーブルスペース（General Tablespace）を暗号化する

これは **[インフラ勉強会 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/infra-workshop)** 22 日目の記事です。

昨日（21 日目）は barson_4 さんでした。

 * **[インフラ勉強会のGROWIを同時編集可能にする](https://qiita.com/barson_4/items/e5d773987ef12e71bc67)**

---

MySQL 8.0.13 では、個別のテーブルスペース暗号化（5.7.11 で対応）と REDO ログ／UNDO ログの暗号化（8.0.4 RC で対応）に加えて、一般テーブルスペース（General Tablespace）の暗号化がサポートされました。

 * **[15.6.3.9 Tablespace Encryption / Enabling and Disabling General Tablespace Encryption](https://dev.mysql.com/doc/refman/8.0/en/innodb-tablespace-encryption.html#innodb-general-tablespace-encryption-enabling-disabling)（MySQL 8.0 Reference Manual）**

# 一般テーブルスペースとは

**「複数のテーブルの割り当て・格納ができる表領域」**です。MySQL 5.7 で対応した機能です。

 * **[MySQL 5.7の一般表領域 : 詳細とTips (MySQL Server Blogより)](https://yakst.com/ja/posts/3875)（Yakst）**

それ以前の MySQL（InnoDB）では、

 * 全てのテーブルを単一の（実際には指定の容量毎に区切った）ファイルに格納（`innodb_file_per_table=0`）
 * 全てのテーブルを個別のファイルに格納（`innodb_file_per_table=1`）

のいずれかしか選択できませんでしたが、MySQL 5.7 で一般テーブルスペースをサポートしたことにより、ある程度の単位（DB スキーマ単位など）で 1 つのファイルにテーブルを格納することができるようになりました。

そして MySQL 8.0.13 で、一般テーブルスペースの暗号化をサポートしました。

# 試してみる

基本的な設定は以下の内容と同じです（`innodb_file_per_table=1`にしておく必要あり。但しデフォルトで`innodb_file_per_table=1`）。

 * **[MySQL 8.0.16 でテーブルスペース・REDO ログ／UNDO ログ・システムテーブル暗号化
](https://qiita.com/hmatsu47/items/bae53fd0f6d09511732c)**

この状態で MySQL を起動し、暗号化した一般テーブルスペースを作成してみます。

```sql:暗号化した一般テーブルスペースを作成
mysql> CREATE TABLESPACE `ts1` ADD DATAFILE 'ts1.ibd' ENCRYPTION = 'Y' Engine=InnoDB;
Query OK, 0 rows affected (0.11 sec)
```

MySQL のデータディレクトリにファイルが作成されました。

```bash:ts1.ibdファイルの存在を確認
# cd /var/lib/mysql
# ls -l *.ibd
-rw-r-----. 1 mysql mysql 37748736 Dec 21 14:17 mysql.ibd
-rw-r-----. 1 mysql mysql   131072 Dec 21 14:17 ts1.ibd
```

次に、このテーブルスペースに 2 つのテーブルを作成し、適当にレコードを挿入します。

```sql:テーブルスペースにテーブルを作成しレコード挿入
mysql> CREATE DATABASE ts1;
Query OK, 1 row affected (0.06 sec)

mysql> USE ts1;
Database changed
mysql> CREATE TABLE table1 (id INT PRIMARY KEY AUTO_INCREMENT, str VARCHAR(100)) TABLESPACE=ts1 Engine=InnoDB;
Query OK, 0 rows affected (0.07 sec)

mysql> INSERT INTO table1 SET str='hoge';
Query OK, 1 row affected (0.05 sec)

mysql> INSERT INTO table1 SET str='fuga';
Query OK, 1 row affected (0.08 sec)

mysql> CREATE TABLE table2 (id INT PRIMARY KEY AUTO_INCREMENT, str VARCHAR(100)) TABLESPACE=ts1 Engine=InnoDB;
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO table2 SET str='FUGA';
Query OK, 1 row affected (0.05 sec)

mysql> INSERT INTO table2 SET str='HOGE';
Query OK, 1 row affected (0.02 sec)
```

```bash:fgrepして確認
# fgrep hoge *.ibd
# fgrep fuga *.ibd
# fgrep HOGE *.ibd
# fgrep FUGA *.ibd
```

レコード挿入時に入れた文字列が表示されないことを確認しました。

作成した一般テーブルスペースは、個別のテーブルスペースと同様、途中で暗号化の有効／無効を切り替えることができます。

```sql:一般テーブルスペースの暗号化を無効に
mysql> ALTER TABLESPACE ts1 ENCRYPTION = 'N';
Query OK, 0 rows affected (0.03 sec)

mysql> INSERT INTO table1 SET str='123';
Query OK, 1 row affected (0.07 sec)

mysql> INSERT INTO table2 SET str='456';
Query OK, 1 row affected (0.03 sec)
```

```bash:fgrepして確認(2)
# fgrep 123 *.ibd
Binary file mysql.ibd matches
Binary file ts1.ibd matches
# fgrep 456 *.ibd
Binary file mysql.ibd matches
Binary file ts1.ibd matches
# fgrep hoge *.ibd
Binary file ts1.ibd matches
# fgrep fuga *.ibd
Binary file ts1.ibd matches
# fgrep HOGE *.ibd
Binary file ts1.ibd matches
# fgrep FUGA *.ibd
Binary file ts1.ibd matches
```

暗号化が無効になったので、今度は挿入時に入れた文字列が表示されました。

---

ちょっと地味な機能追加でした。

次のバージョン（8.0.14）では、いよいよバイナリログの暗号化も対応するのでしょうか…？

---

[インフラ勉強会 Advent Calendar 2018](https://qiita.com/advent-calendar/2018/infra-workshop)、明日 23 日目は nagashi_ma_w さんです。

 * **[Azureの上にActive Directory を構築したらハマった話](https://nagashi-ma-w.hatenablog.com/entry/2018/12/23/000500)（ゆとりエンジニアのアレ）**

---

 * **[Qiitaに投稿したMySQL 8.0関連記事](https://hmatsu47.hatenablog.com/qiita_mysql80)**