2022.10.11

MySQL8のファイアウォール新しい権限(FIREWALL_EXEMPT)

こんにちは。次世代システム研究室のB.V.Mです。宜しくお願いします。
(外国人で言葉遣いが間違いましたらご容赦ください。)
MySQLは2018年4月19日 – Version 8.0 プロダクションリリースされました。今まで、多くの新規機能が追加されました。最新バージョンは8.0.30 (2022-07-26)になっております。
今回はMySQL8のファイアウォールが追加された新しい権限(FIREWALL_EXEMPT)について検証してみました。

目次

1. 背景

MySQL8 の 8.0.27 に新機能が加わりました。FIREWALL の機能に FIREWALL_EXEMPT が使えるようになりました。

新しい FIREWALL_EXEMPT 権限は、ユーザーをファイアウォールの制限から免除します。 これは、たとえば、ファイアウォールを構成するデータベース管理者にとって、管理者でさえロックアウトされてステートメントを実行できなくなる構成ミスの可能性を回避するのに役立ちます。元リンク:https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-27.html#mysqld-8-0-27-firewall

という内容がリリースノートに書いてあります。気に入ったのでMySQL8のファイアウォールを検証して、FIREWALL_EXEMPTを使用してみたいです。
MySQL Enterprise Firewall には、悪意のあるデータベース攻撃(ホワイトリストに一致しないSQL文)に対して3つのモードがあります:

許可 – ホワイトリストに一致するSQL文は実行され結果を返します。
ブロック – ホワイトリストに一致しないSQL文を実行せずにブロックします。
検知 – ホワイトリストに一致しないSQL文をブロックせずに実行し、ログに記録することで、データベース管理者にポリシー違反を知らせます。

2. MySQL8ファイアウォール

2.1 ファイアウォールの仕組み

短くいうと:ファイアウォールの仕組みは自動学習システムによって、記録されたルールによりホワイトリストを自動的に生成します。ホワイトリストに一致するSQL文しかが実行されないです。

具体的につて次のステップに従います:
  1. アカウントプロファイルを登録し、RECORDING モードにします。
  2. アカウントを使用して MySQL サーバーに接続し、学習するステートメントを実行します。 これにより、対応するアカウントプロファイルがトレーニングされ、プロファイル allowlist を形成するルールが設定されます。
  3. アカウントプロファイルを PROTECTING モードに切り替えます。 クライアントがアカウントを使用してサーバーに接続すると、アカウントプロファイル allowlist によってステートメントの実行が制限されます。
  4. 追加のトレーニングが必要な場合は、アカウントプロファイルを再度 RECORDING モードに切り替え、新しいステートメントパターンで許可リストを更新してから、PROTECTING モードに戻します。

グループ権限サポート

MySQL 8.0.23 (2021-01-18)にのグループ プロファイルの登録をサポートしています。 グループ プロファイルは、そのメンバーとして複数のアカウントを持つことができます。 ファイアウォール グループ プロファイルを使用して、特定のアカウントからの着信ステートメントから MySQL を保護するには、次の手順に従います。
グループプロファイルで管理するのはMySQLがすすめです。マイグレーションの手順はここで確認できます。

2.2 インストールと検証

まず要注意点はMySQL8のファイアウォールを利用したいのさい必ずMySQL Enterprise Editionをインストールする必要です。試使用版のダウンロードはこちら になります。
WindowsでMySQLファイアウォールをGUIで選択できますが、LinuxやMacなど下記のようなコマンドでインストールになります。
/usr/local/mysql/share mysql -u root mysql < linux_install_firewall.sql
# 確認
mysql> SHOW GLOBAL VARIABLES LIKE 'mysql_firewall_mode';
+---------------------+-------+
| Variable_name | Value |
+---------------------+-------+
| mysql_firewall_mode | ON |
+---------------------+-------+
1 row in set (0.00 sec)
rootにFIREWALL_ADMIN権限を付与必要です。ドキュメントにないですが、これを実行しないと次のコマンドが実行できないです。
GRANT FIREWALL_ADMIN ON *.* TO 'root'@'localhost';
グループ作成とメンバー追加
# mysql> CALL mysql.sp_set_firewall_group_mode('fwgrp', 'RECORDING');
+-------------------------------------------------------+
| read_firewall_group_allowlist(arg_group_name,FW.rule) |
+-------------------------------------------------------+
| Imported users: 0
Imported rules: 0
グループ作成とメンバー追加
mysql> CALL mysql.sp_firewall_group_enlist('fwgrp', 'member1@localhost');
Query OK, 1 row affected (0.01 sec)

mysql> CALL mysql.sp_firewall_group_enlist('fwgrp', 'member2@localhost');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM performance_schema.firewall_membership WHERE GROUP_ID = 'fwgrp' ORDER BY MEMBER_ID;
+----------+-------------------+
| GROUP_ID | MEMBER_ID         |
+----------+-------------------+
| fwgrp    | member1@localhost |
| fwgrp    | member2@localhost |
+----------+-------------------+
2 rows in set (0.00 sec)
ホワイトリスト作成集モードを確認
# confirm recording status:
mysql> SELECT MODE FROM performance_schema.firewall_groups WHERE NAME = 'fwgrp';
+-----------+
| MODE      |
+-----------+
| RECORDING |
+-----------+
1 row in set (0.00 sec)
幾つかコマンドでホワイトリストを登録
mysql> SELECT title, release_year FROM film WHERE film_id = 1;
+------------------+--------------+
| title            | release_year |
+------------------+--------------+
| ACADEMY DINOSAUR |         2006 |
+------------------+--------------+
1 row in set (0.01 sec)

mysql> UPDATE actor SET last_update = NOW() WHERE actor_id = 1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> SELECT store_id, COUNT(*) FROM inventory GROUP BY store_id;
+----------+----------+
| store_id | COUNT(*) |
+----------+----------+
|        1 |     2270 |
|        2 |     2311 |
+----------+----------+
2 rows in set (0.01 sec)
PROTECTINGモードをオンにして、ホワイトリストを登録完了になります。
mysql> CALL mysql.sp_set_firewall_group_mode('fwgrp', 'PROTECTING');
追加したルール確認
mysql> SELECT RULE FROM performance_schema.firewall_group_allowlist WHERE NAME = 'fwgrp';
+----------------------------------------------------------------------+
| RULE                                                                 |
+----------------------------------------------------------------------+
| SELECT @@`version_comment` LIMIT ?                                   |
| UPDATE `actor` SET `last_update` = NOW ( ) WHERE `actor_id` = ?      |
| SELECT `title` , `release_year` FROM `film` WHERE `film_id` = ?      |
| SELECT `store_id` , COUNT ( * ) FROM `inventory` GROUP BY `store_id` |
+----------------------------------------------------------------------+
ファイアウォール の動作確認:設定したアカウントを検証してみて、新たなコマンドなら確かにエラーになっています。
mysql> SELECT `title` , `release_year` FROM `film` WHERE `film_id`= 1;
+------------------+--------------+
| title | release_year |
+------------------+--------------+
| ACADEMY DINOSAUR | 2006 |
+------------------+--------------+
1 row in set (0.00 sec)
mysql> SELECT title, release_year FROM film WHERE film_id = 98 OR TRUE;
ERROR 1045 (28000): Statement was blocked by Firewall
mysql> SELECT `title` , `release_year` FROM `film` WHERE `film_id`= 1 LIMIT 10;
ERROR 1045 (28000): Statement was blocked by Firewall
mysql> SHOW TABLES LIKE 'customer%';
ERROR 1045 (28000): Statement was blocked by Firewall
mysql> TRUNCATE TABLE mysql.slow_log;
ERROR 1045 (28000): Statement was blocked by Firewall

2.2 新しい権限 FIREWALL_EXEMPT

想定される利用用途

今回はrootユーザーも誤差設定でDETECTINGモードに変更してみます。

この状態だと、異常なクエリを実行したらすべて警告が出ています。というのはmember1、member2、root全員はDBが利用できない状態ということを想定してください。この場合だと管理者でさえロックアウトされてステートメントを実行できなくなります。これは大問題です。

この問題を避けるために、事前にFIREWALL_EXEMPT 権限を設定必要です。管理者でさえロックアウトされるのを回避したいのため事前にFIREWALL_EXEMPT権限があるユーザーを準備して、普通の場合を利用しなくて、特別アカウントとして、いざの時そのユーザーを利用してください。その場合にFIREWALL_EXEMPT権限が設定したのユーザーはファイアウォールの対象外としてアクセスできます。

具体的な検証方法

以下では、fw_userユーザーを作成して、FIREWALL_EXEMPT権限を付与して、DBをアクセスするとき警告が出るかどうかを検証してみます。

まず、rootもfwgrpに追加して、DETECTINGモードに変更して、FIREWALL_EXEMPTが付与されるユーザーを確認します。DETECTING モードでは、ファイアウォールは疑わしいステートメントをエラー ログに書き込みますが、アクセスは普通のようにできています。
mysql> CALL mysql.sp_firewall_group_enlist('fwgrp', 'root@localhost');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM performance_schema.firewall_membership WHERE GROUP_ID = 'fwgrp' ORDER BY MEMBER_ID;
+----------+-------------------+
| GROUP_ID | MEMBER_ID         |
+----------+-------------------+
| fwgrp    | member1@localhost |
| fwgrp    | member2@localhost |
| fwgrp    | root@localhost    |
+----------+-------------------+

mysql> CALL mysql.sp_set_firewall_mode('member1@localhost', 'DETECTING');
Query OK, 0 rows affected (0.01 sec)

mysql>  SHOW TABLES LIKE 'customer%';
+------------------------------+
| Tables_in_sakila (customer%) |
+------------------------------+
| customer                     |
| customer_list                |
+------------------------------+
2 rows in set (0.01 sec)

[WARNING] Firewall detected unknown query with digest 0x720N437FE9D6D72A from user [email protected]
SHOW TABLES LIKE ‘customer%’コマンドが実行できるが、警告ログが出ていました。

それでは、新規なfw_userユーザーを作成してFIREWALL_EXEMPT権限を付与して、SQLを実行してみます。
mysql> CREATE USER 'fw_user'@'localhost' IDENTIFIED BY 'password';
Query OK, 0 rows affected (0.05 sec)

mysql> GRANT ALL ON sakila.* TO 'fw_user'@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql>  GRANT FIREWALL_EXEMPT ON *.* TO 'fw_user'@'localhost';
Query OK, 0 rows affected (0.01 sec)
mysql>  use sakila
mysql>  SHOW TABLES LIKE 'customer%';
+------------------------------+
| Tables_in_sakila (customer%) |
+------------------------------+
| customer                     |
| customer_list                |
+------------------------------+
2 rows in set (0.01 sec)
# fwgrpファイアウォールグループプロファイルからアカウントを削除します。
mysql> CALL mysql.sp_firewall_group_delist('fwgrp', 'root@localhost'); 
Query OK, 1 row affected (0.01 sec)
正常に実行できていて、警告ログも出てないです。ですので、fw_userがちゃんファイアウォールの制限から免除されました。誤操作の際、管理者権限でもアクセスできない場合、もし事前にFIREWALL_EXEMPT権限のユーザーを設定したら、いざの時DBにアクセスできて、ロックされているアカウントを復旧できます。今回はrootがfwgrpから削除され、コマンド実行するときは警告が出なくなるのを確認して、確かに警告が出なくなりました。

2.3 おまけ

FIREWALL_EXEMPTが設定されたユーザーは、アップグレード中に権限がどのデータベース ユーザーにも付与されませんでした。 そのバグは
MySQL 8.0.30のリリースで修正しました。ですので、まだ8.0.30にバージョンアップしていない場合ご注意ください。 (バグ #33854409)

感想

MySQLのファイアウォールの新しい権限を検証しました。ファイアウォールはセキュリティ的にとても強い機能ですが、現在エンタープライズ版しかないのは少し残念です。MySQL8が出てから、多く新機能、新設定が出ています。常にリリースノートを確認して、既存システムを最新かの際注意必要だと思います。

参考リンク

最後に

次世代システム研究室では、グループ全体のインテグレーションを支援してくれるアーキテクトを募集しています。インフラ設計、構築経験者の方、次世代システム研究室にご興味を持って頂ける方がいらっしゃいましたら、ぜひ募集職種一覧からご応募をお願いします。 皆さんのご応募をお待ちしています。

  • Twitter
  • Facebook
  • はてなブックマークに追加

グループ研究開発本部の最新情報をTwitterで配信中です。ぜひフォローください。

 
  • AI研究開発室
  • 大阪研究開発グループ

関連記事