本稿では以下2つのコマンドのいずれかを実行してSSM経由でSSH接続することを目的とします。なお、ローカル環境はMacOS、EC2インスタンスのAMIはAmazon Linux 2023を想定します。

ssh xxxxx    (以下asano-ssm-testとしますが、任意)
ssh -i xxxxx.pem ec2-user@i-xxxxxx  (i-xxxxはインスタンスID)

ssh -i xxxxx.pem ec2-user@000.000.000.000というように、ローカルの端末からSSH接続する場合はIPアドレスを指定してログインするという方法はしばしばあるかと思います。しかし、これはきちんと設定がなされていればのことです。例えば以下のようなケースでは接続できません。
– EC2インスタンスにグローバルIPアドレスがない(EIPが付与されていない)
– プライベートサブネットにインスタンスがある
– SG(セキュリティグループ)で接続元のIPアドレスや22番ポートが許可されていない

そのような場合でも、SSMさえ動いていればSSH接続できることがメリットになります。

前提

一言でいえば、ローカル環境ではAWS CLIが使えて、AWS環境のインスタンスではコンソールからSSM接続できることが前提です。以下長く述べますが、一旦読み飛ばして次の「configを設定する」へ進み、何かエラーが出たらこちらの前提へ戻るという読み方でも問題ありません。

AWS CLIとSession Managerがローカル環境で使えることを確認します。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/install-plugin-verify.html
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-install.html

which aws
aws --version
session-manager-plugin

例として、以下のように返ってきます。

$ which aws
/xxxxxxxxx/bin/aws
$ aws --version
aws-cli/2.15.49 Python/xxxxxxxxx
$ session-manager-plugin
The Session Manager plugin was installed successfully. Use the AWS CLI to start a session.
$

EC2インスタンスはコンソールからSSM接続できることを前提とします。より正確にはSSM Agent のバージョン 2.3.672.0 以降などの条件(詳細)はありますが、Agentのバージョンが古いとそのような主旨のエラーメッセージが出てログインできないことでわかるので、ここでは省略します。

また、ターミナルでアクセスキー・シークレットアクセスキーなどを設定して、AWS CLIで操作できる状態を想定します。

$ aws sts get-caller-identity
{
    "UserId": "xxxxxxxxxxxxxxx",
    "Account": "0000000000000",
    "Arn": "arn:aws:sts::0000000000000:xxxxxxxxxxxxxxx"
}
$

configに設定する

前置きが長くなりましたが本題です。

SSHのconfigファイルに以下の記述を追記します。Macでは、デフォルトは ~/.ssh/configに置いているかと思います。

パターン①

 # SSH over Session Manager
host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

上記記述を追記したところでSSH接続します。

$ ssh -i xxxxx.pem ec2-user@i-xxxxxxxx
   ,     #_
   ~\_  ####_        Amazon Linux 2023
  ~~  \_#####\
  ~~     \###|
  ~~       \#/ ___   https://aws.amazon.com/linux/amazon-linux-2023
   ~~       V~' '->
    ~~~         /
      ~~._.   _/
         _/ _/
       _/m/'
Last login: Wed Jun 00 00:00:00 2024 from 0.0.0.0
[ec2-user@ip-000-000-000-000 ~]$ 

このようにSSH接続ができます。
ちなみにもし先のconfigの設定をしていないと以下のようなエラーメッセージとなります。

$ ssh -i xxxxx.pem ec2-user@i-xxxxxxxx
ssh: Could not resolve hostname i-xxxxxxxx: nodename nor servname provided, or not known
$ 

先の追記したconfigの記述は、コマンドを事前に指示しておき、省略するためのものとも言えます。コマンドを読み解くと、実際にはProxyCommandとAWS CLIを用いて、aws ssmのstart-sessionというコマンドをターゲットに対して実行しているものです。ですので、configファイルの追記なしでも次の通りにすることで同様の挙動が可能です。

$ ssh -i xxxx.pem ec2-user@i-xxxxx -o ProxyCommand="sh -c 'aws ssm start-session --target i-xxxxx --document-name AWS-StartSSHSession --parameters portNumber=22'"`

インスタンスID、ポート番号を細かく書くと上記ですが、少し省略すると以下の通りです。

$ ssh -i xxxx.cer ec2-user@i-xxxxx -o ProxyCommand="sh -c 'aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters portNumber=%p'"

パターン②

この記述をconfigファイルに追記することで$ ssh asano-ssm-test(任意の名前)だけで接続できるようになります。

host asano-ssm-test(任意の名前)
    HostName i-xxxxx
    User ec2-user(ログインしたい任意のユーザー名)
    IdentityFile "xxxx.pem"
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"

まとめ

インスタンスIDがコロコロと変わるケース(様々なインスタンスに接続するケース)ではパターン①を、特定のインスタンスIDに接続するケースでは②を選択することが使い勝手がいいと思います。なお、これを設定すればSCPコマンドでデータのやりとりをすることも可能です。

今回は以下のドキュメントで紹介されている、configの設定があるとグローバルIPがないインスタンスなどへもSSH/SCPが便利だという内容の投稿でした。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager-getting-started-enable-ssh-connections.html

# SSH over Session Manager
host i-* mi-*
    ProxyCommand sh -c "aws ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"