EC2シリアルコンソール接続を試す。

# はじめに
EC2インスタンスにシリアル接続を行える「**EC2シリアルコンソール**」について、今まで使ったことがなかったので、以下AWSのドキュメントを参照して、どういったものなのか試してみようと思います。

- [Linux インスタンス用 EC2 シリアルコンソール](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-serial-console.html)

# EC2シリアルコンソールとは
私もオンプレミスのサーバを構築する際にはシリアルポートから接続して作業を使ったりしておりましたが、主にサーバ機等を初期セットアップする際に使用する黒いコンソール画面に接続できるサービスとなります。

設定誤りや障害でネットワークサービスがダウンしてしまった場合等、リモートログインできないような状況になった場合でもシリアルコンソールから接続することでサービス復旧作業を行ったりすることができるため、何かあった場合の予防策として覚えておくと役に立つことがあるかもしれません。

# 前提条件
全てのEC2インスタンスに対してシリアルコンソール接続ができるかと言うとそうではなく、以下のようないくつかの前提条件をクリアしている場合に、**EC2シリアルコンソール**を使用することができます。

- [パスワード設定を行ったユーザが必要](#パスワード設定を行ったユーザが必要)
- [Nitroシステムで構築された仮想インスタンスのみ対応](#nitroシステムで構築された仮想インスタンスのみ対応)
- [接続するIAMユーザにEC2シリアルコンソールアクセス権限を付与する](#接続するiamユーザにec2シリアルコンソールアクセス権限を付与する)

## パスワード設定を行ったユーザが必要
いわゆるシリアルコンソールに公開鍵・秘密鍵による接続を行うような機能は無いので、事前にパスワードログインできるようにしておく必要があります。

尚、ここで言っているのは`SSH`でのパスワード接続ではなく、シリアルコンソールからのパスワードログインとなります。

シリアルコンソールからログインするだけであればパスワード設定するだけでログインできるようになるので、間違っても`sshd`の設定を変更しないようにしましょう。

## Nitroシステムで構築された仮想インスタンスのみ対応
`Nitro`システムで構築されている仮想インスタンスのみ対応とのことなので、それ以外のインスタンスタイプを使用している場合はシリアルコンソールを使用することはできません。

また、`Nitro`システムでもベアメタルインスタンスは対象外となります。

以下シリアルコンソールを使用可能なインスタンスタイプ一覧となります。

- [Nitroインスタンスタイプ](https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/instance-types.html#nitro-instance-types)

## 接続するIAMユーザにEC2シリアルコンソールアクセス権限を付与する
EC2シリアルコンソールの有効化と接続を行うIAMユーザに、以下のようなカスタムポリシーの付与が必要となります。

もし使用するIAMユーザに以下のようなアクセス権限が付与されていない場合は、付与するようにしましょう。

後述の「[EC2シリアルコンソールアクセスの有効化](#ec2シリアルコンソールアクセスの有効化)」だけ行う場合は以下のアクションを許可することで有効化できます。

```json:EC2シリアルコンソール接続のアクセス権限を付与するためのカスタムポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:GetSerialConsoleAccessStatus",
                "ec2:EnableSerialConsoleAccess",
                "ec2:DisableSerialConsoleAccess"
            ],
            "Resource": "*"
        }
    ]
}
```

また、EC2シリアルコンソール接続を有効化したEC2インスタンスにシリアルコンソール接続を行う場合は以下のアクションを許可する必要があります。

今回はアクセス有効化とシリアルコンソール接続両方を同じユーザで行おうと思うので、両方定義しますが、シリアルコンソールだけ行うのであれば以下の定義のみ設定してください。

```json:EC2シリアルコンソール接続を行うためのカスタムポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowSerialConsoleAccess",
            "Effect": "Allow",
            "Action": [
                "ec2-instance-connect:SendSerialConsoleSSHPublicKey",
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceTypes",
                "ec2:GetSerialConsoleAccessStatus"
            ],
            "Resource": "arn:aws:ec2:region:account-id:instance/i-0598c7d356eba48d7"
        }
    ]
}
```

# 事前作業
**EC2シリアルコンソール**を使用する前に事前にいくつか準備を行っておく必要があるので、設定を行います。

- [カスタムポリシーの作成](#カスタムポリシーの作成)
- [EC2シリアルコンソールアクセスの有効化](#ec2シリアルコンソールアクセスの有効化)

## カスタムポリシーの作成
前提条件にあったEC2シリアルコンソールの許可設定を行います。

使用するIAMユーザに`AdministratorAccess`等の強力な権限が付与されている場合は作業不要ですが、付与されていない場合はビジュアルエディタ等から作成します。

`IAM`のダッシュボードより、「**アクセス管理**」→「**ユーザー**」→「**対象のユーザー**」を選択し、「**許可**」→「**許可ポリシー**」から「**許可を追加**」→「**インラインポリシーを追加**」を選択します。

![Monosnap_20230121_173107.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/a0358271-a57e-1a8c-9871-ea425c59c489.png)

ビジュアルエディタより以下画面、表のように前提条件で記載したアクションを指定し、「**ポリシーの確認**」を選択します。

尚、AWSのドキュメントおよび画面上の説明ではリソースの`ARN`を指定することがベストプラクティスと記載されておりますが、今回は指定せずすべてのリソース許可の定義で設定します。

![Monosnap_20230121_181945.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/4bf62f92-8a7e-28cd-b300-122a845c9d46.png)

|項目|定義1|定義2|
|:--|:--|:--|
|サービス|EC2|EC2 Instance Connect|
|アクション|・リスト<br>DescribeInstances<br>DescribeInstanceTypes<br>・読み込み<br>GetSerialConsoleAccessStatus<br>・書き込み<br>DisableSerialConsoleAccess<br>EnableSerialConsoleAccess|・書き込み<br>SendSerialConsoleSSHPublicKey|
|リソース|指定なし|指定なし|
|リクエスト条件|指定なし|指定なし|

「**ポリシーの確認**」で任意の名前を指定して「**ポリシーの作成**」を選択します。

![Monosnap_20230121_174203.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/838d9c62-bd6b-4cf9-b7ce-bb5320fdf50f.png)

以下のようにインラインポリシーが追加されていればOKです。

![Monosnap_20230121_174231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/6a8b5e0d-f356-952a-e260-108cead37cf5.png)

## EC2シリアルコンソールアクセスの有効化
EC2シリアルコンソールへのアクセスはデフォルトで無効化されているため、有効化して使用できるようにします。

※まだEC2インスタンスが作成されていない場合は、`Nitro`インスタンスタイプのEC2インスタンスを作成しておいてください。

対象のEC2インスタンスを選択→「**接続**」ボタンを選択。

「**EC2シリアルコンソール**」タブを表示させると以下のようなメッセージが表示されるため、「**Manage access**」を選択します。

![Monosnap_20230121_175000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/9654dc6a-f810-b5e4-6c20-fca86063a563.png)

「**EC2シリアルコンソールのアクセス**」にチェックをし、「**更新**」を選択。

![Monosnap_20230121_175049.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/a02b22d1-6e4a-f471-a5d9-4689b1eee769.png)

以下のように「**許可**」となれば完了です。

![Monosnap_20230121_175358.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/b8b2f0ec-2c6f-aaf9-86eb-d4205ad37b23.png)

コマンドで有効化する場合は以下実施すれば有効化できます。

```bash:EC2シリアルコンソールの有効化
aws ec2 enable-serial-console-access --region [リージョン]
```

```bash:EC2シリアルコンソールの状態確認
aws ec2 get-serial-console-access-status --region [リージョン]
```

ちなみに、有効化したシリアルコンソールを再度無効化するには以下実行すれば無効化できます。

```bash:EC2シリアルコンソールの有効化
aws ec2 disable-serial-console-access --region [リージョン]
```

# EC2シリアルコンソールでのログイン
EC2シリアルコンソールへのログイン方法には2種類あり、1つはマネジメントコンソール画面から接続する方法、もう1つはコマンドラインで接続する方法の2種類あります。

- [マネジメントコンソール画面からのEC2シリアルコンソールログイン](#マネジメントコンソール画面からのec2シリアルコンソールログイン)
- [独自のキーとSSHクライアントを使用したEC2シリアルコンソールログイン](#独自のキーとsshクライアントを使用したec2シリアルコンソールログイン)
    - [SSH公開鍵の作成](#ssh公開鍵の作成)
    - [SSH公開鍵の転送](#ssh公開鍵の転送)
    - [ec2シリアルコンソールへの接続](#ec2シリアルコンソールへの接続)
    - [ログアウト方法](#ログアウト方法)

## マネジメントコンソール画面からのEC2シリアルコンソールログイン
マネジメントコンソール画面からEC2シリアルコンソールにログインする場合、再度「**接続**」画面より「**EC2シリアルコンソール**」タブを選択すると、接続できるようになっているため、「**接続**」を選択します。

![Monosnap_20230121_180001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/de0659f5-26ca-c082-f49e-7cff27cb9eaf.png)

以下のログイン画面が表示されたら、事前に設定していたユーザID、パスワードを入力することでログインできます。

![Monosnap_20230121_183452.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/8228e8a1-ec57-01d0-3e20-d6eb0b3556e0.png)

ログアウトする場合は、`exit`でEC2インスタンスからログアウトして上記画面に戻ってからシリアルコンソールが開かれているブラウザのタブを閉じればOKです。

EC2インスタンスからログアウトしてから閉じないと、タイムアウトで解放されるまでログインできなくなるので、`exit`でログアウトしてから閉じましょう。

## 独自のキーとSSHクライアントを使用したEC2シリアルコンソールログイン
コマンドラインでEC2シリアルコンソールに接続するためにはSSH公開鍵・秘密鍵のペアが必要となります。

SSH鍵はAWSのキーペアサービスで作成した鍵ファイルでなくてもよく、接続時に一時的に使用するだけなので、事前にEC2インスタンスに仕込んでおいたりする必要はありません。

また、SSH公開鍵・秘密鍵のペアを使用しますが、EC2インスタンスへ直接SSH接続するわけではなく、コンソール接続を行うAWSサービスまでの接続がSSHとなるだけのようなので、セキュリティグループで`SSH`を許可したりする必要はありません。

鍵ファイルが乱立するのも面倒なので、今回はAWSのキーペアで作成した秘密鍵からEC2シリアルコンソール接続で使用する公開鍵を生成して接続を行ってみようと思います。

### SSH公開鍵の作成
AWSのキーペアからSSH鍵を作成した場合、秘密鍵しか生成されないので、公開鍵を生成するには、該当のキーペアを指定して作成したEC2インスタンスの`authorized_keys`ファイルの中身をコピーするか、秘密鍵から`ssh-keygen`コマンド等で公開鍵を生成する必要があります。

以下は`ssh-keygen`コマンドで公開鍵を生成した場合の例。

```bash:公開鍵ファイルの生成
ssh-keygen -y -f [秘密鍵ファイル名] > [生成する公開鍵ファイル名]
```

### SSH公開鍵の転送
`send-serial-console-ssh-public-key`コマンドで、先程生成した公開鍵ファイルをAWSに転送します。

このコマンドを実行することで**AWS側に60秒間だけ転送したSSH公開鍵が保持**されるため、その間にSSHによるシリアルコンソール接続を行う必要があります。

```bash:SSH公開鍵の転送
aws ec2-instance-connect send-serial-console-ssh-public-key \
--instance-id [インスタンスID] \
--serial-port 0 \
--ssh-public-key file://[生成した公開鍵ファイル名] \
--region [リージョン]
```

コマンド実行後、`Success`が`true`と表示されていれば転送成功です。

```
RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Success: true
```

### EC2シリアルコンソールへの接続
`send-serial-console-ssh-public-key`コマンド実行後、60秒以内に以下のコマンドを実行します。


```bash:EC2シリアルコンソールへの接続
ssh -i [秘密鍵ファイル名] [インスタンスID].port0@serial-console.ec2-instance-connect.ap-northeast-1.aws
```

また、私の環境（MacBook Air M2）では以下のエラーが表示され、接続できませんでした。

```bash:no mutual signature supported エラー
sign_and_send_pubkey: no mutual signature supported
i-xxxxxxxxxxxxxxxxx.port0@serial-console.ec2-instance-connect.ap-northeast-1.aws: Permission denied (publickey).
```

比較的新しいバージョンの`OpenSSHクライアント`を使用している場合、`ssh-rsa`の使用が拒否されるため、上記エラーが出力されるようです。

上記エラーが出力された場合は、以下で一時的に`ssh-rsa`を許可するか、`~/.ssh/config`に`ssh-rsa`を許可する定義を設定する必要があるようです。

```bash:no mutual signature supported エラーが出力された場合の接続コマンド
ssh -o 'PubkeyAcceptedKeyTypes +ssh-rsa' -i [秘密鍵ファイル名] [インスタンスID].port0@serial-console.ec2-instance-connect.ap-northeast-1.aws
```

```bash:~/.ssh/configに設定した場合の例
Host *
  HostKeyAlgorithms +ssh-rsa
  PubkeyAcceptedKeyTypes +ssh-rsa
```

### ログアウト方法
EC2インスタンスログイン後、`exit`しただけではシリアルコンソール画面からはログアウトできないので、`exit`して最初のログイン画面まで戻ってきたら、「**~.**」（チルダ＋ドット）を入力することでシリアルコンソール画面から抜けます。

```bash:ログアウト方法
~.  ←「チルダ＋ドット」を入力（画面には表示されない）
 Connection to serial-console.ec2-instance-connect.ap-northeast-1.aws closed.
```

# おわりに
クラウド環境でリモートから接続して作業している場合、SSHサービス設定など誤ると、リモートから接続できず、最悪詰む可能性があるので、いざというときにシリアルコンソールからコンソール接続できるようにしておくと、心の余裕ができると感じました。

私も今後、`Nitro`インスタンスのEC2インスタンスを使用する場合はシリアルコンソール接続できるように設定しておこうと思いました。