【python】SSHトンネル経由でMySQL接続する方法


SSHトンネル経由でMySQL接続する方法を紹介したいと思います。
例えばAWSを使用していて、VPC内にあるMySQLへアクセスするには一度踏み台サーバー経由しないと行けず、ローカル環境から直接出来ないですよね。こういったネットワーク環境構成は多いのではないかと思いますが、ローカル環境から直接MySQLに接続したい場面もあります。

そんな時にsshtunnelというライブラリで実現することが出来るんですが、SSHポートフォワーディングを利用して、処理を実行しています。簡単にSSHポートフォワーディングについて説明したいと思います。

SSHポートフォワーディングとは

クライアントのポートを、直接アクセス出来ないサーバーのポートに転送してくれる仕組みのことです。
コードを実行する前にSSHコマンドを利用して、ローカルからリモートサーバ先にあるHTTPサーバやMySQLサーバにアクセスすると、コードをより理解出来ると思います。

例えば、リモートサーバのIPアドレスが「10.1.1.1」だったとします。通常のSSH接続であれば、
ssh [ユーザ名]@10.1.1.1
となりますが、ポートフォワーディングをする場合、オプション「L」を付与します。
SSH -L ローカルポート番号:リモートホストアドレス:ホストポート番号

リモートサーバ「10.1.1.1」のローカルホストにあるポート「3306」の「MySQLサーバ」にポートフォーディングする場合は、次のようになります。
SSH -L 10022:127.0.0.1:3306 [ユーザ名]@10.1.1.1

ローカルポート番号は自由に指定することが出来ますが、MAMPやDockerなどで動かしているポートと競合しないように指定してください。ターミナルの窓を二つ起動し、片方で上記コマンドを実行した後に、ローカルからリモートサーバ先のMySQLに接続できることを確かめてみてください。
mysql -h 127.0.0.1:10022 -u root -p

実行コード

#! /usr/env/bin python
# coding: UTF-8

import pymysql
import sshtunnel

with sshtunnel.open_tunnel(
    ("111.111.111.11", 22), // (踏み台サーバのIPアドレス, SSHポート)
    ssh_username="root",
    ssh_pkey="~/.ssh/ida_rsa", // 秘密鍵認証の場合は秘密鍵のパスを記述
    remote_bind_address=("127.0.0.1", 3306), // MySQLが踏み台サーバのローカルにある場合
    local_bind_address=('0.0.0.0', 10022) 
) as tunnel:
        connection = pymysql.connect(host="127.0.0.1",
                                user="hoge",
                                password="hogehoge",
                                db="hogedb",
                                port=10022)

SSHトンネル経由でMySQL接続することが出来ます。

図解


恥ずかしいことに最初ポストフォーディングがあまり理解できておらず、remote_bind_addressとlocal_bind_addressの値を設定するか分からなかったのですが、図解と実際にSSHコマンドで実行することで何を指定すべきかが分かりました。

Pythonコードを利用して、SSHトンネル経由でMySQL接続する際につまずいてしまっている方がいましたら、上記試してみてください。