[PHP,MySQL] sshトンネル奮戦記

2023年8月1日

MySQL PHP 日記

eyecatch セキュリティの高いデータベースにアクセスをする時に、sshトンネルを使うパターンを覚えておくと非常に便利です。 先日お仕事を引き受けた会社さんの案件で、少々構築に苦労したので、つまづきポイントと、構築ポイントなどを解説を踏まえて備忘録しておきます。

どんな時に使うの?

データベース(今回はMySQL)が特定のサーバー(公開用のwebサーバーなど)からしかアクセスできない時に、アクセスできるサーバーを介してデータベースにアクセスをする方法です。 多くの場合、鍵を使って認証を行っていると思うので、ssh の機能を使ってトンネルアクセスという方法を使うことでアクセスできてしまいます。 本番環境だけでなく、開発サーバー環境からのデータベースへのアクセスや、ローカルPC環境、検証サーバーからのデータベースアクセスなど、踏み台サーバーを介して構築することが可能になり、セキュリティも担保されるという仕組みです。

事前確認事項

どんなサーバーからでもアクセスできると言っても、他人のサーバーにはアクセスできませんよ。 ちゃんと鍵を持っているとか、認証パスワードを知っているという事が最低限の条件になります。 なので、認証サーバーへは、普通にsshアクセスできる事が大前提になります。 ということで、以下のコマンドで、アクセスしたいサーバーやローカル端末からのsshアクセスを確認しましょう。 $ ssh -i 鍵ファイル ユーザー@踏み台サーバー

必要な情報

鍵ファイル : ※これがわからない人は、サーバー管理者にお尋ねください。 ユーザー : 踏み台サーバーにログインするログインID(ユーザー名)。 踏み台サーバー : サーバーのドメインまたは、IPアドレスを入力します。

上記以外でのサーバーログイン

普通にUser-ID/Passwordでのログインをする場合は、-iオプション無しでパスワードでログイン出来る事を確認します。 $ ssh ユーザー@踏み台サーバー password > ***

データベースログイン確認

踏み台サーバー側での確認。 上記ログインした状態で、mysqlへのログインを確認します。 # 踏み台サーバー内にmysqlがインストールされている場合。 $ mysql -u localhost -p password > *** # 別サーバーのデータベースにアクセスする場合。 $ mysql -u 別サーバーアドレス -p password > *** ポートは、デフォルトの3306の場合ですが、別のポート番号がセットされている場合は、-Pオプションを追加して、ポートしていをします。

トンネル確認

トンネルは、sshコマンドで行います。

基本コマンドの解説

$ ssh -NL %任意ポート:%踏み台サーバーからアクセスするmysqlアドレス:3306 -i %鍵ファイルのパス %ユーザーアカウント@%踏み台サーバーアドレス %任意ポート : サーバー内で使われていないポートであれば、何でも構いません。(このポートを使ってトンネルを掘ります) %踏み台サーバーからアクセスするmysqlアドレス : 多くの場合、localhostですが、トンネルの場合は、127.0.0.1で行ったほうがいいです。 %鍵ファイルのパス : コマンドを実行している場所からの相対パス(または絶対パス)で、鍵ファイルにアクセスします。 %ユーザーアカウント@%踏み台サーバーアドレス : sshでアクセスしたモノと同じです。

サンプルコマンド

$ ssh -NL 13306:127.0.0.1:3306 -i ~/.ssh/id_rsa.pub user@example.com 上記コマンドを実行すると、ターミナルが固まってしまいます。 control+cで、コマンド実行を停止することができますが、エラーが出ずに固まった状態になれば、成功です。 固まっている間は、トンネルが掘られている状態になり、%任意ポートが踏み台サーバーにアクセスできる状態になっています。

任意ポートの確認

ターミナルが固まってしまった状態で、command+tで、ターミナルタブを別に切り替えて、任意ポートが生きているか確認します。 $ lsof -i:%任意ポート: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ssh 22054 wwwuser 4u IPv6 203099122 0t0 TCP localhost:%任意ポート (LISTEN) ssh 22054 wwwuser 5u IPv4 203099123 0t0 TCP localhost:%任意ポート (LISTEN) 正常に踏み台にトンネルが掘られている場合は、上記のように、IP4とIP6でのポート開通が確認できます。

強制停止する方法

コマンドが、バックグラウンドで動いている場合は、次のコマンドで強制終了させることができます。 $ kill -9 %PID PIDは毎回変わるので、都度確認しながら強制終了させてください。

MySQLアクセス確認

トンネルが開通している状態で、踏み台経由でMySQLにアクセスしてみましょう。 $ mysql -u 127.0.0.1 -P 13306 -p password > *** 上記でmysqlにログインできたら、無事にトンネルアクセスが成功です。 もしこの時点でアクセスできない場合は、エラーコマンド等を確認してください。

エラーポイント

ちなみに、自分の場合、ここで時間を費やしたのは次のようなポイントがあったので、参考のため、掲載しておきます。 【注意ポイント】 mysqlアクセスを、ローカル環境では"localhost"でできるが、トンネルでのアクセスは、"127.0.0.1"でないと、開通しなかった。

PHPを使ったサンプルコード

最後に、この面倒くさい作業をやったのは、phpでの、踏み台サーバー経由でmysqlにアクセスさせたかった為だったんですね。 ということで、上記のアクセスが成功した状態であれば、下記のソースで、データベース内のテーブル一覧が取得できるはずです。 <?php echo '<meta charset="utf-8">'; echo '<h1>Mysql access</h1>'; echo '<pre>'; $port1 = '3306'; $port2 = '13306'; $host = '127.0.0.1'; $user = 'db_user'; $pass = 'password'; $dbname = 'sample_database'; $key = '~/.ssh/id_rsa.pub'; $ssh_ac = 'user@example.com'; /** * sshトンネル */ $cmd = 'ssh -f -g -N -C -L '.$port2.':'.$host.':'.$port1.' -i '.$key.' '.$ssh_ac.' >/dev/null 2>&1'; exec($cmd, $cmd_res, $cmd_ret); var_dump($cmd_res, $cmd_ret); /** * MySQL */ // PDO $dns = "mysql:host={$host};port={$port2};dbname={$dbname};charset=utf8"; $mysql = new PDO($dns, $user, $pass); $sql = 'show databases'; foreach ($mysql->query($sql) as $row) { print_r($row); } $mysql = null; 変数に情報をまとめておいたので、使用する環境に合わせて値を登録すれば、結果が得られるはずです。

解説とポイント

sshトンネルを掘る処理は、実行すると、backgroundモードでポートが残り続けます。 なので、2回目移行の実行は、この機能はエラーで弾かれています。 サーバー側で、ポートを閉じる場合は、上記のkillコマンドまたは、サーバーの再起動で、ポートは開放されます。 バックグラウンドモードは、ssh内のオプションで、セットしているので、オプションの内訳は以下のとおりです。
-g : 他端末から使えるようにする -f : sshをバックグラウンドで実行する -N : SSHトンネリングモードにする -C : 通信データを圧縮する -L : ポートフォワードを利用する
PHPでのSQLアクセスは、PDOを使っていますが、mysqliでもできると思います。 また、php以外でも似たようなシステムコマンド実行処理を書けば、問題なくアクセスできるようになるはずです。

あとがき

今回の方法以外でも、鍵をシステム側の~/.ssh/confignに書き込んでおけば、それぞれのコマンドでの-iオプションは不要になります。 そして、任意コマンドで、トンネルを実行している間のみ、phpでの通信が可能になるなどのセキュリティ設定も可能になるので、環境に応じて独自の設定で行うのがいいでしょう。 データベースのセキュリティ管理は、非常にセンシティブに行う必要もあるので、こうした手間を掛けてでもしっかりと行うことをオススメします。 とりあえず、これで、便利に開発がはかどることができるようになりました。

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。