EC2に構築したWebシステムでDBにはRDSを使用している環境があります(まぁ、普通ですが)。
この環境でDB内の情報の直接的参照や更新のためにphpMyAdminを使用できるようにしました。
EC2のOSにはUbuntu20.04(コードネーム:Focal)を使用し、Web環境構築にはVirtualminを使用しました。phpMyAdminは独自インストールします。
と、この辺の環境構築方法(Virtualminインストール以降)は以前記事にした「UbuntuにLaravel環境構築」と同じで、最後にphpMyAdminの設定で接続先ホストにRDSを指定する辺りが違うだけだろうと高を括っていたのですが、存外色々と苦労したので、その辺を書きたいと思います。
なお、前述したように「UbuntuにLaravel環境構築」に示した手順におけるphpMyAdminのインストールが済んだ状態からの話になります。
認証エラー
先に書いたように、手順自体は開発環境(Virtualbox上)構築と変わらず、DB(今回はMariaDB)が当該サーバではなく別のサーバ上に存在する点に違いがあるだけなので、その設定を行えば良いと考えました。この辺の設定はphpMyAdminをインストールしたディレクトリ(/usr/share/phpmyadmin)直下に「config.sample.inc.php」が存在するので、これを「config.inc.php」としてコピーし、同ファイル内の
$cfg['Servers'][$i]['host'] = 'localhost';
の「localhost」を対象となるDB搭載サーバの情報に書き換えるというのが一般的な方法です。
DB搭載サーバの識別情報としては、通常はサーバのIPを用いますが、AWS(RDS)ではDBに割り振られたエンドポイントを指定します。
なお、phpMyAdminへのアクセスURLは、まずは基本形の「https://<IPアドレス>/phpmyadmin」とします。
これでアクセスできるはず…と思いきや、「Access denied」になります。ユーザー名・パスワードを確認してみたり、先のhostの設定を確認してみたりしましたが、どちらも問題なさそうです。困りました…
スクリプト言語の良いところは処理内容が直接確認できますし、処理を追加することもできると言うことです。
と言うことで、頑張って処理を追いかけてみることにしました。
まず、最終的にDBにアクセスする直前辺りの処理で情報を採取してみると、なぜかhostが「localhost」のままであることが分かりました。つまり先に更新したhostの情報が反映されていないと言うことです。当然ながら、別の設定ファイルの存在を疑います。
ネットで調べると「/etc/phpmyadmin/config.inc.php」なるファイルの存在が浮上。さらに同ファイル内で「/etc/phpmyadmin/config-db.php」を読み込んでおり、このファイルを更新するのが正解のようです。
ちなみに中身は以下の通り。
<?php
##
## database access settings in php format
## automatically generated from /etc/dbconfig-common/phpmyadmin.conf
## by /usr/sbin/dbconfig-generate-include
##
## by default this file is managed via ucf, so you shouldn't have to
## worry about manual changes being silently discarded. *however*,
## you'll probably also want to edit the configuration file mentioned
## above too.
##
$dbuser='';
$dbpass='';
$basepath='';
$dbname='phpmyadmin';
$dbserver='localhost';
$dbport='3306';
$dbtype='mysql';
上記の「dbserver」を書き換えれば良さそうです。この辺のファイル構成はどうもUbuntu(Debian系)固有っぽいです。
と言うことで同パラメータにDBのエンドポイントを設定し、再度アクセス実行…してみましたが、結果は変わらず。
相変わらずhostは「localhost」のまま。
さらに色々調べたところ、「/etc/phpmyadmin/config.inc.php」内の以下の処理が問題でした。
if (check_file_access('/etc/phpmyadmin/config-db.php')) {
require('/etc/phpmyadmin/config-db.php');
}
まさに先に更新したファイルを読み込んでいる処理ですが、読み込む前に読み込み可能かチェックしています。
ここで使用している「check_file_access」なる関数は同ファイル内で別途定義されている関数で、実質的には対象ファイルに対して「is_readable」を実行している程度の処理です。つまり単純に読み込み権があるかどうかの問題と言うことです。
調べてみると、まずはPHP実行ユーザーの方はVirtualminでの環境構築時に作成したドメイン用のユーザーになっていました。Virtualminではドメインごとに当該環境を管理するユーザーを作成しつつ、そのユーザーのホームディレクトリ配下に当該ドメインの環境を構築します。例えばドメイン名が「abc.def.co.jp」のようなものであった場合、最初のドットまでの文字列(ここでは「abc」)に合わせて新規ユーザー「abc」を作成し、「/home/abc」配下に同ドメイン運用に必要な環境(PHP関連の設定ファイルなども含む)を構築します(ちなみにドキュメントルートは「/home/abc/public_html」になります)。
上記例で言えば「abc」というユーザーがphpMyAdminの実行ユーザーになっていたということです。
仮想ホスト環境においては同一IP配下に複数のドメインを配置する関係上、ドメイン名自体を識別子としてアクセス先を決定します。具体的には「/etc/apache2/sites-available」配下にドメインに対応する設定ファイル(今回の例で言えば「abc.def.co.jp.conf」)が生成され、その先頭には以下のような記述があります。
<VirtualHost IPアドレス:80>
SuexecUserGroup "#1001" "#1001"
ServerName abc.def.co.jp
...
DocumentRoot /home/abc/public_html
...
「ServerName」に当該ドメイン名が設定されていることで、同じIPへのアクセスでもドメイン名がこの設定と一致するものが当該ドメインへのアクセスと判断され、「DocumentRoot」で指定されたドキュメントルート配下のファイルにアクセスできるようになります。この時、PHPの実行ユーザーは「SuexecUserGroup」の設定に準じて決定されます。上記ではID表記になっているので分かりにくいですが、このIDが先のユーザー「abc」を意味している訳です。
さて、上記のようにドメイン名を指定した際の動きははっきりしているのですが、IPアドレスでアクセスした場合はどうなるでしょう?
この辺は私も正確に説明できないところですが、何らかのルールにしたがっていずれかのドメイン環境に紐付けられるようです。
現時点ではドメインは1つしか生成していないため、無条件にそこに紐づけられたと言ったところでしょう。その結果、先に示した設定ファイルの内容に従って実行ユーザーが決定されていた模様です。
なお、phpMyAdmin自体は「/usr/share/phpmyadmin」にインストールされますが、ここへの動線としては「/etc/apache2/conf-available/phpmyadmin.conf」(実はこれ自体はシンボリックリンクで、実体は「/etc/phpmyadmin/apache.conf」)で定義されています。
このファイルの中で
Alias /phpmyadmin /usr/share/phpmyadmin
と設定されているので、「https://<IPアドレス>/phpmyadmin」というアクセスが当該ドメインのドキュメントルート配下の「phpmyadmin」ディレクトリではなく「/usr/share/phpmyadmin」を参照するようになる訳です。
以上から「/etc/phpmyadmin/config.inc.php」へアクセスを行うPHPの実行ユーザーは「abc」であることが分かりましたが、一方で当該ファイルのオーナーとグループは「root」と「www-data」になっており、パーミッションは「0640」です。つまりオーナー「root」か「www-data」グループに属するユーザー以外では当該ファイルが読めないため、同ファイルでの設定内容が有効にならず、デフォルトのhost(localhost)が採用されてしまっていたと言うことです。
独自ドメイン設定
若干話が変わりますが、前述のようにphpMyAdmin環境が仮想ホスト環境におけるいずれかのドメインに紐付けされることを考えると、いっその事phpMyAdmin用の独自ドメインがあっても良いと思えてきました。
そもそも、IP指定でアクセスできるという形はセキュリティ的にも問題ありますので(Apacheのログを見るとphpMyAdminを狙ったアタックの痕跡は良く見られます)。
例えば、Virtualminで新たに「https://hoge.fuga」でアクセスできるような仮想ホストを定義します。この時、ドメイン名は正規に運用しているドメインとは無関係な名称でも問題ありませんし、むしろ正規ドメインやphpMyAdminを連想させる文字列が含まれないものの方が第三者から推測され難いということで良いかもしれません。
若干注意が必要な点としては、IPでアクセスした際に上記「hoge.fuga」の方がアクセスされるようにならないことを保証する必要があります。IPでphpMyAdminにアクセスできてしまってはわざわざ特殊な(推測し難い)ドメイン名を付けた意味がなくなってしまいますので。具体的な方法に関してはGoogle先生に聞いてください。
上記名称で仮想ホスト環境を構築した場合、ユーザー「hoge」、ホームディレクトリ「/home/hoge」、ドキュメントルート「/home/hoge/public_html」が生成されます。この時、「/usr/share/phpmyadmin」が「/home/hoge/public_html」となるようにシンボリックリンクし直すことで、同ドメインへのアクセスでphpMyAdminが起動できるようになります。
上記ができたら「/etc/apache2/conf-available/phpmyadmin.conf」を削除しておきましょう。この設定が残ったままでは「当該サーバ上の何らかのドメイン/phpmyadmin」というパス指定でphpMyAdminにアクセスできる動線が残ってしまいますので。
最後に名前解決ですが、DNSではなくアクセス元PCのhostsで行うようにします。このようにhostsで名前解決するため、ドメイン名は適当な文字列で良い訳です。
上記一連の設定により、対象サーバのIPと「hoge.fuga」を紐付けた名前解決情報を持つhostsが存在する環境からしかphpMyAdminにアクセスできなくなります。
パーミッションの解決
話が発散気味ですが、ここまでの作業で「https://hoge.fuga」でphpMyAdminが起動できるようになっているはずですが、当該ドメインにおけるPHPの実行ユーザー(hoge)に対して設定ファイル「/etc/phpmyadmin/config.inc.php」が読めないと言う状況は変わっていません。
同ファイルのオーナー・グループを変更しても良いですが、他にも類似した事情を持つファイルがあることも考慮して、実行ユーザー(hoge)をグループ「www-data」に加えて対処します。
gpasswd -a hoge www-data
また、「/etc/phpmyadmin/config.inc.php」の設定に関しては、「$dbserver」の変更には触れましたが、「$dbname」に関しても適切に設定しておきます。なお、「$dbname」が設定されていないと当該ファイルでの設定自体が有効にならないため、必ず指定しておく必要があります。
上記設定を行なってApacheを再起動すると、phpMyAdminで期待するDBにアクセスできるようになるはずです。
ただ、「/var/lib/phpmyadmin/tmp/」と言うディレクトリの書き込み件がないので性能に影響が出るっぽい警告メッセージが出るかと思います。
確かに同ディレクトリを確認してみるとオーナー・グループ共に「www-data」でパーミッションは「0755」なので、グループに対する書き込み件がありません。
ここは直接的に当該ディレクトリでグループ「www-data」に対して書き込み権を与えておきます。
ここまで行うことで、「https://hoge.fuga」へのアクセスで目的とするDBの内容を操作可能なphpMyAdminが起動できるようになります。
総括
phpMyAdminが使えるようになりました。phpMyAdmin環境への不正アクセスに関しても名前解決自体が関所となっており、相当にハードルを上げられたはずです。めでたしめでたし。
と言いたいところですが、セキュリティ面でphpMyAdminに対する否定的な意見は聞きますし、ネット上でもそのような情報が見受けられます。PleskなどではDB管理ツールとして普通にphpMyAdminが入っていたりすると思うのですが(最近新しく構築されたPlesk環境を見ていないので、あくまで古い情報かもしれませんが)。
セキュリティ関連の話となると、個人的に安易に結論を出しづらいので難しいところです。
加えて、本記事に書いたようにphpMyAdmin環境を構築すること自体が相応に面倒な作業です。今後もバージョンが変わったり環境が変わったりする中で新たな問題が発生する可能性もありますし。
一方で、普段あまり愛用していませんが「Sequel Pro」というフリーソフトを使用したこともあって、こちらでのアクセスも試してみました。
同ツールは自PC(Mac)で動作し、sshで中継点となる最寄りサーバ(今回の構成ではEC2)にアクセスした上で、その先のDBにアクセスする(この辺の仕組みは不明)という形になっており、当然ながらアクセス設定としてDB名やエンドポイント、EC2のアカウントやpemなど10項目弱程度の設定を行いますが、つまりはその程度の設定を行うだけで目的のDBの操作ができるようになりました。手間で言えば雲泥の差です。
個人的にはphpMyAdminの方が使い慣れていますし、「Sequel Pro」に関しては昨今更新が止まっているとの噂もあり、何を選択するかは悩むところですが、とりあえず選択肢を増やしておいて、環境に合わせて適切な選択肢を選んでいければと思っています。