SSHの小技集(ログインからポートフォワード、Pythonを利用した自動化まで)

はじめに

MacBook Proとモバイル回線で作業をする様な場合に良く利用するSSHの使い方です。また、サーバー側は、awsの利用を想定しています。

設定編

モバイル回線なので、デフォルトの設定だと頻繁に接続が切れます。
そんな時は、~/.ssh/configに以下の設定を記載します。
これで10秒ごとにパケットを流して接続を維持しようとしてくれます。
(勿論、切られることもあるので、そんな時はscreenなりを活用します。)

ServerAliveInterval 10
TCPKeepAlive yes

基本

ログインしたいサーバが、インターネットに公開されている場合は、以下のように単発のコマンドでログインします。
(証明書での認証を想定しています。)

ssh -i ~/.ssh/<i>foo.pem</i> <i>user</i>@<i>hostname</i>

図にすると以下の様になります。

f:id:marmarossa:20191209003936p:plain
SSH_basic

踏み台の先にあるサーバにログインする

ログインして作業したいサーバが踏み台の先にある場合、一旦、踏み台にログインした後、さらに目的のサーバにログインするのは、面倒なことがあります。そういう場合は、以下の様に
~/.ssh/configファイルに記載しておくことで、自動化されます。
具体的には、ssh target_server とコマンドを打つだけで、自動でJUMP_SERVERを経由してtarget_serverに接続されます。

HOST [target_server]
           HostName [IP address or host name (1)]
           User [user name(1)]
           ProxyCommand ssh -W %h:%p JUMP_SERVER
           IdentityFile ~/.ssh/foo.pem

HOST JUMP_SERVER
           HostName [IP address or hostname (2)]
           User [user name(2)]
           IdentityFile ~/.ssh/bar.pem

※target_serverは、自分の覚えやすい名前に変更してください
※[IP address or host name(1)] は、target_serverのものです。
※[IP address or host name(2)]は、踏み台サーバ(jump server)のものです。
※JUMP_SERVERの所は、字面が一致していれば、なんでも良いです。

踏み台だけをパブリックサブネットに置いて、プライベートサブネット内のワーカーにログインするのは、良く利用するパターンなので、上記の設定で2度ログインする手間を省けます。

ポートフォワード

セキュリティを考慮して、データベース(RDS)やElasticSearchは、外部からは直接接続できない様にすることが普通です。勿論、前述の通り、踏み台を経由して、プライベートサブネット内のマシンにログインして、開発をすることも可能です。しかし、効率面を考慮すると、極力ローカルの慣れたエディタを使いたいケースが多いと思います。
そこでオススメなのが、ポートフォワードです。

例えば、以下の様に、データベースとローカルマシンの間にトンネルを作っておくと、データベースへのアクセスを透過的に扱えます。
これで、踏み台をトンネルして、データベースサーバの5439ポートをローカルの5439ポートへバインドします。
(5439は、Redshiftのデフォルトポートです。適宜バックエンドで動作しているDBのポートに置き換えてください)

ssh -N -i ~/.ssh/[踏み台へ接続するための秘密鍵] -L 5439:[データベースサーバのアドレス]:5439 [ユーザ名]@[踏み台のアドレス]

PythonからSSHで踏み台サーバへログインしてプライベート領域のDBへ接続

上記は、トンネリングはあくまで手動で実施することを想定していました。
ただ、全てをプログラムで制御したい場合も往々にして存在します。
特に、AWS lambdaと組み合わせると、ローカルPCのcronに対するクラウドのcronのごとく、一定間隔で様々な処理が実施できて大変便利です。

では、早速Pythonでのやり方を見ていきたいと思います。

前準備

  • 以下のコマンドで、sshtunnelをインストールします。
    • pip install sshtunnel
  • また、DB接続用のライブラリも好みのものをインストールします(例では、psycopg2)。

コードスニペット

上で出てきた踏み台サーバを経由してバックエンドのDBへアクセスするサンプルは以下の通りです。
必要に応じて、wait(スニペットでwaitのコメントを付けている部分)を入れて接続が整うのを待ってください。

from sshtunnel import SSHTunnelForwarder
import psycopg2 as psy2

server = SSHTunnelForwarder(
    (踏み台サーバのアドレス, 22),
    ssh_host_key=None,
    ssh_username=踏み台サーバのユーザ名,
    ssh_password=None,
    ssh_pkey=踏み台サーバのSSH秘密鍵,
    set_keepalive=10.0,
    remote_bind_address=(データベースのアドレス, 5439)
)
server.start()

con = psy2.connect(
    dbname = データベース名,
    user = データベースのユーザ名,
    password = パスワード,
    host = "localhost",
    port=server.local_bind_port,
    async_=True(非同期) or False(同期) 
)

while True : #wait
    state = con.poll()
    time.sleep(1)
    if state == psy2.extensions.POLL_OK:
	break

cur = con.cursor()
cur.execute(任意のSQL文)
con.close()

その他

  • ファイルのやりとりは、上で述べてきたsshコマンドをsftpコマンドに置き換えることで可能です。