【AWS】SSM Session ManagerでローカルからEC2インスタンスに接続する

SSM Session Managerを利用してaws-cliで手軽にローカルからEC2へ接続するためにShell Scriptを書いたので説明していきたいと思います
SSM Session Mangerの設定方法は本記事では説明しませんので[公式ドキュメント](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html)を参照して下さい

SSM Session Managerだと長いので、以下ではSession Mangerと略します


# Shell Script

動作保証しているOSはMacOSです
それ以外のOSでは動作しないことがありますのでご了承下さい

## plugin用

Session Managerを利用するためにはローカルにPluginが必要です
以下のスクリプトでサポートしているのはPluginのインストールとアンインストールです
インストールはS3にあるPluginのzipファイルをダウンロードしてローカルのPATHに含まれている/user/local/binにビルドします
アンインストールはビルドしたスクリプトを削除するだけです

```bash:plugin.bash
#!/bin/bash

# ------------------------------------------
# SSM Session Manager Plugin
# https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html
#
# this script features
# - install
# - uninstall
# ------------------------------------------

set -xeu

function install {
  base_dir=$(cd $(dirname $0); pwd)
  download_dir="/tmp/ssm"

  if [ ! -d "$download_dir" ]; then
    mkdir $download_dir
  fi

  pushd "$base_dir" > /dev/null
  pushd "$download_dir" > /dev/null

  curl -o "sessionmanager-bundle.zip" \
    "https://s3.amazonaws.com/session-manager-downloads/plugin/latest/mac/sessionmanager-bundle.zip"

  unzip sessionmanager-bundle.zip

  sudo ./sessionmanager-bundle/install \
    -i /usr/local/sessionmanagerplugin \
    -b /usr/local/bin/session-manager-plugin

  popd > /dev/null
  popd > /dev/null

  read -p "Do you remove the downloaded files ? [y/n] > " flag
  case "$flag" in
    "y")
      rm -rf $download_dir ;;
    "n") ;;
    *)
      echo "Please typing y or n"
      exit 1 ;;
  esac
}

function uninstall {
  sudo rm -rf /usr/local/sessionmanagerplugin
  sudo rm /usr/local/bin/session-manager-plugin
}


cmd="$1"
case "$cmd" in
  "install")
    install ;;
  "uninstall")
    uninstall ;;
  *)
    echo "Please specify install or uninstall in first argument"
    exit 1 ;;
esac
```

## Session用

このスクリプトではSessionのスタートと履歴の確認ができるようになっています
まずSessionをスタートさせるには接続先のEC2のインスタンスIDが必要です
それを自動取得するために接続先のEC2の名前を引数としてもらって、`aws ec2 describe-instances`コマンドでインスタンスIDを取得します
なので接続先のEC2の名前さえ覚えておけば接続できます

```bash:session.bash
#!/bin/bash

set -xeu

cmd="$1"
target_ec2_name="$2"
profile="$3"

if [ -z "$target_ec2_name" ]; then
  echo "Please specify EC2 name in the second argument"
  exit 1
fi

if [ -z "$profile" ]; then
  echo "Please specify aws profile name in the third argument"
  exit 1
fi

instance_id=$(aws ec2 describe-instances --output text \
                --filters "Name=tag:Name,Values=$target_ec2_name" \
                --query "Reservations[*].Instances[?Instance.State.Name==running].InstanceId" \
                --region ap-northeast-1 --profile "$profile")

function start {
  aws ssm start-session \
    --target "$instance_id" \
    --region ap-northeast-1 --profile "$profile"
}

function list {
  aws ssm describe-sessions \
    --state "History" \
    --filters "key=Target,value=$instance_id" \
    --region ap-northeast-1 --profile "$profile"
}

case "$cmd" in
  "start") start ;;
  "list") list ;;
  *)
    echo "Please specify start or list in the first argument"
    exit 1 ;;
esac
```

## Makefile

上記のShell Scriptを手軽に実行できるようにMakefileを書いてみました

```makefile:Makefile
.PHONY: session plugin

plugin:
	bash plugin.bash $(cmd)

session:
	bash session.bash $(cmd) $(name) $(profile)
```

### pluginのコマンド引数説明

$(cmd)には`install`か`uninstall`を指定します
機能は名前通りです

### sessionのコマンド引数説明

|引数|説明|
|:--:|:--|
|cmd|`start`か`list`を指定して下さい<br>startはSessionの開始します<br>listはSesisonの履歴をみることができます|
|name|接続したいEC2インスタンスの名前を指定します|
|profile|AWS profleのことを示しています<br>適切なIAM Roleが紐づいているIAM Userのprofileを指定して下さい|

### Session Startを実行

Sessionを開始してみます

```bash
make session cmd=start name=qiita profile=test
```

上記のコマンドを実行してみると以下のようになります

![ssm_session.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/173064/c810e872-c023-648c-dd3e-6ac99fea1a78.png)


プロンプトが`sh-4.2$`になっていればEC2に接続できたということです
ちなみにSessionでログインするユーザをSSMSessionRunAsでタグ付したとしてもログインシェルは初期化されないので、`sh-4.2$`のままです
この[Issue](https://github.com/aws/amazon-ssm-agent/issues/131)でも書かれていますが、ログインシェルを自動で変更したいのであれば以下のようにすればよさそうです

```bash
aws ssm start-session --target <INSTANCE_ID> --document-name AWS-StartInteractiveCommand --parameters command="bash -l"
```

個人的にはSSMSessionRunAsのように手軽にログインシェルを指定できるようにして欲しいですね

# 参考

- https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-manager.html
- https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/session-preferences-run-as.html