SSHポートフォワーディングを使ったサーバー間接続

こんにちは。商品開発部Webエンジニア、入社3年目の水之浦と申します。

私は主に弊社のバックヤード業務で利用する社内システムの運用および保守業務を担当しております。今回は社内システム間のデータ連携処理の改修で利用した「SSHオプションを使ったポートフォワーディング」について整理しました。

実現したかったこと

前述の社内システムの改修では、異なるサーバーで起動され、APIで連携する2つのシステムのプログラム変更を行いました。API連携では、システムAからシステムBのバックエンドAPIにリクエストし、システムBからレスポンスとしてデータを返します。

  • 販売管理を支えるシステム (以下、システムAとします。)
  • 現場クラウド for サイボウズOfficeのお客様データを一元管理するシステム (以下、システムBとします)

実現にあたっての制約

開発環境サーバーのファイアウォール

前提

システムAとシステムBはそれぞれ異なる開発サーバーで起動されます。両サーバーは共にDebian環境で動きます。しかし、Debianバージョンアップのタイミングやサービスが稼働する本番サーバー環境の違いから、システムAとシステムBはそれぞれバージョンが異なるDebian環境下で開発されています。
以降、システムAが起動されるサーバーをサーバーA、システムBが起動されるサーバーをサーバーBとします。

制約条件

サービスが起動されるサーバーが異なるため、システムAおよびBのAPI連携にあたり、サーバーAおよびB間で通信を行う必要がありました。しかし、両サーバーはセキュリティ上、SSH接続のみを許可するようにファイアウォールが設定されていました。

開発環境で各システム間のAPI連携を確認するにあたって、このファイアウォール設定という制約をクリアする必要がありました。

実現のために実施したこと

今回のサーバー間の通信方法について、先輩エンジニアに質問したところ、「SSHポートフォワーディング」というヒントをいただきました。ポートフォワーディング(トンネリング)は基礎的な技術ですが、当時の私は「ふむ…なるほど。(分かっていない)」という状況でした。

そこで、先輩エンジニアがまとめてくださっていたドキュメントやオンラインの情報をもとに学習を進め、SSHポートフォワーディングを使ってサーバー間の通信を試みました。

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

SSHポートフォワーディングとは、SSHコネクション上で任意のポートへの通信を特定ポートへ転送する機能です。これはSSHの機能で、sshコマンドにポートを転送するオプションがデフォルトで備わっています。異なるサーバー間でセキュリティやネットワークの設定によって直接アクセスができない場合に利用されます。
代表的な2つのSSHポートフォワーディングをご紹介します。

ローカルポートフォワード

  • クライアント…ユーザーや稼働するソフトウェアから見た、自らのコンピュータまたは端末
  • リモートホスト…ローカルのクライアントから見た、ネットワークで接続する先のコンピュータまたは端末

サーバーを中継して、クライアントのポートをリモートホストのリモートポートに転送します。

ssh -L {port}:{remotehost}:{remoteport} {server}

リモートポートフォワード

  • クライアント…ユーザーや稼働するソフトウェアから見た、自らのコンピュータまたは端末
  • リモートホスト…クライアントから接続するホストから見た、ネットワークで接続する先のコンピュータまたは端末

クライアントを中継して、サーバーのポートをリモートホストのリモートポートに転送します。

ssh -R {port}:{remotehost}:{remoteport} {server}

 

実現した方法

開発環境

ターミナルA / B … Cygwin。
サーバーA / B… SSHデーモンがあり、SSHの接続のみ許可されたサーバー。
SSHクライアント … OpenSSH。
python3

通信の確認

以下の手順でサーバーA / B間の接続を確認しました。

⓪エージェントフォワーディングを行う。

 エージェントフォワーディングによって、複数ホストにSSHをする際に公開鍵認証でsshの認証を代行します。

◆ターミナルBにて①~③を実行

①サーバーBにSSH接続

   ssh サーバーB 

②サーバーBでpythonの簡易サーバーのポート番号を8081に指定して起動。

 なお、サーバーBからサーバーAにsshするため、ジョブをバックグラウンドにします。
 コマンドライン末尾に”&”をつけることで、ジョブをバックグラウンドで実行します。

   python3 -m http.server 8081 &

   Serving HTTP on 0.0.0.0 port 8081 (http://0.0.0.0:8081/)

③サーバーBからサーバーAに対してSSHリモートポートフォワード

   ssh -R 8081:localhost:8081 サーバーA

 この時、各サーバー間の通信は以下のようなイメージになります。

◆ターミナルAにて④と⑤を実行

④サーバーAにSSHログイン

   ssh サーバーA

⑤curlで②のURLにアクセスして接続を確認。

   curl http://0.0.0.0:8081/

結果

ターミナルAにてサーバーAからサーバーBに対して接続を確認できました。
下図はサーバーAにSSHログインしたターミナルAからサーバーBへの接続の確認をした際のイメージ図です。

振り返り

今回学んだポートフォワード、とりわけローカルポートフォワードについては日頃の開発で「おまじない」のように利用していた技術でした。今回の学習と実践を通して基本的な知識を1つ1つ、知的好奇心を持って積み重ねることがスキル向上に重要だと学びました。