mysql.global_priv テーブル – MariaDB Server 10.4
2019年6月18日にGAとなった MariaDB Server 10.4 ではユーザ認証を管理するテーブルが mysql.user から mysql.global_priv テーブルに変更されています。
今回は mysql.global_priv テーブルについて解説いたします。
mysql.global_priv テーブル
従来,ユーザ認証情報は mysql.user テーブルに収められておりました。
MariaDB [(none)]> select user,host,password,plugin from mysql.user; +----------+-------------+-------------------------------------------+--------+ | user | host | password | plugin | +----------+-------------+-------------------------------------------+--------+ | root | localhost | | | | root | 127.0.0.1 | | | | root | ::1 | | | +----------+-------------+-------------------------------------------+--------+
これに対して,10.4 では以下のようにテーブル名,テーブル構成が変更されております。
# mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 9 Server version: 10.4.5-MariaDB MariaDB Server Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> DESC mysql.global_priv; +-------+----------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +-------+----------+------+-----+---------+-------+ | Host | char(60) | NO | PRI | | | | User | char(80) | NO | PRI | | | | Priv | longtext | NO | | '{}' | | +-------+----------+------+-----+---------+-------+
Priv 列は longtext 型となっていますが,デフォルト値が ‘{}’ となっており,実際はJSON型であることがわかります。
mysql.global_priv テーブルのデータを確認すると,以下のようになっています。
MariaDB [(none)]> SELECT * FROM mysql.global_priv; +-----------+-------+--------------------------------------------------------------------------------------------------------------------------------------------+ | Host | User | Priv | +-----------+-------+--------------------------------------------------------------------------------------------------------------------------------------------+ | localhost | root | {"access":18446744073709551615,"plugin":"mysql_native_password","authentication_string":"invalid","auth_or":[{},{"plugin":"unix_socket"}]} | | localhost | mysql | {"access":18446744073709551615,"plugin":"mysql_native_password","authentication_string":"invalid","auth_or":[{},{"plugin":"unix_socket"}]} | | localhost | | {} | | mdb104 | | {} | +-----------+-------+--------------------------------------------------------------------------------------------------------------------------------------------+
JSON_DETAILED 関数を用いると少し見やすくすることができます。
MariaDB [(none)]> select concat(user, '@', host, ' => ', json_detailed(priv)) from mysql.global_priv; +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | concat(user, '@', host, ' => ', json_detailed(priv)) | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | root@localhost => { "access": 18446744073709551615, "plugin": "mysql_native_password", "authentication_string": "invalid", "auth_or": [ { }, { "plugin": "unix_socket" } ] } | | mysql@localhost => { "access": 18446744073709551615, "plugin": "mysql_native_password", "authentication_string": "invalid", "auth_or": [ { }, { "plugin": "unix_socket" } ] } | | @localhost => { } | | @mdb104 => { } | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
root / mysql ユーザのパスワードハッシュ値は “authentication_string”: “invalid” となっており,”plugin”: “unix_socket” となっていますので,unix_socket プラグインで認証されています。
unix_socket プラグインは以前から Debian などでは有効になっていましたが,10.4.3 からデフォルトの認証形式となりました。この認証方式の場合,MariaDB のユーザ名と同じユーザが Linux OS上で存在すれば,MariaDB サーバに接続可能となります。
/etc/passwd:
root:x:0:0:root:/root:/bin/bash mysql:x:997:994:MySQL server:/var/lib/mysql:/sbin/nologin
また,ユーザ毎に認証方式を変更することができますので,以前から mysql_native_password を用いる既存ユーザがいて,新規ユーザにはよりセキュアな ed25519 認証を用いたいといった場合に,認証プラグインを変更することができます。
Authentication Plugin – ed25519
mysql_native_password 認証では,SHA-1 を用いて計算されたハッシュ値が mysql.user テーブルの password 列に収められていましたが,SSL証明書などでも SHA-1 はかなり以前に非推奨で,SHA-256 を用いてハッシュ値を生成することが一般的となっており,現在の水準では十分に安全とはいえません。
そこで,10.1.22 から ed25519 認証プラグインが導入されています。ed25519 は Elliptic Curve Digital Signature Algorithm(ECSA) と呼ばれる OpenSSH でも用いられるアルゴリズムを用いています。
ed25519 プラグインはデフォルトではインストールされていませんので,以下のコマンドを MariaDB monitor(mysql) などで実行,インストールする必要があります。
INSTALL SONAME 'auth_ed25519';
念のため,show plugins で確認します(実行結果は抜粋しています)。
MariaDB [(none)]> show plugins; +-------------------------------+----------+--------------------+-----------------+---------+ | Name | Status | Type | Library | License | +-------------------------------+----------+--------------------+-----------------+---------+ | mysql_native_password | ACTIVE | AUTHENTICATION | NULL | GPL | | mysql_old_password | ACTIVE | AUTHENTICATION | NULL | GPL | | ed25519 | ACTIVE | AUTHENTICATION | auth_ed25519.so | GPL | +-------------------------------+----------+--------------------+-----------------+---------+
正常にインストールされていることが確認できました。
ed25519 認証を用いる新規ユーザを作成してみます。
MariaDB [(none)]> GRANT ALL ON *.* to safe@'%' IDENTIFIED VIA ed25519 USING PASSWORD('secret'); MariaDB [(none)]> SELECT CONCAT(user, '@', host, ' => ', json_detailed(priv)) FROM mysql.global_priv; +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | concat(user, '@', host, ' => ', json_detailed(priv)) | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | safe@% => { "access": 1073740799, "plugin": "ed25519", "authentication_string": "ZIgUREUg5PVgQ6LskhXmO+eZLS0nC8be6HPjYWR4YJY", "password_last_changed": 1560226756 } | +----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
authentication_string にハッシュ値が入力されていることが確認できます。なお,ed25519 認証を用いるにはこれに対応したバージョンの MariaDB Connector を用いる必要があります。
なお,互換性のため mysql.user は VIEW として定義されております。
MariaDB [(none)]> SELECT user,host,password,plugin FROM mysql.user; +---------+-----------+----------+-----------------------+ | User | Host | Password | plugin | +---------+-----------+----------+-----------------------+ | root | localhost | invalid | mysql_native_password | | mysql | localhost | invalid | mysql_native_password | | safe | % | | ed25519 | +---------+-----------+----------+-----------------------+
MariaDB [mysql]> SHOW CREATE VIEW mysql.user \G *************************** 1. row *************************** View: user Create View: CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `user` AS select `global_priv`.`Host` AS `Host`,`global_priv`.`User` AS `User`,if(json_value(`global_priv`.`Priv`,'$.plugin') in ('mysql_native_password','mysql_old_password'),ifnull(json_value(`global_priv`.`Priv`,'$.authentication_string'),''),'') AS `Password`,if(json_value(`global_priv`.`Priv`,'$.access') & 1,'Y','N') AS `Select_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 2,'Y','N') AS `Insert_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 4,'Y','N') AS `Update_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 8,'Y','N') AS `Delete_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 16,'Y','N') AS `Create_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 32,'Y','N') AS `Drop_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 64,'Y','N') AS `Reload_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 128,'Y','N') AS `Shutdown_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 256,'Y','N') AS `Process_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 512,'Y','N') AS `File_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 1024,'Y','N') AS `Grant_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 2048,'Y','N') AS `References_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 4096,'Y','N') AS `Index_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 8192,'Y','N') AS `Alter_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 16384,'Y','N') AS `Show_db_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 32768,'Y','N') AS `Super_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 65536,'Y','N') AS `Create_tmp_table_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 131072,'Y','N') AS `Lock_tables_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 262144,'Y','N') AS `Execute_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 524288,'Y','N') AS `Repl_slave_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 1048576,'Y','N') AS `Repl_client_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 2097152,'Y','N') AS `Create_view_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 4194304,'Y','N') AS `Show_view_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 8388608,'Y','N') AS `Create_routine_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 16777216,'Y','N') AS `Alter_routine_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 33554432,'Y','N') AS `Create_user_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 67108864,'Y','N') AS `Event_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 134217728,'Y','N') AS `Trigger_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 268435456,'Y','N') AS `Create_tablespace_priv`,if(json_value(`global_priv`.`Priv`,'$.access') & 536870912,'Y','N') AS `Delete_history_priv`,elt(ifnull(json_value(`global_priv`.`Priv`,'$.ssl_type'),0) + 1,'','ANY','X509','SPECIFIED') AS `ssl_type`,ifnull(json_value(`global_priv`.`Priv`,'$.ssl_cipher'),'') AS `ssl_cipher`,ifnull(json_value(`global_priv`.`Priv`,'$.x509_issuer'),'') AS `x509_issuer`,ifnull(json_value(`global_priv`.`Priv`,'$.x509_subject'),'') AS `x509_subject`,cast(ifnull(json_value(`global_priv`.`Priv`,'$.max_questions'),0) as unsigned) AS `max_questions`,cast(ifnull(json_value(`global_priv`.`Priv`,'$.max_updates'),0) as unsigned) AS `max_updates`,cast(ifnull(json_value(`global_priv`.`Priv`,'$.max_connections'),0) as unsigned) AS `max_connections`,cast(ifnull(json_value(`global_priv`.`Priv`,'$.max_user_connections'),0) as signed) AS `max_user_connections`,ifnull(json_value(`global_priv`.`Priv`,'$.plugin'),'') AS `plugin`,ifnull(json_value(`global_priv`.`Priv`,'$.authentication_string'),'') AS `authentication_string`,'N' AS `password_expired`,elt(ifnull(json_value(`global_priv`.`Priv`,'$.is_role'),0) + 1,'N','Y') AS `is_role`,ifnull(json_value(`global_priv`.`Priv`,'$.default_role'),'') AS `default_role`,cast(ifnull(json_value(`global_priv`.`Priv`,'$.max_statement_time'),0.0) as decimal(12,6)) AS `max_statement_time` from `global_priv` character_set_client: latin1 collation_connection: latin1_swedish_ci
まとめ
MariaDB Server 10.4 から変更されたユーザ認証テーブルに関して解説させて頂きました。