ssm経由でVSCodeをリモートSSHで使った話

# コロナ禍で
みなさまリモートワークでお仕事されてる方も多いのではないかと思います。当社も5月末までは原則在宅勤務、それ以降も週2出勤（他在宅）が原則、週1〜週4出勤も選択可能という形態になりました。

## リモートワークとはいえ
実は開発サーバーはクラウド上（AWSとかGCPとかAzureとか）にあるから会社と家とで大きく変わらんよ、なんて人もだいぶ増えてきたのではないでしょうか。当社も開発のかなりの部分をクラウド化しております。

前置き、以上

## bastionサーバ
AWSのVPC上でマイクロサービス構築するとき、bastionサーバーをおいてそれを踏み台にssh tunnelingで開発サーバーにアクセスして開発する、という形がこれまで多かったと思います。bastionサーバーにIP制限を掛けておけば、社外から不正に侵入される可能性は低くなるわけです。

が、在宅リモートワークではこれが仇となります。家から繋いだらIPなんてプロバイダによってマチマチなわけです。もしIP制限解除したら、実は同じマンションにクラッカーがいてクラッキングされた、なんてことになりかねません。
さあ、どうする？？

# ssm
そこで登場するのが AWS Systems Managerです（ssmは Amazon <u>S</u>imple<u>S</u>ystems<u>M</u>anager, もしくは Amazon EC2 <u>S</u>ystem<u>s</u> <u>M</u>anagerの略らしい）。
ssm-agentといわれるagentプログラムを、管理したいサーバーにインストールしておけば、bastionサーバーなし、SSH鍵ペアの管理もなしで対象サーバーにログインできてしまうという代物。対象サーバーのセキュリティグループの22番ポートを開けておく必要もないので、堅牢です。

ただし今回のSSH/SCPトンネリングの話ではSSH接続を行うので鍵ペアは管理しておく必要があります

## ssm のインストール
あちこちに情報は転がっているので、割愛。
公式はこちら
https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-install-ssm-agent.html
とはいえ、Amazon LinuxやAmazon Linux2のAMIにはデフォルトでインストールされるようになっているので、面倒な手続きなどは必要ありません。（古いAMIを利用している場合には手動でインストールが必要です）

## 接続
AWSコンソールのEC2のインスタンスリストで接続したいEC2インスタンスを選んで、「接続」ボタンをクリック → 接続方法：「セッションマネージャー」 → 「接続」ボタンをクリック
そうすると、ブラウザで新規タブが開き、ブラウザ上で仮装ターミナルが開きます。

デフォルトではssm-userというユーザーでログインします。
でも、在宅リモートワークでログインする人がみんなssm-userでサーバーにログインするのは、管理上どう考えてもよろしくない。

## IAM で SSMSessionRunAs タグ設定
ということで、IAMユーザーにSSMSessionRunAsタグでユーザーIDを紐付けしましょう。（要IAM編集権限）
AWSコンソールにログインし、IAMの各ユーザーの設定画面を開き、タグ編集タブで「タグの追加」をクリックして、「キー」に`SSMSessionRunAs`を、「値」にログイン対象のLinuxOSでのユーザーIDを登録します。

## Amazon Systems Manager の設定
次にAWS コンソールのAWS Systems Managerを開きます（もちろんSystems Managerの編集権限が必要です）。左の「インスタンスとノード」に「セッションマネージャー」があるのでクリックします。右の「設定」のタブをクリックして、「編集」ボタンをクリックし、「Linux インスタンスの Run As サポートを有効にする」のチェックを入れます。

これで、IAMユーザーごとに別々のユーザーでSSM管理下のEC2インスタンスにログインできるようになりました。

## SSM接続の制約
ところが、ブラウザ上の仮想ターミナルによるSSM接続には制約が多いです。
まず初期化プロセスが走りません。日頃SSHログインした時に利用しているユーザーコマンド(`bundle`など)が使えません。プロンプトも`$`だけでカレントディレクトリなどがわかりにくいです
また、LANG設定もされていないので、vimなどで日本語ファイルを開くと文字化けします。
これらの制約は下記のコマンドを実行することである程度解消できます。

```bash
source /etc/profile
source ~/.bash_profile
export LANG=ja_JP.UTF-8
```

また、大きな問題としてSCPによるファイルのアップロードができません。
ブラウザ上の仮想ターミナルでvimで新規ファイルを開いてエディタからコピーペースト、などと原始的な方法を取らざるをえないのです。

どうすればいいんだろう。ということで本題。

# Session ManagerでSSH/SCPをトンネリングしてEC2に接続する

### 参考資料
https://qiita.com/hayao_k/items/78b5bfe030ad8a053e93

### 前提
AWS CLIがローカルマシンにインストール済み。
対象サーバーにssm-agentがインストール済み。
### 手順

1. Session Manager Pluginのインストール

    下記を参考にローカルマシンにインストールします

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

2. AWS認証情報の確認
    一旦サーバーにssmでログインします。
    `whoami`コマンドで自分のユーザーであること(ssm-userでないこと)を確認してください。それから次のコマンドを実行してAWSの認証情報を開きます

    ```bash
    cd ~/.aws
    vi credentials
    ```

    ```
    [default]
    aws_access_key_id = AKIA*******
    aws_secret_access_key = ******
    ```
    とあるaccess_key_idとsecret_access_keyの両方を安全な場所にメモします。
    対象サーバーからはログアウトします

3. AWS認証情報をローカルマシンに設定する
    ローカルマシンでターミナル（コマンドプロンプト）を立ち上げ、

    ```bash
    aws configure --profile hogefuga
    ```
    を実行します。(hogefugaは適当なプロファイル名)
    idとsecretを聞かれるので2.でメモした値を入力します

4. SSHの設定
    https://qiita.com/hayao_k/items/78b5bfe030ad8a053e93 にあるように.ssh/configを編集します。この時、

    ```
    # SSH over Session Manager
    host i-* mi-*
    ProxyCommand sh -c "aws --profile hogefuga ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
    ```
    と、awsのすぐ後ろに`--profile hogefuga`をいれることで、先ほど入力したプロファイルでアクセスするようになります

5. sshログイン
    SSHコマンドでログインします。この時従来のSSHログインで用いていた鍵ペアの秘密鍵が必要です

    ```bash
    ssh -i {秘密鍵のパス} ${user}@{EC2インスタンスID}
    ```
   ここで`${user}`はサーバーのログインID、`{EC2インスタンスID}`はAWSコンソールのEC2のインスタンス一覧で確認できるiで始まるインスタンスIDです。

SSHログインができれば、SCPもできます。

```bash
scp <ローカルファイルパス> {EC2インスタンスID}:{サーバーのファイルのパス} # local -> remote
scp {EC2インスタンスID}:{サーバーのファイルのパス} <ローカルファイルパス> # remote -> local
```

長かった。
これで、ようやく表題が出てきます(^^;)

# Microsoft Visual Studio Code の Remote SSH 拡張機能
sshコマンドで接続できるんなら、Microsoft Visual Studio Code （以下VSCode）の Remote SSH 拡張機能が使えるのではないか？と思って試してみました。

VSCodeのRemote SSH拡張機能を使うと、SSHログインできる環境はローカルでVSCodeで開いて編集することが可能になります。（一部古いサーバー、インターネットに接続されていないサーバーを除く）
「SSHログインできる環境」ということはSessionManagerを経由してSSHログインできるならVSCodeで開けるはず！！

### 前提
MS VSCodeがローカルにインストール済みである
前段 Session ManagerでSSH/SCPをトンネリングしてEC2に接続する でログイン可能な状態である

### 手順

1. VSCodeにRemote-SSH拡張機能をインストール
    1. 左のツールバーの一番下の拡張機能をクリック
    2. 検索窓に”Remote SSH”と入力、Remote - SSHが表示されるのでクリックして、インストールボタンをクリックする
2. SSH設定ファイルをひらく
    1. F1キーを押し、"Remote-ssh open config"と入力、”Remote-SSH: Open Configuration File...”が表示されるのでクリックする
    2. ホームディレクトリ配下のconfigファイルが一覧の中に表示されるはずなので選択する。（Mac0SXの場合、/Users/$user/.ssh/config）
    3. 下記のように設定を追加する。Host: i-*,m-*より上に追加しないと下の設定が優先されてしまうと思われる

    ```
    Host i-1x2x3ccccc
        ProxyCommand sh -c "aws --profile hogefuga ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
        User $user
        HostName i-1x2x3ccccc
        IdentityFile ~/.ssh/hoge.pem
    ```

    ここでi-1x2x3cccccはEC2のインスタンスID
    $userはログインユーザーID
    hoge.pemはi-1x2x3cccccにログインするのに用いる秘密鍵

3. 対象のサーバーを開く

    1. F1キーを押し、"Remote ssh con"と入力、"Remote-SSH: Connect to Host..."をクリック
    2. リストに接続可能なホストが出てくるので先ほど追加したi-1x2x3ccccをクリック
    3. 左のツールバーの一番上の”エクスプローラー”をクリックして、フォルダーを開くで任意の開発フォルダを開く

4. enjoy coding!!