[AWS]踏み台不要、キーペア登録不要、ポート開放不要のSSH接続環境を作る

# 概要

EC2インスタンスにSSHでログインする。
接続先のインスタンスはプライベートサブネット上に立っている前提。

インスタンスからSessionManagerへの接続はVPCエンドポイントを経由する。
クライアントは、SessionManagerのシェルアクセスではなく、普通のSSHコマンドを使う。

インスタンスにキーペアは登録しない。
接続時にEC2 Instance Connectを使って一時的に登録する。
キーペアは接続ごとに生成/破棄する。

構成を図にするとこんな感じになると思う。

![session-manager.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379/8d155715-4efc-eade-cb04-489133d5d860.png)

## メリット

- **キーペアの管理が不要**
秘密鍵を管理する必要がなくなる。
公開鍵の登録も不要になるため、仮に秘密鍵が漏れてもログインできない。

- **22番ポートの開放が不要**
インバウンドの接続がなくなるので、22番ポートを開ける必要がなくなる。

- **バッションサーバーが不要**
インターネットに不要な口を開ける必要がなくなる。

- **IAMで接続制御ができる**
EC2 Instance ConnectのAPIはIAMで制御できる。

- **CloudTrailで接続の監査ができる**
試してないがEC2 Instance Connectのリクエストなどの監査ができる。

- **シェルアクセスより軽快(な気がする)**
SSM Agentは通信に専念しているので負荷が低そう。
シェルアクセスより動作が軽いんじゃないかと思う。

## デメリット

- **アクセスキーの管理**
IAMで制御するのでアクセスキーの管理は相変わらず重要。
とはいえ、秘密鍵を `~/.ssh` に置きっぱなしにしているよりは安全じゃないかと思う。
今はAWS CLIで自動的にAssumeRoleするような設定も簡単にできるので。

- **準備が面倒**
AWS上の設定や、ローカルPCでも色々と設定しないといけないので面倒。
うまくやればCloudFormationで構築できるかもしれない。

- **VPCエンドポイントが高い**
正直高すぎるんじゃないかと思う。
たぶん、できて当然と思っている機能に金を払わされてるからなんだろう。

- **結構すぐ切れる**
ちょっと放っておくとすぐ切れる。使ってる時に切断されることはない。
何かいい方法があるかもしれないけど、まだ見つけられていない・・・

# 準備

面倒な準備をしていく。

## AWS

### VPCエンドポイント

プライベートサブネット内のインスタンスにSessionManagerで接続するには、NATやVPCエンドポイントの設定が必要。
VPCエンドポイントは各サブネットごとに設定する必要がある。

[ここ](https://qiita.com/ryo0301/items/df4ef5a971fa6349ecd0#aws-systems-manager) に書いてある中で `com.amazonaws.ap-northeast-1.ec2` 以外が必要。
ログを出力するならS3のVPCエンドポイントも必要かもしれない。

### セキュリティグループ

SessionManagerで接続するので22番ポートの開放が不要になる。
もし開いている場合は閉じる。

### マネージドインスタンス

マネージドインスタンスとして認識されていないとSessionManagerで接続できない。
EC2インスタンス用のIAMロールに `AmazonSSMManagedInstanceCore` ポリシーをつけること。
`AmazonEC2RoleForSSM` は古い。

認識されているかどうかは、AWSコンソールのSystemsManager＞マネージドインスタンスで確認できる。

### SSM Agent

SessionManagerを使って接続するインスタンスには、SSM Agentがインストールされている必要がある。
StateManagerを使うことでSSM Agentを常に最新の状態に保つことができる。
マネージドインスタンスのページで `Agent auto update` ボタンをクリックするだけ。

この時点でAWSコンソールからシェルアクセスはできるんじゃないかと思う。

### EC2 Instance Connect

キーペア登録不要でログインするために必要。
最新のAmazon Linuxではインストール済み。
`/opt/aws/bin/` 以下に `eic-*` で始まるコマンドがあるはず。
ない場合は [ここ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/Connect-using-EC2-Instance-Connect.html) を参考にしてインストールする。

### IAMロール

SessionManager関連の設定はこちら。
[クイックスタートデフォルト IAM のポリシー Session Manager | AWS Systems Manager ユーザーガイド](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/getting-started-restrict-access-quickstart.html)

EC2 Instance Connect関連の設定はこちら。
[タスク 4: EC2 Instance Connect の IAM アクセス許可を設定する | Amazon EC2
Linuxインスタンス用ユーザーガイド](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instance-connect-set-up.html#ec2-instance-connect-configure-IAM-role)
[Amazon EC2 Instance Connect のアクション、リソース、および条件キー | AWS IAMユーザーガイド](https://docs.aws.amazon.com/IAM/latest/UserGuide/list_amazonec2instanceconnect.html)

## ローカルPC

### Session Manager Plugin

[ここ](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) に書いてある方法に従ってインストールする。
一応 [Homebrewでインストールできるようにしている人](https://github.com/dkanejs/homebrew-aws-session-manager-plugin) も見かけた。使ってないけど。

### ssh

`~/.ssh/config` に `ProxyCommand` の設定を追記する。

```
Host i-* mi-*↲
  ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"↲
```

### EC2 Instance Connect CLI

`mssh` コマンドを使うとキーペアの自動生成などしてくれるらしい。
今は自作のコマンドで同じようなことをやってしまってるのでインストールしてない。
[5年たったらAWS CLIの薄いラッパーコマンドが出来ていた | Qiita](https://qiita.com/ryo0301/items/fd8fc5f7d1e667e5a5c4#start-ssh-session)

# 接続

## 公開鍵の登録

一時的なキーペアを作成し、公開鍵を接続先インスタンスに登録する。

### キーペアの生成

`ssh-keygen` で適当に作成。
たしかRSAじゃないと接続できなかったと思う。

```
$ ssh-keygen -t rsa -b 4096
```

### 公開鍵の登録

```
$ aws ec2-instance-connect send-ssh-public-key \
              --instance-id i-1234567890abcdef0 \
              --instance-os-user ec2-user \
              --availability-zone ap-northeast-1a \
              --ssh-public-key file://path/my-rsa-key.pub
{
    "RequestId": "f31e23d4-1786-4761-8583-bb03de0795c9",
    "Success": true
}
```

## SSH接続

一時的な秘密鍵を使って接続してみる(公開鍵の有効期限は60秒)。

```
$ ssh -vvv -i ~/.ssh/tmp.pem -l ec2-user i-1234567890abcdef0
```

普通のSSH接続なのでポートフォワーディングなどもそのまま出来る。