Help us understand the problem. What is going on with this article?

MySQL 5.7の透過的データ暗号化

MySQL 5.7.11で導入、5.7.12で一部改良された、透過的データ暗号化をテストしたときのメモです。
とある勉強会のLTでグダグダになったので、あらためて書き直して投稿しておきます。

※内容は無保証です。


2019/04/30 追記:
MySQL 8.0 については以下の記事をご覧ください。


透過的データ暗号化(TDE)とは

アプリケーション(SQL)側で暗号化/復号処理をしなくても、DBのデータファイルが暗号化される機能です。
データファイルや物理メディア(HDDなど)の窃取・盗難対策に有効です。
一方で、アプリケーション側にSQLインジェクションなどの脆弱性がある場合には、何の保護にもなりません。

MySQL以外のRDBMSでは

商用のOracleなどでは、かなり前から使えるようになっています。
無償で使えるOSSでは、PostgreSQL(9.3~・要NEC提供のモジュール)が列単位、MariaDB(10.1.3~)がテーブル単位でのTDEをサポートしています。
また、Amazon RDSでは、MySQLを含め、様々なRDBMSをサポートしています。

利用準備

インストールとテーブル初期化、暗号化に関係のない設定チューニングについては省略します。

# vi /etc/my.cnf

以下を追記します。

innodb_file_per_table=1
early-plugin-load=keyring_file.so 
keyring_file_data=/usr/local/mysql/mysql-keyring/keyring

1行目:テーブル単位で.ibdファイル生成
2行目:キーリングプラグインとして、ファイルベースのプラグインを使用
3行目:キーリングファイルの置き場所を指定

追記したら保存します。
続いて、キーリングファイルの置き場所(ディレクトリ)を作成します。

# mkdir -p /usr/local/mysql/mysql-keyring
# chown -R mysql.mysql /usr/local/mysql
# chmod 750 /usr/local/mysql/mysql-keyring

終わったら、サービスを再起動します(以下、CentOS6などの場合)。

# service mysqld restart

暗号化テーブルを作成する

MySQLクライアントからサーバに接続して、暗号化テーブルを作ってみます。

mysql> CREATE DATABASE sample_db;
mysql> USE sample_db;
mysql> CREATE TABLE sample_tbl (id int(10) PRIMARY KEY AUTO_INCREMENT, value VARCHAR(100)) ENGINE=innodb ENCRYPTION='Y';

データを入れてみます。

mysql> INSERT INTO sample_tbl SET value='hogehoge';

この状態で、テーブルファイルを覗いてみます。

# view -b /var/lib/mysql/sample_db/sample_tbl.ibd

image

キーワード検索しても見つかりません。暗号化されたようです。
その他の操作は、以下のとおりです。

・既存テーブルの暗号化

mysql> ALTER TABLE ○○○ ENCRYPTION='Y';

・暗号化されたテーブルを復号

mysql> ALTER TABLE ○○○ ENCRYPTION='N';

・鍵のローテーション

mysql> ALTER INSTANCE ROTATE INNODB MASTER KEY;

・ローテーションした鍵を、既存テーブルに適用(既存テーブルの暗号化と同じSQL)

mysql> ALTER TABLE ○○○ ENCRYPTION='Y';

速度について

Oracleによると、「数%のオーバーヘッドしか生じない」とのこと。
バイナリログあり(同期出力)、メモリチューニングなし(デフォルト設定どおり)の環境で実際にやってみましたが、INSERT時に約10%、SELECT時に5%未満のオーバーヘッドが生じました。
ほぼ、謳い文句どおりです。

機能的な制限

ここまでは良いのですが、実は、REDOログが暗号化されません。

# view -b /var/lib/mysql/ib_logfile0

image

システムテーブルスペース(ibdata1)に含まれるUNDOログ(ロールバックセグメント)も暗号化されません。

また、レプリケーション時に使う、バイナリログも暗号化されません(row・mixedの両方で確認)。

# view -b /バイナリログのパス/ログファイル名

image

おそらくですが、もし仮に、(今後、Oracleが)ログを暗号化するような処理に変更したとしても、暗号化のオーバーヘッドはもっと大きくなるでしょう。テーブルファイルは非同期書込ができるので、実質的なオーバーヘッドが少なくなるのに対し、ログは同期書込しなければデータを失うことになるからです。

2016/10/04追記Oracle奥野さんの著書では、この機能を「透過的テーブルスペース暗号化」という表現で紹介されていますが、こちらの呼び方のほうが機能の実体をより正確に表していますね。

その他の制限

Oracleのリファレンスマニュアル等にも(英語で)記されていますが、キーリングプラグインとしてファイルベースのプラグインを使う場合は、PCI DSSなどの要件を満たしません。
暗号鍵がサーバーローカルに保存されるので、キーリングファイルとデータファイルを一緒に窃取された場合、復号される危険性があります(キーリングファイルも一応暗号化されているようですが、ロジックはソースを解析すれば分かるはずです)。

5.7.12からサポートされた、Oracle Key Vaultを使うキーリングプラグインでは、要件を満たすそうですが、こちらはEnterprise Edition(有償サポート付き)専用です。REDO/UNDOログ、バイナリログについては、暗号化されないままのはずです。
また、メモリ上の処理(バッファプールなど)は暗号化されないため、OSレベルの侵入にも、効果は限定的です。

「何を守るのか」を良く考えた上で、この機能を使うか、Amazon RDSなど他のソリューションを使うか、選択したほうが良いでしょう。

2017/04/15追記:MySQL 8.0.1(DMR)で追加された、REDOログ/UNDOログの暗号化についても試してみました。
MySQL 8.0.1 DMRでテーブルスペース暗号化+REDOログ/UNDOログ暗号化


【おまけ】
MySQL 5.7関連投稿記事へのリンクを集めました。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away