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
キーワード検索しても見つかりません。暗号化されたようです。
その他の操作は、以下のとおりです。
・既存テーブルの暗号化
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
システムテーブルスペース(ibdata1)に含まれるUNDOログ(ロールバックセグメント)も暗号化されません。
また、レプリケーション時に使う、バイナリログも暗号化されません(row・mixedの両方で確認)。
# view -b /バイナリログのパス/ログファイル名
おそらくですが、もし仮に、(今後、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関連投稿記事へのリンクを集めました。