使う時だけEC2インスタンスを起動し、SSH接続元にのみポート(443)を開放する

# 要約
　SSH接続時にEC2インスタンスを起動し、SSH接続が無ければEC2インスタンスを停止する。
併せて、SSHクライアント側に対してポート(この記事の例としてhttps/443)を開放/閉鎖する。
その結果、利用料の最適化とセキュリティ対策の強化ができる。
　この記事では、Systems Manager のノード管理サービス「セッションマネージャー」機能による実装を述べている。但し、AWSについてベースの知識や経験があり独力で設定ができる方への気付きを指向したものである。

# 背景
　必要時に直ぐに使えるように開発用サーバー(EC2インスタンス)は、常時起動するか、あるいは、定時で起動/停止する運用が見受けられる。開発途中のプログラムを稼働させるのだから、その前提でセキュリティを適切に設定する必要がある。しかし、デバッグ等で試行錯誤している状況が想定され、セキュリティを適切に設定することは事実上は困難である。また、開発用サーバーでプログラムを稼働させる実際の時間は、その起動時間よりも遥かに少ないことも多い。
　この記事は、Systems Manager のノード管理サービス「セッションマネージャー」機能（以降、SSMと呼称)を使ってSSH接続時にEC2インスタンスを起動する仕組みとSSH接続が無い時に停止する仕組みの実装を述べている。
　なお、Step by Step 手順や扱うポート変更など更に詳しい内容が必要とするならば連絡ください。

# 1. IAM準備
## ポリシーを作成
　SSMの利用とEC2インスタンス操作のため、必要な許可を設定した次のポリシー(例:ondemand-ssm-policy)を作成する。ここでREGIONとOWNERは自身の環境に合わせて書き換える必要がある。例えば、REGIONはap-northeast-1、OWNERは123456789012の様な文字列である。
[ondemand-ssm-policy](https://github.com/yoshiylife/ondemand-aws/blob/de3df357a02ccb7c643c1a4a4ae6e10a32c32a99/ondemand-ssm-policy)

## ユーザーを作成
　今回の仕組みを実装するスクリプトを実行するため、先のポリシー(ondemand-ssm-policy)を適用したユーザー(例:ondemand-ssm-user)を作成する。また、スクリプトで使用するセキュリティ認証情報としてアクセスキーを生成する。なお、AWS Single Sign-Onの利用も考えられるが本記事では対応していない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108405/173d9e10-85a7-8ffe-ffc3-be67274dc8f3.png)

## ロールを作成
　SSMを経由したSSH接続を可能にするため、EC2インスタンスに適用するロール(例:ondemand-ssm-role)をAmazonSSMManagedInstanceCoreのみをアタッチし作成する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108405/fac0a6a6-df61-c652-f3f5-4e84187d32a7.png)

# 2. クライアント側設定(ubuntu on Windows10 Pro)
　Windows10 ProのubuntuからSSH接続する際の設定について記載する。
## AWS Command Line Interface (awscli)のインストールと設定
　次のWebページを参照しawscliをインストールする。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

　インストール後、aws configureを実行しセキュリティ認証方法を設定する。以下に設定の様子を示す。なお、AWS Access Key ID/AWS Secret Access Keyは、アクセスキーの生成で得られる文字列である。
~~~
$ aws configure
AWS Access Key ID: ****************ABCD
AWS Secret Access Key: ****************WXYZ
Default region name: ap-northeast-1
Default output format: json
$
~~~

## Session Manager プラグインをインストール
　次のWebページを参照しSession Manager プラグインをインストールする。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html

## SSH接続時にEC2インスタンス起動の設定
　次のスクリプトondemand-connect.shをダウンロードし、.ssh/configを設定する。なお、インスタンスIDは後述する接続先サーバーを特定するもので、ondemand-test.pemはキーペアの例である。
[ondemand-connect.sh](https://github.com/yoshiylife/ondemand-aws/blob/de3df357a02ccb7c643c1a4a4ae6e10a32c32a99/ondemand-connect.sh)

.ssh/config設定例
~~~
Host    test
HostName        インスタンスID
IdentityFile ~/.ssh/ondemand-test.pem
User    ec2-user
ProxyCommand bash ~/ondemand-connect.sh %h %p
StrictHostKeyChecking no
ForwardX11 yes
~~~

# 3. EC2インスタンス作成
## セキュリティグループ
　開放/閉鎖するポートを制御するために、セキュリティグループ(例:ondemand-ホスト名-sg)を作成する。SSM経由の接続を可能にするため、アウトバンドルールにhttps(443)で送信先は全て許可のルールのみを追加する。VPCルーティングを使って厳密に絞り込むことが考えられるが本記事では対応していない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108405/9f5c2f8c-9853-2bf7-0603-b20d7d1dce4c.png)

## EC2インスタンス起動(作成)
　次のパラメータシートでECインスタンスを起動する。
<table>
<caption>EC2インスタンス起動時パラメータ</caption>
<tr><td>項目</td><td>内容</td><td>説明</td></tr>
<tr><td>名前(NAME)</td><td>ホスト名</td><td>本記事ではtestとしている</td></tr>
<tr><td>アプリケーションおよび OS イメージ (Amazon マシンイメージ)</td><td>Amazon Linux 2023 AMI</td><td>本記事の説明で使用</td></tr>
<tr><td>セキュリティグループ</td><td>ondemand-ホスト名-sg</td><td>EC2インスタンス毎に設定</td></tr>
<tr><td>IAMロール</td><td>ondemand-ssm-role</td><td>－</td></tr>
<tr><td>キーペア(ログイン)</td><td>ondemand-test</td><td>本記事ので例</td>
<tr><td>アクセス可能なメタデータ</td><td>有効</td><td>起動や停止の際にスクリプトから参照するため</td></tr>
<tr><td>メタデータのバージョン</td><td>V1およびV2(トークンはオプション)</td><td>－</td></tr>
<tr><td>メタデータのタグを許可</td><td>有効化</td><td>タグを使って操作する対象のセキュリティグループを特定するため</td></tr>
</table>

# 4. サーバー側設定
　Amazon Linux 2023 AMIを想定する設定を記載する。なお、EC2インスタンスには次のコマンドによりSSM経由で接続できる。
~~~
aws ssm start-session --target インスタンスID
~~~

## タイムゾーン設定
　次のWebページを参照しタイムゾーンを設定する。本記事とは直接の関係はないが、設定すると動作の確認に都合が良い。

https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/set-time.html#change_time_zone

## awscliのインストールと設定
　プリインストールの有無を次のコマンドで確認する。
~~~
aws --version
~~~

インストールされていなければ、下記のWebページを参照しインストールする。

https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

　インストール後、aws configureを実行しセキュリティ認証方法を設定する。以下に設定の様子を示す。なお、AWS Access Key ID/AWS Secret Access Keyは、アクセスキーの生成で得られる文字列である。
~~~
$ aws configure
AWS Access Key ID: ****************ABCD
AWS Secret Access Key: ****************WXYZ
Default region name: ap-northeast-1
Default output format: json
$
~~~

## SSM Agentをインストール
　プリインストールの有無を次のコマンドで確認する。
~~~
sudo systemctl status amazon-ssm-agent
~~~

インストールされていなければ、下記のWebページを参照しインストールする。

https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/agent-install-al2.html

## cronのインストールと設定
　SSH接続の有無を定期的に監視するため、次のコマンドでインストールする。
~~~
yum install -y cronie
~~~
　次のスクリプトondemand-shutdown.shをダウンロードし、SSH接続が無い場合にシャットダウンを実行するようにcronを設定する。
[ondemand-connect.sh](https://github.com/yoshiylife/ondemand-aws/blob/de3df357a02ccb7c643c1a4a4ae6e10a32c32a99/ondemand-connect.sh)

　次の例は、10分間隔でSSH接続の有無をチェックする設定である。なお、ondemand-shutdown.shの引数1800は起動直後の30分はシャットダウンを抑止する指定である。
~~~
*/10 * * * * /root/ondemand-shutdown.sh 1800
~~~

# 5. 実行例
~~~
[18:56:39]$ ssh test
ec2 describe-security-groups
ec2 describe-instance-status
start-instances
ec2 describe-security-group-rules
Wait a while for the instance ok...
wait instance-status-ok
Warning: No xauth data; using fake authentication data for X11 forwarding.
X11 forwarding request failed on channel 0
Last login: Mon Jun 19 13:47:30 2023 from localhost

       __|  __|_  )
       _|  (     /   Amazon Linux 2 AMI
      ___|\___|___|

https://aws.amazon.com/amazon-linux-2/
33 package(s) needed for security, out of 51 available
Run "sudo yum update" to apply all updates.
[ec2-user ~]$ 
~~~