MySQL8.0.20でSHOW_ROUTINEなる権限ができたらしい
退職して絶賛有休消化中なので、日々「有効な時間の使い方とは何か」という命題と戦っています。
とりあえずMySQL8.0.20がGAになったので、リリースノートをまったり読んでいます。
今回は新しく追加された権限についてです。
MySQL8.0.20でSHOW_ROUTINE
という権限が新しくできたようです。
3行で
MySQL8.0.20で
SHOW_ROUTINE
という権限が導入された今まで自分以外が定義したプロシージャなどの定義を確認したい場合は、グローバルレベルのSELECT権限という非常に広い権限が必要だった
SHOW_ROUTINE
権限によりグローバルレベルのSELECT権限が無くても、他人が定義したプロシージャの定義も確認できるようになった(ただしmysqldumpは不可)
ということで実際に試してみましょう。
以前のバージョンで
まずは、MySQL8.0.19で試してみます。
mysql8019-root@localhost:[(none)] >CREATE USER test_user IDENTIFIED BY 'test'; Query OK, 0 rows affected (0.02 sec) mysql8019-root@localhost:[(none)] >CREATE DATABASE db1; Query OK, 1 row affected (0.01 sec) mysql8019-root@localhost:[(none)] >GRANT SELECT ON db1.* TO test_user; Query OK, 0 rows affected (0.02 sec) mysql8019-root@localhost:[(none)] >USE db1; Database changed mysql8019-root@localhost:[db1] >DELIMITER // mysql8019-root@localhost:[db1] >CREATE PROCEDURE test_routine(IN a INT, IN b INT) -> BEGIN -> SELECT a + b AS 'sum'; -> END -> // Query OK, 0 rows affected (0.02 sec) mysql8019-root@localhost:[db1] >DELIMITER ;
まずはこの状態ではtest_user
がdb1.test_routine
の定義を確認できないことを見てみましょう。
mysql8019-test_user@localhost:[db1] >SHOW GRANTS; +--------------------------------------------+ | Grants for test_user@% | +--------------------------------------------+ | GRANT USAGE ON *.* TO `test_user`@`%` | | GRANT SELECT ON `db1`.* TO `test_user`@`%` | +--------------------------------------------+ 2 rows in set (0.00 sec) mysql8019-test_user@localhost:[db1] >SELECT * FROM information_schema.ROUTINES WHERE routine_schema = 'db1'; Empty set (0.01 sec)
Emptyが返ってきてますね。
では、test_user
にグローバルレベルのSELECT権限を渡してみます。
mysql8019-root@localhost:[db1] >GRANT SELECT ON *.* TO test_user; Query OK, 0 rows affected (0.01 sec)
もう一度test_user
でdb1.test_routine
の定義をもう一度確認してみます。
mysql8019-test_user@localhost:[db1] >SHOW GRANTS; +--------------------------------------------+ | Grants for test_user@% | +--------------------------------------------+ | GRANT SELECT ON *.* TO `test_user`@`%` | | GRANT SELECT ON `db1`.* TO `test_user`@`%` | +--------------------------------------------+ 2 rows in set (0.00 sec) mysql8019-test_user@localhost:[db1] >SELECT * FROM information_schema.ROUTINES WHERE routine_schema = 'db1'\G *************************** 1. row *************************** SPECIFIC_NAME: test_routine ROUTINE_CATALOG: def ROUTINE_SCHEMA: db1 ROUTINE_NAME: test_routine ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN SELECT a + b AS 'sum'; END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: SQL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2020-04-30 16:27:13 LAST_ALTERED: 2020-04-30 16:27:13 SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8mb4 COLLATION_CONNECTION: utf8mb4_0900_ai_ci DATABASE_COLLATION: utf8mb4_0900_ai_ci 1 row in set (0.01 sec)
一応test_routineの定義を確認することができました。
またSHOW GRANTS
で権限を確認してみると、USAGEと表示されていた行が消えていることが確認できます。
(USAGEは何の権限もないことを意味しています)
しかし、一方で場合によっては過剰な権限を渡してしまう可能性もあります。
mysql80-test_user@localhost:[(none)] >SELECT * FROM db2.t1; +---+ | a | +---+ | 1 | | 2 | | 3 | +---+ 3 rows in set (0.00 sec)
このように本来、test_user
には見せたくないdb2のテーブルの内容も閲覧できてしまいます。
SHOW_ROUTINEを使おう
さっそくMySQL8.0.20で試してみましょう。
mysql8020-root@localhost:[db1] >SELECT VERSION(); +-----------+ | VERSION() | +-----------+ | 8.0.20 | +-----------+ 1 row in set (0.00 sec) mysql8020-root@localhost:[(none)] >CREATE USER test_user IDENTIFIED BY 'test'; Query OK, 0 rows affected (0.01 sec) mysql8020-root@localhost:[(none)] >CREATE DATABASE db1; Query OK, 1 row affected (0.01 sec) mysql8020-root@localhost:[(none)] >GRANT SELECT ON db1.* TO test_user; Query OK, 0 rows affected (0.03 sec) mysql8020-root@localhost:[(none)] >USE db1; Database changed mysql8020-root@localhost:[db1] >DELIMITER // mysql8020-root@localhost:[db1] >CREATE PROCEDURE test_routine(IN a INT, IN b INT) -> BEGIN -> SELECT a + b AS 'sum'; -> END -> // Query OK, 0 rows affected (0.02 sec) mysql8020-root@localhost:[db1] >DELIMITER ;
当たり前ですが、この状態ではプロシージャの定義を確認することはできません。
mysql8020-test_user@localhost:[information_schema] >SHOW GRANTS; +--------------------------------------------+ | Grants for test_user@% | +--------------------------------------------+ | GRANT USAGE ON *.* TO `test_user`@`%` | | GRANT SELECT ON `db1`.* TO `test_user`@`%` | +--------------------------------------------+ 2 rows in set (0.00 sec) mysql8020-test_user@localhost:[information_schema] >SELECT * FROM information_schema.ROUTINES WHERE routine_schema = 'db1'; Empty set (0.01 sec)
では、本題
SHOW_ROUTINE
を与えてプロシージャの権限が確認できるか見てみます。
mysql8020-root@localhost:[db1] >GRANT SHOW_ROUTINE ON *.* TO test_user; Query OK, 0 rows affected (0.00 sec)
注意点として、権限を与えるときはグローバルレベルで与える必要があります。
mysql8020-root@localhost:[db1] >GRANT SHOW_ROUTINE ON db1.* TO test_user; ERROR 3619 (HY000): Illegal privilege level specified for SHOW_ROUTINE
さてさて、もう一度test_user
でプロシージャの定義を確認してみます。
mysql8020-test_user@localhost:[db1] >SHOW GRANTS; +----------------------------------------------+ | Grants for test_user@% | +----------------------------------------------+ | GRANT USAGE ON *.* TO `test_user`@`%` | | GRANT SHOW_ROUTINE ON *.* TO `test_user`@`%` | | GRANT SELECT ON `db1`.* TO `test_user`@`%` | +----------------------------------------------+ 3 rows in set (0.00 sec) mysql8020-test_user@localhost:[db1] >SELECT * FROM information_schema.ROUTINES WHERE routine_schema = 'db1'\G *************************** 1. row *************************** SPECIFIC_NAME: test_routine ROUTINE_CATALOG: def ROUTINE_SCHEMA: db1 ROUTINE_NAME: test_routine ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN SELECT a + b AS 'sum'; END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: SQL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2020-04-30 17:00:11 LAST_ALTERED: 2020-04-30 17:00:11 SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8mb4 COLLATION_CONNECTION: utf8mb4_0900_ai_ci DATABASE_COLLATION: utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
無事にtest_routine
の権限を確認できました。
また、SHOW GRANTS
したときにUSAGEの行が消えていないことが分かります。
この状態で他のデータベース(db2)の中身も見えないのか確認してみます。
mysql8020-test_user@localhost:[db1] >SELECT * FROM db2.t1; ERROR 1142 (42000): SELECT command denied to user 'test_user'@'localhost' for table 't1' mysql8020-test_user@localhost:[db1] >SHOW DATABASES; +--------------------+ | Database | +--------------------+ | db1 | | information_schema | +--------------------+ 2 rows in set (0.00 sec)
大丈夫そうですね。
ただし、当たり前ですがdb2のプロシージャの定義は確認できてしまうので注意です。
mysql8020-test_user@localhost:[db1] >SELECT * FROM information_schema.ROUTINES WHERE routine_schema = 'db2'\G *************************** 1. row *************************** SPECIFIC_NAME: test_routine ROUTINE_CATALOG: def ROUTINE_SCHEMA: db2 ROUTINE_NAME: test_routine ROUTINE_TYPE: PROCEDURE DATA_TYPE: CHARACTER_MAXIMUM_LENGTH: NULL CHARACTER_OCTET_LENGTH: NULL NUMERIC_PRECISION: NULL NUMERIC_SCALE: NULL DATETIME_PRECISION: NULL CHARACTER_SET_NAME: NULL COLLATION_NAME: NULL DTD_IDENTIFIER: NULL ROUTINE_BODY: SQL ROUTINE_DEFINITION: BEGIN SELECT a + b AS 'sum'; END EXTERNAL_NAME: NULL EXTERNAL_LANGUAGE: SQL PARAMETER_STYLE: SQL IS_DETERMINISTIC: NO SQL_DATA_ACCESS: CONTAINS SQL SQL_PATH: NULL SECURITY_TYPE: DEFINER CREATED: 2020-04-30 17:16:30 LAST_ALTERED: 2020-04-30 17:16:30 SQL_MODE: ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION ROUTINE_COMMENT: DEFINER: root@localhost CHARACTER_SET_CLIENT: utf8mb4 COLLATION_CONNECTION: utf8mb4_0900_ai_ci DATABASE_COLLATION: utf8mb4_0900_ai_ci 1 row in set (0.00 sec)
ということでSHOW_ROUTINE
権限を使えば過剰に権限を渡すことなく自分以外が定義したプロシージャの権限を確認することができます。
mysqldumpは別問題・・・?
さて、SHOW_ROUTINE
によって以前より柔軟に権限を設定することができるようになりました。
では、どういったケースで使えるでしょうか。
公式リファレンスでは、SHOW_ROUTINE
によりグローバルSELECT権限なしに、ストアドプロシージャのバックアップをできるようになるとあります。
バックアップと言えばmysqldump!ということで早速バックアップをば
mysql8020-test_user@localhost:[(none)] >SELECT user(); +---------------------+ | user() | +---------------------+ | test_user@localhost | +---------------------+ 1 row in set (0.00 sec) mysql8020-test_user@localhost:[(none)] >SHOW GRANTS; +----------------------------------------------+ | Grants for test_user@% | +----------------------------------------------+ | GRANT USAGE ON *.* TO `test_user`@`%` | | GRANT SHOW_ROUTINE ON *.* TO `test_user`@`%` | +----------------------------------------------+ 2 rows in set (0.00 sec)
さてこんなユーザーに対してmysqldumpでストアドプロシージャのみバックアップしてみます。
[root@centos8-instance3:/home]# mysqldump -utest_user -ptest --all-databases -R mysqldump: [Warning] Using a password on the command line interface can be insecure. -- MySQL dump 10.13 Distrib 8.0.20, for Linux (x86_64) -- -- Host: localhost Database: -- ------------------------------------------------------ -- Server version 8.0.20 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!50503 SET NAMES utf8mb4 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!50606 SET @OLD_INNODB_STATS_AUTO_RECALC=@@INNODB_STATS_AUTO_RECALC */; /*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=OFF */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=@OLD_INNODB_STATS_AUTO_RECALC */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2020-04-30 18:03:45
🤔・・・?
何も表示されませんね・・・
mysqldumpのリファレンスにはこうあります。
MySQL :: MySQL 8.0 Reference Manual :: 4.5.4 mysqldump — A Database Backup Program
から引用
Include stored routines (procedures and functions) for the dumped databases in the output. This option requires the global SELECT privilege.
😇< 意味ねーじゃねーか!
試しにdb1のSELECT権限だけ渡してみます。
mysql8020-root@localhost:[db2] >GRANT SELECT ON db1.* TO test_user; Query OK, 0 rows affected (0.00 sec)
再度mysqldumpを実行
[root@centos8-instance3:/home]# mysqldump -utest_user -ptest --all-databases -R mysqldump: [Warning] Using a password on the command line interface can be insecure. -- MySQL dump 10.13 Distrib 8.0.20, for Linux (x86_64) -- -- Host: localhost Database: -- ------------------------------------------------------ -- Server version 8.0.20 /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!50503 SET NAMES utf8mb4 */; /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; /*!40103 SET TIME_ZONE='+00:00' */; /*!50606 SET @OLD_INNODB_STATS_AUTO_RECALC=@@INNODB_STATS_AUTO_RECALC */; /*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=OFF */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -- -- Current Database: `db1` -- CREATE DATABASE /*!32312 IF NOT EXISTS*/ `db1` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; USE `db1`; -- -- Dumping routines for database 'db1' -- /*!50003 DROP PROCEDURE IF EXISTS `test_routine` */; /*!50003 SET @saved_cs_client = @@character_set_client */ ; /*!50003 SET @saved_cs_results = @@character_set_results */ ; /*!50003 SET @saved_col_connection = @@collation_connection */ ; /*!50003 SET character_set_client = utf8mb4 */ ; /*!50003 SET character_set_results = utf8mb4 */ ; /*!50003 SET collation_connection = utf8mb4_0900_ai_ci */ ; /*!50003 SET @saved_sql_mode = @@sql_mode */ ; /*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION' */ ; DELIMITER ;; CREATE DEFINER=`root`@`localhost` PROCEDURE `test_routine`(IN a INT, IN b INT) BEGIN SELECT a + b AS 'sum'; END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; /*!50003 SET character_set_client = @saved_cs_client */ ; /*!50003 SET character_set_results = @saved_cs_results */ ; /*!50003 SET collation_connection = @saved_col_connection */ ; /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!50606 SET GLOBAL INNODB_STATS_AUTO_RECALC=@OLD_INNODB_STATS_AUTO_RECALC */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; -- Dump completed on 2020-04-30 18:09:59
うーん、やっぱりSELECT権限は必要なようですね。
このあたりは、バグ報告というよりFuture Requestしたほうがいいんですかね。 (どなたかやってくれないかなあ|ω・`) )
現在、無職中なのでOracleプロファイルの作成ができないんですよねorz
今回はこのあたりで