ポートフォワーディングがないと生きていけない・・・冬。

---
## はじめに
はじめまして！今年もアドカレの季節がやってきたため参加させていただきます。
1年経つのがあっという間すぎる、というセリフをここ10年ほど言っていますが今年も良い年でした🍺

3月から参画しました案件では様々な役割を担当しまして、バックフロント開発・不具合対応・サブリーダー・データメンテナンスなどを経験し大変なこともありましたが、恵まれたメンバーに囲まれとても充実した経験ができました。現在はデータメンテナンスを担当しており、割と複雑なデータの整合性チェックやそこから派生するソースの修正・データ修正対応などを行なっています。

## 毎度のEC2接続が手間・・

aws EC2にある踏み台サーバーからDEV以降のDB（RDS）にアクセスし、セッションマネージャーを使ってブラウザからデータ確認やクエリ実行をしますが、毎度その接続をすることが非常に面倒です。実行結果をコピーすると+---+---+のような区切りもまざってしまうし、エクセルなどにデータを貼り付けると体裁を整えるまでも非常に大変・・別で調べ物をしているとセッション切れしてしまうため、新たに接続し直さなければならないと手間になります。

DBクライアントツールはDBeaverを使用していますが、ポートフォワーディングを使えばローカルからDBにアクセスでき、クライアントツールの有り難き機能も使えて業務がかなり効率化されるため、使わない手はないです。改めてこの仕組みについてまとめてみました。
今回の記事はどうしても文字の説明が多くなってしまいます。ご了承ください🙇‍♂️

## ポートフォワーディングとは？
> ポートフォワーディング（port forwarding）とは、IPネットワーク上のある機器が、自らのIPアドレスのTCPやUDPの特定のポート番号への通信を、別のアドレスの特定のポートへ自動的に転送すること。また、ネットワーク機器などの持つそのような機能。

> ポートフォワーディングを設定されたポートは、対応付けられた別のアドレス・ポートの窓口として機能し、外部との間で送受信されるパケットはすべて自動的に転送される。SSHの機能を用いて外部の機器との間で暗号化された通信経路を用意することを特にSSHポートフォワーディングという。

> ポートフォワーディングはインターネットとLAN（構内ネットワーク）の境界にあるルータやゲートウェイが、LAN側のアドレスしか持たない内部のコンピュータの特定のポートへ外部から着信できるようにするために用いられることが多い。これにより、LAN側のコンピュータにサーバ機能を立ち上げて外部から接続することができるようになる。

> 引用元: [ポートフォワーディング 【port forwarding】 ポート転送](https://e-words.jp/w/%E3%83%9D%E3%83%BC%E3%83%88%E3%83%95%E3%82%A9%E3%83%AF%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0.html) - 「IT用語辞典 e-Words」

要約すると、IPネットワーク上のある機器（ローカルPC）が、特定のポート番号への通信（ローカルで設定したもの）を、別のアドレスの特定のポート（EC2）へ自動的に転送すること、となります。ローカルからあるポートへアクセスするだけでEC2へ転送してくれるので、プライベートネットワークに隔離されているようなサーバにもローカルのターミナルなどから簡単にEC2内にアクセスできます。リモートデスクトップやVPNでもこの仕組みが使われていたりしますね。

- 流れ
```
[ローカルPC localhost:3306] <---(SSHトンネル)--> [EC2 localhost:3306]
```
1. SSHを使って、ローカルPCとEC2の間に暗号化された通信経路（トンネル）を作成する
1. ローカルPCの特定のポート（例: 3306）に送られた通信を、EC2インスタンス内のDBサーバのポート（例: 3306）に転送する設定を行う

この設定により、ローカルPCで「localhost:3306」に接続すれば、SSHを通じてEC2のデータベースに安全にアクセスできる仕組みが完成します。

## ポートフォワーディングの種類
ポートフォワーディングには3種類あり、基本的に各コマンドにオプションを付けます。
- L..ローカル
- R..リバース
- D..ダイナミック

### ローカルフォワード (Local Forwarding)

ローカルマシンのとあるポートを経由し、リモートマシンのとあるポートに接続を転送する設定です。こちらが今回のローカルからEC2へ接続する例に当たります。リモートマシンやサーバー上のDBなどにSSHを用いてローカルマシンから安全にアクセスできます。

```
ssh -L 8080:localhost:80 user@example.com
```
ブラウザで http://localhost:8080 にアクセスすると、リモートサーバーの localhost:80 の内容を取得できます。

### リバースフォワード (Reverse Forwarding)

リモートマシンのとあるポートを、ローカルマシンのとあるポートへ転送する設定です。名前の通り、先ほどのローカルフォワードの逆の通信ですね。閉じられたローカルネットワーク内のリソースを外部からアクセス可能にし、リモートマシンのポートに接続されたデータがSSHを通じてローカルマシンに転送されます。

```
ssh -R 9090:localhost:8080 user@example.com
```
リモートマシンで http://localhost:9090 にアクセスすると、ローカルマシンの localhost:8080 に接続できます。

### ダイナミックフォワード (Dynamic Forwarding)

概要
SOCKSプロキシ（クライアントの通信を中継するプロキシサーバの一種）として機能し、トラフィックを動的に転送する設定。特定のポートやアドレスを指定せず、プロキシサーバーを介して柔軟に接続を転送する仕組みです。

用途
セキュアなプロキシサーバーとして利用し、外部ネットワークを安全に閲覧する。
VPNのような使い方で、複数のリモートサーバーにアクセスする。

```
ssh -D 1080 user@example.com
```
アプリケーション（例：Webブラウザ）でSOCKSプロキシをlocalhost:1080に設定すると、SSH経由で任意のリモートアドレスにアクセスできます。

> 引用元: ssh接続のポートフォワーディングは3種類ある！](https://tech-lab.sios.jp/archives/37377) - 「SIOS Tech.Lab」

## aws環境でのポートフォワーディング設定手順

以下の設定でポートフォワーディングの準備ができます。

- 手順
1. awsのセキュリティ認証情報でアクセスキーを作成する。
（AWS CLIがローカル環境にない場合はインストールする）
1. .aws/credentialsにアクセスキーなどの情報を記載する。
1. pemファイルを任意のディレクトリに置き、権限を変更する。
1. .ssh/configにProxyCommandを記載する。
1. ssh インスタンス名でコマンド実行する。

---

1 awsのセキュリティ認証情報でアクセスキーを作成する。
aws内コンソールでユーザーを選択し、「セキュリティ認証情報」タブからでアクセスキーを作成します。作成するとアクセスキーIDとシークレットキーが発行されるので、これを控えます。

2 .aws/credentialsにアクセスキーなどの情報を記載する。
1 で控えた情報を使い、AWS CLIインストール時に作成されるユーザー配下、.aws/credentialsに以下の内容を記述します。
```
[preferable-name]←任意の名前で良い
aws_access_key_id = <アクセスキーID>
aws_secret_access_key = <シークレットキー>
```
3 pemファイルを任意のディレクトリに置き、権限を変更する。

pemファイルはPJの管理者から渡されると思いますが、こちらをユーザーディレクトリ配下のどこかに置きます。私は.sshディレクトリ内に置いていますが、権限をオーナーのみが読み取り可能とするために、chmod 400を実行します。
```
chmod 400 ~/.ssh/<key-file>.pem
```
4 .ssh/configにProxyCommandを記載する。

ここが肝で、ProxyCommandを設定することによってポートフォワードの開始コマンド実行時のオプション指定などが不要になります。この設定でローカルマシンの3306をリモートのRDSクラスターの3306ポートにトンネルします。ssm --profileの後には.aws/credentialsに2で定義した文字列（preferable-name）を設定します。

- SSM接続
コマンド途中にssmとありますが、これはAWS Systems Manager (SSM) を利用して、AWSリソースにリモート接続する方法
- AWS-StartPortForwardingSessionToRemoteHost
ssmセッションで使用されるドキュメントの1つで、ポートフォワーディングを設定してくれるもの
```
Host ec2-instance
    ProxyCommand /usr/local/bin/aws ssm --profile preferable-name start-session --target %h --document-name AWS-StartPortForwardingSessionToRemoteHost --parameters "{\"host\":[\"dns.cluster-xxxxxxx.ap-northeast-1.rds.amazonaws.com\"],\"portNumber\":[\"3306\"],\"localPortNumber\":[\"3306\"]}"
    HostName <ターゲットEC2のIPアドレス、FQDN、またはエンドポイント>
    IdentityFile ~/.ssh/<key-file>.pem
    User ec2-user
```
5 ssh インスタンス名でコマンド実行する。

これで設定ができたので、コマンド実行をします。
```
ssh ec2-instance
```
このコマンドを実行しながらクライアントツールでも3306ポートとして接続設定すれば、簡単にEC2環境のDBへアクセスができるようになります。セッションの時間などはawsのSSMセッションの設定で変更することができますが、デフォルトは45分となっているようです。

## まとめ
ポートフォワーディング設定をすることによって作業の効率化が図れました。繰り返す手間な作業は一度手間をかけて効率化してしまえば総合的に時間の節約にもなります。
文字が多い記事となってしまいましたがお付き合いありがとうございました。
皆様良いお年を！🏃