AutoScalingで起動したインスタンスの情報をssh bannerで表示させた話

#背景
自社のプロジェクトでAWS上に構築したインスタンスを冗長構成にしようという話になり、AutoScalingを採用することに。
しかし、いざ使ってみるとホスト名絡みの動作が自分たちの既存の環境とミスマッチしてしまう。
なので、立ち上がったインスタンスのホスト名を自動で書き換えるような仕組みを、
起動テンプレートのUserdataやLambdaやDNSへのAレコード登録で実現しようと試みたが、
ちょいと手間がかかるということで別の仕組みを考えることに。
で、管理サーバにsshで接続したときにbannerで稼働中のインスタンスの情報を表示させる的なアイデアにたどり着く。

#ミスマッチになった点
* awslogsでCloudwatchにログを送信する際、ログストリーム名にホスト名を指定していたため、ip-10-x-x-x.ap-northeast-1.compute.internalという名前でログストリームが乱立して見にくくなった。
* 管理サーバを踏み台としてssh接続する構成であり、この時ホスト名ではなくIPアドレスを指定して接続する必要がある。なので、awsコマンドやawsコンソールから接続先のIPアドレスを確認する手間が発生する。

#目指したもの
* 管理サーバにssh接続した際に、現在稼働中のサーバの情報がssh bannerで表示される。
* Autoscalingプロセス完了時にbannerの内容を更新する。

#作業
##AWS側設定
###起動テンプレート
タグにNameタグを設定し、Autoscalingで起動したことがわかるようなキーワードを指定。（ホントはここもユニークである方がいい気もする。。。）

###Cloudwatch Events
「Autoscalingプロセス完了時」をトリガーとする場合、概ね以下のルールになると思う。

```
{
  "source": [
    "aws.autoscaling"
  ],
  "detail-type": [
    "EC2 Instance Launch Successful",
    "EC2 Instance Terminate Successful",
    "EC2 Instance Launch Unsuccessful",
    "EC2 Instance Terminate Unsuccessful",
    "EC2 Instance-launch Lifecycle Action",
    "EC2 Instance-terminate Lifecycle Action"
  ],
  "detail": {
    "AutoScalingGroupName": [
      "autoscaling-servers"
    ]
  }
}
```

後述のスクリプトをキックするために、SSMを使用してコマンドを管理サーバへ送信するためのターゲットを設定。

タイプ | Name | 入力 | ロール | 追加のパラメータ
--- | --- | --- | --- | ---
SSM Run Command | AWS-RunShellScript | 定数: {"commands":["sudo -i","sudo -u ec2-user /home/ec2-user/create_banner.sh"]} | AWS_Events_Invoke_Run_Command_xxxxxxxxxxx | RunCommandParameters:キー: InstanceIds、値: i-xxxxxxxxxxxxxxxxx


##管理サーバ側設定
###ssh設定
/etc/ssh/sshd_configに以下の一行を追加。
追加後に`systemctl restart sshd`を実行して適用。

```ssh:/etc/ssh/sshd_config
Banner /tmp/ssh_banner.txt
```

###SSM設定
以下のURLを参考に管理サーバにSSMを追加。
https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/sysman-manual-agent-install.html#agent-install-rhel

###スクリプト
以下のスクリプトを作成。（殴り書き）
作成後に`chmod +x /home/ec2-user/create_banner.sh`を実行。

```shell:/home/ec2-user/create_banner.sh
#!/usr/bin/bash

result=/tmp/ssh_banner.txt

if [ -e $result ]; then
  rm -rf $result
  touch $result
  chown ec2-user:ec2-user $result
else
  touch $result
  chown ec2-user:ec2-user $result
fi

echo "_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/" >> $result
echo "Current running servers is following." >> $result

Describe_Tags=`sudo -u ec2-user aws ec2 describe-tags --filters "Name=value,Values=autoscaling-server"`

echo "$Describe_Tags" | grep "i-" | cut -d \" -f 4 | while read id
do
State=`sudo -u ec2-user aws ec2 describe-instances \
        --instance-ids $id --query Reservations[*].Instances[*].[State.Name]`
IPAdd=`sudo -u ec2-user aws ec2 describe-instances \
        --instance-ids $id --query Reservations[*].Instances[*].[PrivateIpAddress]`
IPAdd=`echo "$IPAdd" | grep [0-9] | cut -d \" -f 2`
if [[ $State == *running* ]]; then
  echo "  EC2 instance id : $id  -->  ssh ec2-user@$IPAdd" >> $result
fi
done

echo "_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/" >> $result
```

#ssh bannerの表示結果
上記のスクリプトの場合、こんな感じの表示っぷり。
sshほにゃららの部分をコピペすればスムーズに接続できる感じ。

```
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
Current running servers is following.
  EC2 instance id : i-xxxxxxxxxxxxxxx  -->  ssh ec2-user@10.20.30.40
  EC2 instance id : i-yyyyyyyyyyyyyyy  -->  ssh ec2-user@50.60.70.80
_/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/ _/
Last login: Fri May xx xx:xx:xx 2019 from hogehogehoge
[ec2-user@管理サーバ ~]$
```

#所感
とりあえず、IPアドレスを確認する手間ってのは解消。
ログストリームの点はマジでどうしようか検討中。。。
「AutoScalingで立ち上がったインスタンスのホスト名を自動でつける」的なサービスを同僚と探していたんですが、
ググってみると思いのほか同じ問題を対処した記事が中々見当たらず、
「皆どうしてるんだろう・・・？自分たちだけがこの問題を抱えてんのかなぁ・・・？」と同僚と難儀してます。
ホスト名の命名規則次第でどうとでもなるんでしょうかね。。。？
もっといいソリューションとか「うちはこうしてる」とかあればコメントいただけると幸いです。
ご拝読ありがとうございました。