MySQL道普請便り

第19回 MySQLのユーザー管理について[その2]

この記事を読むのに必要な時間:およそ 4 分

前々回から何回かに分けて,MySQLのユーザー認証について説明しています。「第17回 MySQLのユーザー管理について[その1]⁠では,⁠ホスト名」⁠⁠ユーザー」⁠⁠パスワード」についてと, mysql.user テーブルについて説明しました。今回は「root@127.0.0.1とroot@localhostは別アカウントのはずなのに認証できてしまう謎」について説明したいと思います。

第17回から引き続き,今回のデモンストレーション環境は敢えて「匿名アカウント」を有効にしておくために,MySQL 5.6をyumリポジトリーからインストールしたものになっています。各バージョンのyum版, rpm版の構成の違いは 「第10回 yum, rpmインストールにおけるMySQL 5.6とMySQL 5.7の違い」 を参考にしてください。

筆者がCentOS 6.6上で今回の環境を作るために実行したコマンドは以下の通りです。

$ sudo yum install -y http://dev.mysql.com/get/mysql57-community-release-el6-7.noarch.rpm
$ sudo yum install -y --disablerepo=mysql57-community --enablerepo=mysql56-community mysql-community-server
$ sudo service mysqld start

root@127.0.0.1とroot@localhostは別アカウントか

前々回説明した通り,MySQLはアカウントを「接続元ホスト」「ユーザー」の組を用いて一意に識別するため,⁠root@127.0.0.1とroot@localhostは別アカウントである」というのが一応の説明です。

TCP経由でローカルホストに接続する場合は「接続元ホスト127.0.0.1」のコネクションとなりroot@127.0.0.1アカウントが利用されるのに対し,UNIXソケット経由で接続する場合は「接続元ホストlocalhost(UNIXソケットに「接続元ホスト」の概念はない)⁠のコネクションとなりroot@localhostアカウントが利用されます。

上記の説明が原則ではあるのですが,MySQLはデフォルトで「接続元ホストの名前解決」機能が有効になっており,これが事態をややこしくします。

TCP経由で接続する

まずは原則通り動くケースとして,/etc/my.cnf[mysqld]セクションにskip_name_resolveオプションを追記してMySQLを再起動します。

$ sudo vim /etc/my.cnf
..
[mysqld]
skip_name_resolve
..

$ sudo service mysqld restart

この状態でTCP接続を試してみましょう。MySQLサーバが動いているマシン上で明示的にTCP接続を指定するためには,--protocol=tcpオプションまたは-h127.0.0.1オプションを使用します。

$ mysql -uroot -h127.0.0.1
mysql> SELECT current_user();
+----------------+
| current_user() |
+----------------+
| root@127.0.0.1 |
+----------------+
1 row in set (0.00 sec)

ちなみにIPv6形式で-h::1と指定した場合,⁠接続元ホスト」がIPv6形式のものが利用されました。

$ mysql -uroot -h::1
mysql> SELECT current_user();
+----------------+
| current_user() |
+----------------+
| root@::1       |
+----------------+
1 row in set (0.00 sec)

UNIXソケットで接続する

同じくUNIXソケット接続ではこのようになります。ローカルホストへの接続は,-hオプションで明示的にIPアドレス形式を取るか,--protocol=tcpオプションを指定しない限り,優先的にUNIXソケット接続を利用しようとします(Windows系OSの場合はUNIXソケット接続が存在せず,優先的にTCP接続を利用しようとします)⁠

$ mysql -uroot
mysql> SELECT current_user();
+----------------+
| current_user() |
+----------------+
| root@localhost |
+----------------+
1 row in set (0.00 sec)

root@localhostアカウントを削除する

この状態で,root@localhostアカウントをDROP USERしてみましょう。

mysql> DROP USER root@localhost;
Query OK, 0 rows affected (0.01 sec)

これで,⁠理屈の上では)⁠TCP接続を使ったroot@127.0.0.1にはアクセス可能だが,UNIXソケット接続のroot@localhostにはアクセス不可」な状態になりました。

$ mysql -uroot -h127.0.0.1 -sse "SELECT current_user()"
root@127.0.0.1

$ mysql -uroot -sse "SELECT current_user()"
@localhost

TCP接続は変わらずroot@127.0.0.1アカウントで認証されていますが,UNIXソケット接続の方は「@localhost」という「ユーザー部分が空欄」の妙なアカウント(⁠匿名アカウント」と呼びます)で認証されました。認証されてしまっているので少しきまりが悪いですが,少なくともroot@localhostアカウントは利用できなくなったことがわかります。

匿名アカウントは「接続元ホストのみを検証し,ユーザーとパスワードを検証しない」ユーザーです。今回の場合はroot@localhostを DROP したことで,⁠接続元ホストlocalhostにのみマッチした登録のないアカウント」と認証されたために匿名アカウントでのログインになっています。

著者プロフィール

yoku0825

GMOメディア株式会社のDBA。日本MySQLユーザ会員。主に地雷担当。主食はMySQLだがPercona Server,MariaDB,InfiniDBにMroongaストレージエンジンなど,mysqldでありさえすれば雑食。

Twitter:@yoku0825

コメント

コメントの記入