3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

秘密鍵を使ったSSHでPDO接続

Last updated at Posted at 2019-07-23

はじめに

業務で踏み台経由でDBへ接続する必要があった時やったこと。
PDOはSSH接続する方法はないっぽいので、SSHトンネルをバックグランドで実行しといて、
それ宛にPDOで接続する。

バックグランド実行の方法はこちら

環境

[クライアント] ---- [ 踏み台サーバー] ---- [データベース]
・Mac         ・ユーザー       ・アクセスは踏み台からのみ許可
・PHP        ・パスワード
           ・秘密鍵

#コード

バックグラウンドでSSHトンネリングの実行

-N 指定してリモートでコマンド実行できないようにしています。
停止のときに使うため、変数に格納しています。

php
$cmd = "ssh -f -N -L 13306:dbhost:3306 sshuser@sshhost -i key/id_rsa";
exec($cmd);
[クライラント] -> [このトンネルへ13306で接続] -> [sshuser@sshhostとしてデータベースの3306へ転送] -> [データベース]

PDO接続

SSHトンネリングを実行した状態で。

php
//ローカルの13306へ向けて
$dsn = 'mysql:dbname=db;host=127.0.0.1;port=13306';
$user = 'root';
$password = 'root';

try {
    $dbh = new PDO($dsn, $user, $password);
    echo "接続成功\n";
} catch (PDOException $e) {
    echo "接続失敗: " . $e->getMessage() . "\n";
    exit();
}

SSHトンネリングの停止

php
//開始時に使ったコマンドを元に調べる
$_cmd = "ps aux | grep '[0-9] ".$cmd."' | awk '{print $2}'";
exec( $_cmd ,$output ,$return_var );

//$ouput[0]にPID入っているのでkill
exec('kill '.$output[0]);

実装

DB設定やらポート設定はかくじで。

SSHTunneling.php
class SSHTunneling{

    private static $pids = array();
    private static $cmd;

    public static function start(){
        self::$cmd = 'ssh -f -N -L '.$tunnel_port.':'.DBConfig::$host_name.':'.DBConfig::$port.' '.$ssh_user.'@'.$ssh_host.' -i '.$private_key;
        echo "SSHトンネリングを開始します。".PHP_EOL;
        exec( self::$cmd ,$output ,$return_var );
        if( $return_var != 0) throw new Exception( $output[0] );
        self::set_pid();
    }

    private function set_pid(){
        $_cmd = "ps aux | grep '[0-9] ".self::$cmd."' | awk '{print $2}'";
        exec( $_cmd ,$outputs ,$return_var );
        if( $return_var != 0) throw new Exception( $outputs[0] );
        foreach ((array)$outputs as $output) {
            self::$pids[] = $output;
        }
    }

    public static function stop(){
        echo "SSHトンネリングを終了します".PHP_EOL;
        foreach (self::$pids as $pid) {
            $_cmd = 'kill '.$pid;
            exec( $_cmd ,$output ,$return_var );
            if( $return_var != 0) throw new Exception( $output[0] );
        }
    }
}
php
$dsn = 'mysql:dbname=db;host=127.0.0.1;port='.$tunnel_port;
$db_user = 'root';
$db_password = 'root';

try {
    SSHTunneling::start();
    $dbh = new PDO($dsn, $db_user , $db_password);
    echo "接続成功\n";
} catch (PDOException $e) {
    echo "接続失敗: " . $e->getMessage() . "\n";
}finally{
    SSHTunneling::stop();
    exit;
}
3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?