MySQL道普請便り

第28回MySQLと名前解決、skip-name-resolve

MySQLと名前解決

MySQLにおいて名前解決は、コネクションの確立・認証のフェーズで利用されます。デフォルト(名前解決が有効)な場合のシーケンスはざっくりと以下のようになります。

  1. IPアドレスがMySQL内の名前解決キャッシュに載っているかどうかを確認する
  2. (載っていない場合⁠⁠ IPアドレスからホスト名に逆引きをかける(getnameinfo)
  3. 得られたホスト名を正引きし、IPアドレスを得る(getaddrinfo)
  4. IPアドレスとホスト名の両方を使って、接続元ホストの検証をする第17回 MySQLのユーザー管理について[その1]の2ページ目を参照)
  5. 検証に成功した場合、これ以降の「接続元ホスト」はIPアドレスまたはホスト名の「検証に成功したどちらか一方」を利用する
  6. ユーザー名、パスワードなどの認証に進む

名前解決が無効skip-name-resolveオプションが有効)な場合、上記1、2、3のフェーズがスキップされ、4で検証される対象はIPアドレスのみとなります。

--skip-name-resolveオプションはよく「DNSによる名前解決を無効化する」と説明されますが、実際に利用しているのはgetnameinfogetaddrinfoであるため、設定によって/etc/hostsなどDNS以外の名前解決も試みます(しかし、大半はやはりDNSによる名前解決になるでしょう⁠⁠。

DNSの逆引き、正引き設定が適切にされていない場合、⁠MySQLに接続する際に時間がかかる、--skip-name-resolveを設定したら速くなった」というのはこのためです。なお、このオプションはクライアントの名前解決の動作には影響を及ぼしません。サーバに--skip-name-resolveが設定されていようといまいと、mysql -hmysql-hostnameとコマンドラインから名前を指定することは可能です(もちろん、クライアント側のOSでその名前が解決できる必要があります⁠⁠。

名前解決を利用するメリット

MySQLの名前解決を有効にしておくメリットが享受できるのは、DNSの設定(あるいは、/etc/hostsなどその他の名前解決手段)が適切にされている場合のみです。そうでない場合はメリットを受けられないだけでなく、デメリットばかりが現れてくるため、おとなしく--skip-name-resolveの設定をした方が良いでしょう。

名前解決が適切に設定されている場合、以下の2点のメリットを得ることができます。

ホスト名ワイルドカードの運用がしやすくなる

第21回 MySQLのユーザー管理について[その3] で説明した通り、MySQLのアカウント認証においてはホスト名に "%" ワイルドカードを利用することができます。

たとえばIPアドレス172.17.0.2、172.17.0.3、172.17.1.2からのアクセスのみを許可したい場合、mysql.userテーブルに記録されている情報は以下の通りであるべきです。

mysql> SELECT user, host FROM mysql.user WHERE user = 'myuser';
+--------+------------+
| user   | host       |
+--------+------------+
| myuser | 172.17.0.2 |
| myuser | 172.17.0.3 |
| myuser | 172.17.1.2 |
+--------+------------+
3 rows in set (0.00 sec)

172.17.0.2、172.17.0.3をまとめて"172.17.0.%"(さらには、3アカウントをまとめて"172.17.%")と設定することもできますが、その場合、意図しない172.17.0.11からのアクセスを認証で遮断することはできません。別途ファイアウォールの用意や、⁠172.17.0.0/24 セグメントにその他のサーバは存在しない」ことを保証する必要があります。

かといって、おそらく同じ権限を割り当てるであろうユーザーを、接続元を増やすたびに作成するのは、非効率なこともあるでしょう(特に、負荷に応じて動的にアプリケーションサーバを増減させている場合など⁠⁠。そのような場合にDNSや/etc/hostsを利用して名前解決をさせることで、ユーザー管理をシンプルにすることができる場合があります。

mysql> SELECT user, host FROM mysql.user WHERE user = 'myuser';
+--------+--------------------+
| user   | host               |
+--------+--------------------+
| myuser | myapp%.localdomain |
+--------+--------------------+
1 row in set (0.01 sec)

$ vim /etc/hosts
..
172.17.0.2 myapp2.localdomain
172.17.0.3 myapp3.localdomain
172.17.1.2 myapp4.localdomain

$ sudo service mysqld restart

この設定をしたMySQLサーバに対して172.17.0.2からアクセスすると、以下のようになります。

mysql> SELECT current_user();
+---------------------------+
| current_user()            |
+---------------------------+
| myuser@myapp%.localdomain |
+---------------------------+
1 row in set (0.00 sec)

mysql> SHOW PROCESSLIST;
+----+--------+--------------------------+------+---------+------+----------+------------------+
| Id | User   | Host                     | db   | Command | Time | State    | Info             |
+----+--------+--------------------------+------+---------+------+----------+------------------+
|  5 | myuser | myapp2.localdomain:53164 | NULL | Query   |    0 | starting | SHOW PROCESSLIST |
+----+--------+--------------------------+------+---------+------+----------+------------------+
1 row in set (0.00 sec)

名前解決を設定していない172.17.0.11からは当然アクセスできません。

$ mysql -h172.17.0.1 -umyuser -p
Enter password:
ERROR 1130 (HY000): Host '172.17.0.11' is not allowed to connect to this MySQL server

/etc/hostsなどで172.17.0.11を"myapp10.localdomain"に紐づけてやることで、"myapp%.localdomain"にマッチするようになるため、172.17.0.11からもアクセスが可能になります。

ただし、名前解決のための/etc/hostsの読み込みはMySQLの起動時にしか行われないため、/etc/hostsの運用では毎回再起動が必要になってしまいます。名前解決を利用したアカウント運用は、既に逆引き用DNSが設置されていて自由に変更ができる環境でなければメリットを得ることは難しいでしょう。

名前解決の手段が適切にされていないアクセス元からの接続試行をエラーログに出力することができる

--skip-name-resolveが有効になっていない環境では、エラーログに以下のようなワーニングが出力されることがあります。

2016-09-05T06:36:30.324215Z 3 [Warning] IP address '172.17.0.11' could not be resolved: Name or service not known

これは冒頭で説明したステップの2. ⁠載っていない場合)IPアドレスからホスト名に逆引きをかける(getnameinfo⁠⁠ に失敗した場合に出力されるワーニングです。実際にそのホストからの接続が認証されたのかされていないのかは関係ありませんmysql.userテーブルにIPアドレス形式でアカウントが登録してあれば、このワーニングの有無に関わらず認証が行われます⁠⁠。逆引きがきちんとメンテナンスされている環境であれば、このワーニングの多発から不正なアクセスを発見できるかも知れませんが、そうでない場合はあっという間にこのワーニングがエラーログを埋め尽くしてしまうでしょう。

まとめ

skip-name-resolveオプションはMySQLサーバ内の名前解決を無効化します。たまに聞く誤解ですが、このオプションはクライアントの名前解決動作には影響を及ぼしません。

名前解決を有効にしておくことで得られるメリットも多少ありますが、そのためにはあらかじめ名前解決のための基盤を整備しておく必要があります。このあたりに自信がない場合は、--skip-name-resolveで名前解決を無効化しておく方が定石です。

おすすめ記事

記事・ニュース一覧