はじめに
MySQL にはキーリングと呼ばれる機能が存在しています。
過去に当ブログで紹介させていただいた透過的テーブルスペース暗号化やバイナリログとリレーログの暗号化にはこのキーリングが使用されており、この他にも MySQL Enterprise Audit における監査ログの暗号化の際に利用されています。
MySQL 8.0.24 では、このキーリングの実装方法が従来のプラグイン形式に加えて、コンポーネント形式も用意されるようになりました。
今回は、この新しいキーリングコンポーネントについて、使用方法などを確認していきたいと思います。
インストール方法
通常、MySQL においてコンポーネントをインストールする場合、INSTALL COMPONENT コマンドを使用してインストールをおこなうことができます。この場合、mysql.component システムテーブルに登録されて、MySQL サーバーを起動して InnoDB テーブルを初期化した後に読み込まれるという動作をおこないますが、キーリングコンポーネントのように InnoDB ストレージエンジンテーブルの初期化前に読み込まれている必要がある機能についてはこのタイミングでは遅いため、より早い段階でコンポーネントをロードする必要があります。
そこで、コンポーネントの場合はプラグインのように early-plugin-load を指定することはできないため、MySQL サーバーの起動時にロードするためのマニフェストファイルを別途作成する必要があります。
マニフェストファイルの作成
MySQL サーバーの起動時、マニフェストファイルは以下のように読み取られます。
- mysqld がインストールされているディレクトリからグローバルマニフェストファイルを読み取ります。
- グローバルマニフェストファイルでローカルマニフェストファイルの使用が指示されている(
"read_local_manifest":true
)場合、データディレクトリ(datadir)からローカルマニフェストファイルを読み取ります。 - ローバルマニフェストファイルとローカルマニフェストファイルの名前は、どちらも
mysqld.my
です。 - マニフェストファイルが存在しない場合、コンポーネントはロードされませんが、MySQL サーバーの起動自体はエラーになりません。
そして、マニフェストファイルは以下のような内容になっています。
- JSON 形式で作成します。
- 以下の 2 つの設定が存在します。
- read_local_manifest : グローバルマニフェストファイルにのみ記載します。値が
false
あるいは記載がない場合はグローバルマニフェストファイルの他の項目を適用して、ローカルマニフェストファイルの内容を無視します。値がtrue
の場合はローカルマニフェストファイルの項目を適用して、グローバルマニフェストファイルの他の内容を無視します。 - components : ロードするコンポーネントの URN を指定します。値は「
file://component_keyring_file
」のように、先頭にfile://
をつけて、プラグインディレクトリ(plugin_dir)にあるライブラリファイルのベース名を指定します。
- read_local_manifest : グローバルマニフェストファイルにのみ記載します。値が
- マニフェストファイルの権限は mysqld の実行ユーザーから読み取り専用にする必要があります。たとえば、マニフェストファイルの所有権が root ユーザーであった場合、パーミッションは
644
などに設定する必要があります。 - マニフェストファイルが正常に読み取れなかった場合、MySQL サーバーの起動はエラーになるので注意が必要です。
したがって、たとえばグローバルマニフェストファイルを使用して component_keyring_file コンポーネントをインストールする場合、以下のようにファイルを作成します。
1 2 3 4 5 6 7 8 9 |
# find / -type f -path "*/mysqld" /usr/sbin/mysqld # tee /usr/sbin/mysqld.my { "components": "file://component_keyring_file" } ^C # ls -l /usr/sbin/mysqld.my -rw-r--r-- 1 root root 52 6月 7 18:07 /usr/sbin/mysqld.my |
あるいは、グローバルマニフェストファイルとローカルマニフェストファイルを使用して mysqld プロセス毎に異なるコンポーネントをロードさせたい場合、以下のようにファイルを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# find / -type f -path "*/mysqld" /usr/sbin/mysqld # tee /usr/sbin/mysqld.my { "read_local_manifest": true } ^C # mysql -sNe "SELECT @@datadir;" /var/lib/mysql/ # tee /var/lib/mysql/mysqld.my { "components": "file://component_keyring_file" } ^C # ls -l /usr/sbin/mysqld.my /var/lib/mysql/mysqld.my -rw-r--r-- 1 root root 34 6月 7 18:16 /usr/sbin/mysqld.my -rw-r--r-- 1 root root 52 6月 7 18:16 /var/lib/mysql/mysqld.my |
構成ファイルの作成
さらに、component_keyring_file コンポーネントを利用するためには、構成ファイルも別途作成する必要があります。構成ファイルの概要は以下の通りです。
- コンポーネントの初期化時に、グローバル構成ファイルあるいはローカル構成ファイルを追加で読み取ります。
- グローバル構成ファイルはコンポーネントライブラリ(component_keyring_file)がインストールされているディレクトリ(plugin_dir)から読み取ります。
- グローバル構成ファイルでローカル構成ファイルの使用が指示されている(
"read_local_config":true
)場合、データディレクトリ(datadir)からローカル構成ファイルを読み取ります。 - グローバル構成ファイルとローカル構成ファイルの名前は、どちらも
component_keyring_file.cnf
です。 - 構成ファイルが存在しない場合、コンポーネントの初期化はエラーとなり使用することができません。
そして、構成ファイルは以下のような内容になっています。
- JSON 形式で作成します。
- 以下の 3 つの設定が存在します。
- read_local_config : グローバル構成ファイルにのみ記載します。値が
false
あるいは記載がない場合はグローバル構成ファイルの他の項目を適用して、ローカル構成ファイルの内容を無視します。値がtrue
の場合はローカル構成ファイルの項目を適用して、グローバル構成ファイルの他の内容を無視します。 - path : キーリングデータの保存に使用するファイルを指定します。値の指定は必須であり、絶対パスを使用して名前をつける必要があります。
- read_only : キーリングファイルのデータが読み取り専用かどうかを指定します。値の指定は必須であり、
true
の場合は読み取り専用、false
の場合は読み取りおよび書き込みが可能です。
- read_local_config : グローバル構成ファイルにのみ記載します。値が
したがって、たとえばグローバル構成ファイルを使用する場合、以下のようにファイルを作成します。
1 2 3 4 5 6 7 8 9 10 |
# mysql -sNe "SELECT @@plugin_dir;" /usr/lib64/mysql/plugin/ # mkdir /usr/local/mysql /usr/local/mysql/keyring # chown -R mysql:mysql /usr/local/mysql # tee /usr/lib64/mysql/plugin/component_keyring_file.cnf { "path": "/usr/local/mysql/keyring/component_keyring_file", "read_only": false } ^C |
あるいは、グローバル構成ファイルとローカル構成ファイルを使用して mysqld プロセス毎に異なる設定にしたい場合、以下のようにファイルを作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# mysql -sNe "SELECT @@plugin_dir;" /usr/lib64/mysql/plugin/ # mkdir /usr/local/mysql /usr/local/mysql/keyring # chown -R mysql:mysql /usr/local/mysql # tee /usr/lib64/mysql/plugin/component_keyring_file.cnf { "read_local_config": true } ^C # mysql -sNe "SELECT @@datadir;" /var/lib/mysql/ # tee /var/lib/mysql/component_keyring_file.cnf { "path": "/usr/local/mysql/keyring/component_keyring_file", "read_only": false } ^C |
設定の反映
ここまで設定できたら、MySQL サーバーを起動することで component_keyring_file コンポーネントが有効になります。パフォーマンススキーマの keyring_component_status テーブルからコンポーネントを確認することができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
mysql> SELECT * FROM performance_schema.keyring_component_status; +---------------------+-------------------------------------------------+ | STATUS_KEY | STATUS_VALUE | +---------------------+-------------------------------------------------+ | Component_name | component_keyring_file | | Author | Oracle Corporation | | License | GPL | | Implementation_name | component_keyring_file | | Version | 1.0 | | Component_status | Active | | Data_file | /usr/local/mysql/keyring/component_keyring_file | | Read_only | No | +---------------------+-------------------------------------------------+ 8 rows in set (0.00 sec) |
なお、何らかの要因で起動時にコンポーネントのロードに失敗してしまった場合、エラーログに以下のようなメッセージが出力されます。
1 |
[ERROR] [MY-013714] [Server] Component component_keyring_file reported: 'The component is not initialized properly. Make sure that configuration is proper and use ALTER INSTANCE RELOAD KEYRING to reinitialize the component.' |
その場合は、マニフェストファイルや構成ファイルなどが正しく設定されていることを確認した後、ALTER INSTANCE RELOAD KEYRING を実行することで、コンポーネントの再読み込みをおこなうことが可能です。
利用方法
利用方法については以前のキーリングプラグインと同様に扱うことが可能ですので、以下の記事などをご参照いただければと思います。
その他、以下のような汎用キーリングキー管理関数を作成して利用することも可能です。
1 2 3 4 5 6 7 8 9 |
mysql> INSTALL PLUGIN keyring_udf SONAME 'keyring_udf.so'; mysql> CREATE FUNCTION keyring_key_generate RETURNS INTEGER SONAME 'keyring_udf.so'; mysql> CREATE FUNCTION keyring_key_fetch RETURNS STRING SONAME 'keyring_udf.so'; mysql> CREATE FUNCTION keyring_key_length_fetch RETURNS INTEGER SONAME 'keyring_udf.so'; mysql> CREATE FUNCTION keyring_key_type_fetch RETURNS STRING SONAME 'keyring_udf.so'; mysql> CREATE FUNCTION keyring_key_store RETURNS INTEGER SONAME 'keyring_udf.so'; mysql> CREATE FUNCTION keyring_key_remove RETURNS INTEGER SONAME 'keyring_udf.so'; mysql> SELECT keyring_key_generate('MyKey', 'AES', 32); |
キーリングプラグインからの移行方法
既存のキーリングプラグインからキーリングコンポーネントにキーリングデータを移行する場合、MySQL 8.0.24 から移行サーバーモードでの移行が可能になりました。
キーリングプラグインからキーリングコンポーネントへの移行方法には以下の 2 つが存在しており、システムの稼働状況に応じて使い分けることができます。
- オフライン移行 : 移行元あるいは移行先のキーストアを利用しているユーザーがいないことがわかっている場合に使用します。
- オンライン移行 : 移行元あるいは移行先のキーストアを利用しているユーザーがいる場合はこちらを使用します。keyring_operations が有効(デフォルト値 : ON)になっており、SYSTEM_VARIABLES_ADMIN および ENCRYPTION_KEY_ADMIN 権限を持ったユーザーで実行する必要があります。
たとえば、keyring_file プラグインから component_keyring_file コンポーネントにオフライン移行する場合、コンポーネント用の設定を準備してから以下のようなコマンドを実行します。
なお、エラーメッセージなどは標準出力されます。また、実行ユーザーが root の場合、my.cnf などに user オプションを指定しないとエラーで実行できないので注意してください。
1 |
# mysqld --defaults-file=/etc/my.cnf --keyring-migration-to-component --keyring-migration-source=keyring_file.so --keyring-migration-destination=component_keyring_file.so |
あるいはオンライン移行をおこなう場合、ユーザーを指定して以下のようなコマンドを実行しますが、こちらは MySQL 8.0.25 現在、恐らく何らかのバグの影響で実行するとエラーが発生するようですので、実行しないようにご注意ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# mysqld --defaults-file=/etc/my.cnf --keyring-migration-to-component --keyring-migration-source=keyring_file.so --keyring-migration-destination=component_keyring_file.so --keyring-migration-host=127.0.0.1 --keyring-migration-user=root --keyring-migration-password=<root_password> 2021-06-08T06:29:57.438782Z 0 [Warning] [MY-000057] [Server] Using a password on the command line interface can be insecure. 2021-06-08T06:29:57.618431Z 0 [System] [MY-010116] [Server] /usr/sbin/mysqld (mysqld 8.0.25) starting as process 84411 2021-06-08T06:29:57.621149Z 0 [ERROR] [MY-013106] [Server] Can not perform keyring migration : Connection to server failed.. 2021-06-08T06:29:57.621156Z 0 [ERROR] [MY-011084] [Server] Keyring migration failed. *** Error in `/usr/sbin/mysqld': free(): invalid pointer: 0x00007f0ed01cbd68 *** ======= Backtrace: ========= /lib64/libc.so.6(+0x81499)[0x7f0ece1a5499] /usr/sbin/mysqld(_ZN15Migrate_keyringD1Ev+0x31)[0x117d8d1] /usr/sbin/mysqld(_Z11mysqld_mainiPPc+0x142d)[0xc8312d] /lib64/libc.so.6(__libc_start_main+0xf5)[0x7f0ece146445] /usr/sbin/mysqld[0xc68fe7] ======= Memory map: ======== (...) stack_bottom = 0 thread_stack 0x46000 /usr/sbin/mysqld(my_print_stacktrace(unsigned char const*, unsigned long)+0x3d) [0x1f0083d] /usr/sbin/mysqld(handle_fatal_signal+0x30b) [0xed4b8b] /lib64/libpthread.so.0(+0xf6d0) [0x7f0ecfe446d0] /lib64/libc.so.6(gsignal+0x37) [0x7f0ece15a277] /lib64/libc.so.6(abort+0x148) [0x7f0ece15b968] /lib64/libc.so.6(+0x78d37) [0x7f0ece19cd37] /lib64/libc.so.6(+0x81499) [0x7f0ece1a5499] /usr/sbin/mysqld(Migrate_keyring::~Migrate_keyring()+0x31) [0x117d8d1] /usr/sbin/mysqld(mysqld_main(int, char**)+0x142d) [0xc8312d] /lib64/libc.so.6(__libc_start_main+0xf5) [0x7f0ece146445] /usr/sbin/mysqld() [0xc68fe7] The manual page at http://dev.mysql.com/doc/mysql/en/crashing.html contains information that should help you find out what is causing the crash. |
実行することでキーリングデータが移行先のコンポーネントで設定したファイルに移行されます。なお、実行した後はコンポーネントを反映させるために、一度 MySQL サーバーを再起動するようにしてください。
キーリングプラグインとの違い
従来の keyring_file プラグインなどに比べて、component_keyring_file コンポーネントは以下のような違いがあります。
- インストールをおこなう際に early-plugin-load オプションではなくマニフェストファイルを用意する。
- キーリングの設定はシステム変数(keyring_file_data)ではなく独自の構成ファイルに記載する。
- サポートされているキーのタイプや長さの制限がほぼない。(16MB 以下のキー長であればタイプは問わない。)
そのため、MySQL 8.0.25 時点では設定できる項目に対して利用するまでの準備が多く、キーリングデータの制約が少ないこと以外の利点はあまりなさそうな印象を受けます。
まとめ
ここまで、キーリングコンポーネントのインストール方法や移行方法について確認してきました。
今回は component_keyring_file コンポーネントについて紹介しましたが、有償版であれば component_keyring_encrypted_file コンポーネントを利用することも可能です。ただし、どちらも PCI DSS や FIPS などのセキュリティ標準は満たしていないため、そのような場合は keyring_okv や keyring_aws、keyring_oci といった従来の有償キーリングプラグインを使用する必要があります。
現時点ではあまりキーリングコンポーネントを利用することの利点が感じられませんでしたが、今後のリリースでキーリングコンポーネントの設定項目や高いセキュリティ基準を満たしたコンポーネントが増えるなど拡張が進んでいくことが予想されます。そのため、今のうちから新しい機能に慣れておく意味でも、興味のある方は一度触れてみてはいかがでしょうか。