AWS Systems Mangerを使ってVS CodeからRaspberyPiへRemote SSHできるようにする。

## はじめに
私用、業務を問わず、管理するRaspberyPiがそれなりに増え、デバイス自体の管理とデバイスへの接続作業が面倒に感じることが増えてきた。AWS Systems Mangaer(SSM)内のSession Mangerは主にEC2を管理するためのサービスであるが、オンプレミス（AWSの外の端末）でも利用することが可能である。

SSMを使って、Raspbery PiをEC2のようにSSMで管理できるようにしたい。AWSのドキュメントもしかっりしているが、ポイントだけ抑えたいい塩梅の記事が見つからなかったため、本記事でまとめておく。

混乱しそうだが`AWS Systems Manager Session Manager`が正式名になる。

## やりたいこと
- VS CodeのRemote拡張機能を使ったRaspberyPiへのSSHログイン。
- SSHの接続は、AWS Sesseion Mangaerログインで行う。

## 前提
- Raspbery Piへ公開鍵/秘密鍵を使ってSSH接続できる状態
- 接続元となるHost環境でAWS CLIが使える状態
※AWS CLIの設定など、ベーシックな手順については割愛する。

## この記事で使用する環境
- Raspberry Pi 3 Model A+ (Ubuntu 22.04.2 LTS)
- Windows11  + VS Code


### Step1 AWS側準備

SSMではセッションを開始する際、下記CLIコマンドでセッションを開始できる。
```bash:セッション開始の例
aws ssm start-session --target instance-id
```

EC2であれば、インスタンスIDが一意に割り振られるが、オンプレミスではこのインスタンスIDがないため、アクティベーションという作業が必要になる。Step2では、アクティベーションに必要なロールの作成とアクティベーションを行う。

#### 1.1 IAMロールの作成
Session Mangerをエッジ端末にインストールする場合、IAMロールを割り当ててAWSリソースに対する権限を制御することになる。まずはロールを作成する。

SystemsMangaer
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54100/e5916e77-f84e-b4e3-3e8d-14161160425c.png)


#### 1.2 アクティベーションIDの取得
コンソールから操作する。作成したIAMロールを指定する。このコンソール画面における有効期限は、あくまでアクティベーションをするまでの猶予時間であるので、この時間内にアクティベーションを完了できれば、その時間以降もSystems Managerを使うことができる。IAMロールが共通の場合は、複数の端末を1アクティベーションIDで登録できる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54100/4541b258-4a49-dd60-046e-a18377b34508.png)


操作完了後、コンソール上側から払い出されたCodeやIDが表示される。アクティベーションコードは、**ページ遷移してしまうと消えてしまうので注意。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54100/59985267-032c-179d-dbf9-6d1a74981b0c.png)


#### 2.3 アクティベーションの実行
RaspberryPi側から、アクティベーションを行う。
```bash:
sudo -E amazon-ssm-agent -register -code "activation-code" -id "activation-id" -region "ap-northeast-1" 

```


### Step2 Raspbery Pi側の環境を準備
#### 必要なもの
まずはセッションマネージャーをインストールする。

```bash:インストール
mkdir /tmp/ssm
curl https://s3.ap-northeast-1.amazonaws.com/amazon-ssm-ap-northeast-1/latest/debian_arm64/amazon-ssm-agent.deb -o /tmp/ssm/amazon-ssm-agent.deb
sudo dpkg -i /tmp/ssm/amazon-ssm-agent.deb
sudo service amazon-ssm-agent stop
```

マネジメントコンソールから入手したコードとIDを使い、アクティベーションする。
```bash:アクティベーション実行
sudo dpkg -i /tmp/ssm/amazon-ssm-agent.deb
sudo -E amazon-ssm-agent -register -code "activation-code" -id "activation-id" -region "ap-northeast-1" 
sudo service amazon-ssm-agent start
```

```bash:出力結果
Error occurred fetching the seelog config file path:  open /etc/amazon/ssm/seelog.xml: no such file or directory
Initializing new seelog logger
New Seelog Logger Creation Complete
2023-06-09 15:27:40 WARN Could not read InstanceFingerprint file: InstanceFingerprint does not exist
2023-06-09 15:27:40 INFO No initial fingerprint detected, generating fingerprint file...
2023-06-09 15:27:43 INFO Successfully registered the instance with AWS SSM using Managed instance-id: mi-XXXXXXXXXXXXXXXXX
```

一番最後の行に、`instance-id: mi-XXXXXXXXXXXXXXXXX`と出てくる。これがRaspberyPi固有のIDとなる。




### Step3 Raspbery Piへ接続できるようにする
#### 3.1 Session Mangerプラグインのインストール

Session Mangerプラグインは、AWS CLIがインストールされた環境において、Systems Managerがインストールされたインスタンスや、今回のようなRaspberyPi環境へ接続できるAWS CLIへの追加機能である。

手順に従いインストールする。今回はWindowsへのインストールなので、特に解説することもないので手順は割愛する。

手順は公式ドキュメントに：
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html

#### 3.2 接続トライ（失敗例）

Step2で入手したIDを使って、Raspbery Piへアクセスする。
```bash:接続トライ
aws ssm start-session --target mi-XXXXXXXXXXXXXXXXX
```
コマンドが通るものの、エラーが出てセッションを確立できない。
```bash:実行結果
An error occurred (BadRequest) when calling the StartSession operation: Enable advanced-instances tier to use Session Manager with your on-premises instances
```

これは、SystemsMangerのインスタンス枠の設定によるもので、インスタンス枠を`標準インスタンス層`から、`高度なインスタンス層`へ変更することが必要である。設定を変えることで、インスタンスの上限が撤廃されるが、セッション単位で従量課金制の料金が発生する。設定を有効にした場合、`0.00695 USD *台数*時間`かかることになる。（10台を1か月だと50USDの計算。）


下図は、高度な層から標準層へ切り替えるときに出る警告画面。標準層へ戻すとセッションができなくなると警告される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54100/13c59c29-d9a2-298f-c86c-52999304a335.png)

台数の制約でなく、セッションの使用が目的の場合は、セッションの際に有効にして、セッション終了後はOFFにする、または自動的にOFFにさせるのが良さそう。引数の`setting-value`は`standard`か`advanced`が選べる。CLIから任意にON/OFFが可能。

```bash:CLIから高度な層から標準的な層へ変更
aws ssm update-service-setting \
    --setting-id arn:aws:ssm:region:aws-account-id:servicesetting/ssm/managed-instance/activation-tier \
    --setting-value standard
```


また、CLIから現在の状態を確認することも可能。
```bash:状態の確認
aws ssm get-service-setting \
    --setting-id arn:aws:ssm:region:aws-account-id:servicesetting/ssm/managed-instance/activation-tier
```

```bash:実行結果
{
    "ServiceSetting": {
        "SettingId": "/ssm/managed-instance/activation-tier",
        "SettingValue": "advanced",
        "LastModifiedDate": "2023-06-09T07:07:38.140000+00:00",
        "LastModifiedUser": "",
        "Status": "PendingUpdate"
    }
}
```

`Status`が変化するとタイムスタンプがつく。`Status`は、`Defalut/PendingUpdate/Customized`を行き来する様子。

#### 3.3 接続トライ（成功例）
改めて接続すると、無事接続できた。
```bash:接続トライ
$ aws ssm start-session --target mi-XXXXXXXXXXXXXXXXX
Starting session with SessionId: YYYYYYYYYYYYY

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.2 LTS
Release:        22.04
Codename:       jammy
```

### Step4 VS Codeから接続できるようにする。

VS Code Remoteの設定から接続するためにHostを設定する。
- HostName: Systems ManagerにおけるノードID
- User: SSHを許可しているユーザ。**ssmで生成されるssh-userではない。**
- IdentityFile: SSHで使う秘密鍵へのフルパス
- ProxyCommand: WindowsなのでPowerShellから叩けるコマンドとした。`\`だとコマンドが通らないので、`/`で表現されるパスを指定する必要がある。実体はawsコマンド叩いているだけであり、profileの指定も可能。


```text:設定例
host Raspbery3bA+
  HostName "mi-XXXXXXXXXXXXXXXXX"
  Port 22
  User ubuntu
  IdentityFile C:\XXXX\id_rsa
  ProxyCommand C:/Windows/System32/WindowsPowerShell/v1.0/powershell.exe aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p

```

VS Codeから無事SSH接続できた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54100/00189dc2-a92b-bd7e-5e84-64fc9cdce041.png)

### 終わりに
勘所を抑えればそこまで難しくなかった。CLIからアクティベーションIDなど発行できるようにすれば、マシンが増えても気軽に対応できそう。すべてのマシンの接続管理はSystems Manager、SSH接続先の管理はVS Codeの設定の同期とすることで、接続元に依らない管理・開発環境を揃えられそうだ。特に、Sesson Managerを利用する際、ポート開放など特別な設定が必要なく、これはオンプレミスのような限定環境下において、非常に便利に感じる。

また、Systems Managerのインスタンス枠において、高度な層を利用することで利用料金がかかることが分かった。節約のため切り忘れ防止処置として、EventBridgeとLambdaを使って、定期的に自動で標準層へ戻るようにしておいた方が良さそう。