SSM マネージドインスタンスに出てきていない EC2 インスタンスはどれだ!?

この記事を書いたメンバー:

那須 隆

SSM マネージドインスタンスに出てきていない EC2 インスタンスはどれだ!?

目次

アイキャッチ画像が Systems Manager になってますが実際はほぼ AWS CLI の記事です。那須です。

とある作業で、Systems Manager(以下SSM)でたくさんある EC2 インスタンスを管理しようと思って準備していたら、どうも EC2 インスタンスの数と SSM のマネージドインスタンスの数が合わないことに気がつきました。 インスタンス数が少なければどれが正しく設定できていないかすぐに分かるんですが、100 台近くの EC2 インスタンスがあって 98 台は SSM のマネージドインスタンスとして見えてるけど残りの 2 台はどれ?ってなりましたので、どうやって設定がうまくいっていない EC2 インスタンスを特定したのかをご紹介します。

Excel をうまく使えば特定できるんですが、どうせ EC2 インスタンスの一覧を AWS CLI で取得するなら欲しい情報もそのまま bash でやろうと思ったので、今回は bash メインです。mac や Windows PC で WSL2 を使っている方が対象の記事になっていますが、PowerShell でも似たようなことができるはずですよ。(私は Windows 10 に WSL2 を入れて bash を使ってます。zsh では試してませんが、たぶんできるんじゃないでしょうか…)

 

まずは EC2 インスタンスの一覧を作ろう

SSM マネージドインスタンスの一覧と比較するための情報を取得します。 何も考えずに describe-instances を実行すると停止中の EC2 インスタンスまで表示されるので、running 状態の EC2 インスタンスの ID 一覧を取ってきましょう。 出力を text にしている理由は、あとで簡単に bash の array に入れるためです。 人が見るだけなら json で出力するのがいいと思います。

 $ aws ssm describe-instance-information --filters "Key=PingStatus,Values=Online" --query 'sort(InstanceInformationList[*].InstanceId[])' --output text
i-11111111111111111     i-22222222222222222     i-33333333333333333     i-44444444444444444     i-55555555555555555 ....

さあこれで比較する 2 つの一覧が作れましたね。

さっそく差分を出してみる

さきほどの一覧を配列に入れて、それぞれの差分を表示しています。uniq -u がめちゃくちゃ便利ですね(今日知りました

 declare -a ssm=(`aws ssm describe-instance-information --filters "Key=PingStatus,Values=Online" --query 'sort(InstanceInformationList[*].InstanceId[])' --output text`)
declare -a ec2=(`aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query "sort(Reservations[].Instances[].InstanceId)" --output text`)
echo ${ssm[@]} ${ec2[@]} | tr ' ' '\n' sort uniq -u
i-00000000000000000
i-99999999999999999

この例では 2 つのインスタンスが起動しているけど SSM マネージドインスタンスとして登録されていないことがわかりました。 EC2 インスタンス ID だけで十分特定できているのですが、人が見た時に「ID だけじゃわからん…」って気持ちになりますよね?(私はなりました

そこで、出てきた EC2 インスタンス ID の名前を一緒に出力することにしました。Name タグを取ってくるようにしていますが、もし他にわかりやすいタグがあればそれを指定しましょう。

 declare -a diff_ec2_ssm=(`echo ${ssm[@]} ${ec2[@]} | tr ' ' '\n' sort uniq -u`)
for diff_instance_id in "${diff_ec2_ssm[@]}" do
>     name_tag=`aws ec2 describe-instances --instance-ids ${diff_instance_id} --query "Reservations[].Instances[].Tags[?Key=='Name'].Value[]" --output text`
>     echo "$name_tag $diff_instance_id"
done
nasutest0 i-00000000000000000
nasutest9 i-99999999999999999

スクリプト化するとこうなります

スクリプト名は ssm_unmanaged_instances.sh にしました。 各 AWS CLI 実行時に –profile がついていますが、それぞれの環境にあわせて実行できるようにプロファイル名を指定できるようにしています。

 #!/bin/bash
 
declare -a ssm=(`aws ssm describe-instance-information --filters "Key=PingStatus,Values=Online" --query 'sort(InstanceInformationList[*].InstanceId[])' --output text --profile $1`)
declare -a ec2=(`aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query "sort(Reservations[].Instances[].InstanceId)" --output text --profile $1`)
declare -a diff_ec2_ssm=(`echo ${ssm[@]} ${ec2[@]} | tr ' ' '\n' sort uniq -u`)
 
for diff_instance_id in "${diff_ec2_ssm[@]}" do
    name_tag=`aws ec2 describe-instances --instance-ids ${diff_instance_id} --query "Reservations[].Instances[].Tags[?Key=='Name'].Value[]" --output text --profile $1`
    echo "$name_tag $diff_instance_id"
done

実行するには、以下のように第 1 引数にプロファイル名を指定しましょう。 本当は引数のチェックとかを入れるべきですが、さすがにこれくらいの量のソースならすぐわかるだろうと思うので usage 表示まで作ってません。 

 $ ./ssm_unmanaged_instances.sh nasu_admin
nasutest0 i-00000000000000000
nasutest9 i-99999999999999999

実際に実行してもらうとわかるのですが、結果が出るまで結構時間がかかります。 差分があればあるほど時間がかかるのでもう少し違ったやり方で Name タグを取ってくるのがよさそうですが、時間があまりなかったのでひとまず最低限結果がわかるスクリプトになっています。

2020/09/29追記:PowerShell でもできます!

社内にいる PowerShell マスターが作ってくれました! 以下の内容を PowerShell で実行しても同じ結果が得られます!

 #!/usr/bin/env pwsh
 
<#
.SYNOPSIS
    ssm_unmanaged_instances.ps1
.DESCRIPTION
    SSMが無効になっているインスタンス一覧
.EXAMPLE
    PS >./ssm_unmanaged_instances.ps1 -Profile aws-cli-profile-name
    PS >./ssm_unmanaged_instances.ps1 -Profile aws-cli-profile-name --region ap-northeast-1
.PARAMETER Profile
    AWSプロファイル名を設定
.PARAMETER Region
    AWS-リージョンを指定
.INPUTS
    None
        You cannot pipe objects
.OUTPUTS
    none
.NOTES
    none
#>
 
PARAM(
    [Parameter(Mandatory $True)]
    [String]$Profile,
    [Parameter(Mandatory $False)]
    [String]$Region "ap-northeast-1"
)
 
PROCESS {
 
    # StrictMode設定
    Set-StrictMode -Version Latest
    # エラー時に処理をstop
    $ErrorActionPreference "stop"
 
    # ssm一覧 取得
    [array]$ssm = aws ssm describe-instance-information --filters 'Key=PingStatus,Values=Online' --query 'InstanceInformationList[].{InstanceId:InstanceId} | sort_by(@,&InstanceId)' --output json --profile $Profile --region $Region ConvertFrom-Json
    # ec2一覧 取得
    [array]$runningEC2 = aws ec2 describe-instances --filters 'Name=instance-state-name,Values=running' --query 'Reservations[].Instances[].{InstanceId:InstanceId,Name:Tags[?Key==`Name`]|[0].Value} | sort_by(@,&InstanceId)' --output json --profile $Profile --region $Region ConvertFrom-Json
 
    # 一覧が取得出来た場合のみ結果比較
    if [boolean]$ssm -and [boolean]$runningEC2 ) {
        # PingStatusNG リスト取得
        [array]$pingStatusNG Compare-Object -ReferenceObject $runningEC2.InstanceId -DifferenceObject $ssm.InstanceId -PassThru
        # 対象表示
        $runningEC2 Where-Object InstanceId -In $pingStatusNG
 
    }
    else {
        Write-Host "SSM-PingStatus/RunningEC2Instance is not found"
    }
 
}

実際に実行した場合の出力例です。 

 > .\ssm_unmanaged_instances.ps1 -Profile nasu_admin
 
InstanceId          Name
----------          ----
i-00000000000000000 nasutest0
i-99999999999999999 nasutest9

さいごに

マネジメントコンソールでこの情報を確認できればいいのですが、どこで見れるかわからなかったので簡単ではありますがスクリプトを作ってみました。 AWS CLI を使えばマネジメントコンソールでは確認できない情報もすぐに確認できるので本当に重宝します。 運用作業では GUI での手作業だけでは辛い場面も多々ありますので、日々の運用の中で AWS CLI を積極的に使っていきましょう!










カテゴリー
タグ

SAPシステムや基幹システムのクラウド移行・構築・保守、
DXに関して
お気軽にご相談ください

03-6260-6240 (受付時間 平日9:30〜18:00)