1.はじめに
EC2インスタンスに対して、AWS Systems Manager メンテナンスウィンドウでSSM Agentのアップデートを定期的に行おうとしていたところ、
ある問題が発覚し、その際に調査したときの内容を本記事でまとめます。
なお、SSM Agentのアップデートは「フリートマネージャー」のコンソール上からも実施ができますが、アップデートを任意のタイミングで定期的に行いたかったため、メンテナンスウィンドウにて実装を行っています。
2.やろうとしたこと・起きたこと
何をしたかったか
開発環境、本番環境と分かれた環境で、各環境にはEC2を複数台配置してました。
各環境へのSSM Agentのアップデートは、メンテナンスウィンドウにRun Commandタスク登録で月初(夜間)にAWS-UpdateSSMAgentを実行するように設定を行い、定期的にSSM Agentのバージョンを最新にしようとしていました。
開発環境は常時利用しないため、夜間はEventBridgeにてインスタンス停止を日次で行っていました。
また、各環境は対象となるEC2が複数存在していたため、リソースグループを作成してRun Commandタスクのターゲット先に指定していました。

※イメージ図(リソースグループ割愛)
起きたこと
Run Commandの前提条件でもありますが、ターゲット先インスタンスのSSM Agentとの通信が確立されていないと実行ができません。
そのため、夜間にインスタンス停止している開発環境は、アップデートされないままメンテナンスウィンドウタスクが完了扱いされます。
これはリソースグループをターゲットにしたことによる落とし穴みたいなもので、対象インスタンスが0でもエラー扱いにはならないようです。
本当にリソースグループならではの問題なのかを確認のため、停止しているEC2に対して、以下パターンで検証した結果を記載します。
- リソースグループ(紐付けインスタンスは1台のみ)
- メンテナンスウィンドウ実行は成功
- インスタンス指定(対象は一台のみ)
- メンテナンスウィンドウ実行は失敗
結果として、同じメンテナンスウィンドウを実行させたところインスタンス指定かリソースグループ選択かで実行結果が異なりました。
エラーが出力されずSSM Agentバージョンのアップデートのような即時でサービス影響が出ないようなものだと、メンテナンスウィンドウ上は成功扱いになるのでなかなか気づけないかと思います。
こういったことを防ぐためにもメンテナンスウィンドウのような定期実行するものは、実行自体が成功したことのみを確認するのではなく、
定期的なスケジュール(今回であればインスタンス停止)に沿った検証も大事だと感じました。
3.対応策
対応手段はいくつかあるかと思いますが、今回問題となっているのは主にインスタンスが停止していることによるものです。
そのため、AutomationタスクにてEC2インスタンス起動→Run CommandにてSSM Agentアップデートを実行していきます。
こうすることによって、開発環境のような日次停止を定常実行している環境に対して、任意のサイクルでSSM Agentのアップデートが自動的に行われるような環境を作ります。
4.実施
実施目的
リソースグループに紐づいている単独のEC2(Amazon Linux 2023)に対して、インスタンスが停止時でも問題なくSSM Agentアップデートを行うメンテナンスウィンドウが実行できること。
準備
事前に作成したEC2にある現行SSM Agentバージョン
sh-5.2$ rpm -qa |grep amazon-ssm amazon-ssm-agent-3.2.1630.0-1.amzn2023.x86_64
EC2は停止

検証用メンテナンスウィンドウ用意


- 各タスクのターゲット指定はリソースグループを指定
- レート制御
- 同時実行数
- 100%
- エラーの閾値
- 1エラー
- 同時実行数
- パラメータ
- オートメーションドキュメント(AWS-StartEC2Instance)
- InstanceId
- {{RESOURCE_ID}}
- InstanceId
- オートメーションドキュメント(AWS-StartEC2Instance)
サービスロール用IAM
IAMロール
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "ssm.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
IAMポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"resource-groups:ListGroups",
"resource-groups:ListGroupResources"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"ssm:SendCommand",
"ssm:CancelCommand",
"ssm:ListCommands",
"ssm:ListCommandInvocations",
"ssm:GetCommandInvocation",
"ssm:GetAutomationExecution",
"ssm:StartAutomationExecution",
"ssm:ListTagsForResource",
"ssm:GetParameters",
"ssm:DescribeInstanceInformation"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"ec2:StartInstances",
"ec2:DescribeInstanceStatus"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Action": [
"tag:GetResources"
],
"Resource": "*",
"Effect": "Allow"
},
{
"Condition": {
"StringEquals": {
"iam:PassedToService": "ssm.amazonaws.com"
}
},
"Action": [
"iam:PassRole"
],
"Resource": "*",
"Effect": "Allow"
}
]
}
メンテナンスウィンドウ実行後
メンテナンスウィンドウ実行履歴

SSMエージェント確認
sh-5.2$ rpm -qa |grep amazon-ssm amazon-ssm-agent-3.3.551.0-1.x86_64
無事 EC2が停止状態でも自動的に起動させて、SSM Agentがアップデートできました。
5.最後に
SSM Agentアップデートを今回は例に出しましたが、停止しているEC2に対して何かしら定常的に実行させたいパターンは多々あると思います。
定期実行+バージョンアップデートが関わる内容は、即時確認がしづらかったり、検証するパターンも多かったりと工数が取られがちかと思います。
この記事が少しでも役に立ち、実装の手助けになれば幸いです。