AWS Systems Managerでの定期コマンド実行をコード化してみた

こんにちは。AWSインフラ担当のモチです。
インフラを担当していると常に問題となるOSアップデート。
定期的にコマンド実行するのは人為リスクが伴うので、自動化してみました。
(アップデート後の再起動は含まれないので、それも自動化したlambdaは別記事で公開予定です)
やりたいこと
EC2に対して週次でコマンド実行し、結果をSlackに通知させたい
構成
AWS Systems Manager(以下、SSM)にはたくさんの機能がありますが、今回は以下の3つの機能を組み合わせています。
・SSM MaintenanceWindow
インスタンスに対するアクションの実行計画を定義します。
SSM RunCommand、SSM AutoMation、AWS Lambda、AWS StepFunctionがタスクとしてサポートされています。
(例)OSアップデートを火曜AM1時に実行、タグ付きのEC2がターゲット、コマンドはyum update
・SSM Document
マネージドインスタンスで実行するアクションを定義します。
コマンドやステップは実行時にパラメータで受け取ります。
(例)OSアップデートはRunCommandを使用
・SSM RunCommand
マネージドインスタンスにコマンド実行を行い、設定を安全にリモートで管理することができます。
※ 上記はAWS公式ガイドを参考に記載しています。
<イメージ図>

サンプルコード
<前提>
・EC2、SNSトピック、Chatbotは既に作成済み
・EC2にAmazonSSMManagedInstanceCoreのPolicyを含むRoleがアタッチされていること
・今回はEC2のタグでターゲットを指定
・このCloudWatchEventを設定すると、全部のRunCommand結果がSlackに通知されます
・ServerlessFrameworkの抜粋です
Resources:
# 火曜AM1時にOSアップデートコマンドを実行する
# ------------------------------------------------------------#
# MaintenanceWindow
# ------------------------------------------------------------#
MaintenanceWindow:
Type: AWS::SSM::MaintenanceWindow
Properties:
AllowUnassociatedTargets: true
Cutoff: 0
Duration: 1
Name: "maitenancewindow-Test"
Schedule: "cron(00 16 ? * mon *)" #火曜AM1時に実行
# ------------------------------------------------------------#
# MaintenanceWindowTarget
# ------------------------------------------------------------#
MaintenanceWindowTarget:
Type: AWS::SSM::MaintenanceWindowTarget
Properties:
Name: OSUpdateTarget
ResourceType: INSTANCE
Targets:
- Key: "tag:MaintenanceWindow"
Values:
- "tuesday"
WindowId: !Ref MaintenanceWindow
DependsOn: MaintenanceWindow
# ------------------------------------------------------------#
# MaintenanceWindowTask
# ------------------------------------------------------------#
MaintenanceWindowTask:
Type: AWS::SSM::MaintenanceWindowTask
Properties:
Name: OSUpdateTask
Priority: 1
Targets:
- Key: WindowTargetIds
Values:
- !Ref MaintenanceWindowTarget
TaskArn: OSUpdateScript
TaskType: RUN_COMMAND
WindowId: !Ref MaintenanceWindow
TaskInvocationParameters: #実行時にタスクに渡すパラメータ
MaintenanceWindowRunCommandParameters:
TimeoutSeconds: 600
Parameters: {"commands":["sudo yum update --security -y"]}
DependsOn: MaintenanceWindowTarget
# 実行ドキュメント
# ------------------------------------------------------------#
# SSM Document
# ------------------------------------------------------------#
documentOSUpdate:
Type: AWS::SSM::Document
Properties:
Content:
schemaVersion: '2.2'
description: 'Run a OSUpdateScript'
parameters:
commands:
type: String
description: "OSUpdateScript"
default: 'echo ParameterNothing'
mainSteps:
- action: aws:runShellScript
name: runCommands
inputs:
timeoutSeconds: '60'
runCommand:
- "{{ commands }}"
DocumentType: Command
Name: 'OSUpdateScript'
# RunCommandのコマンドステータスをChatbot経由でメール/Slackに通知
# --------------------------------------------------
# SSM用CloudWatchEvent
# --------------------------------------------------
EventsRuleforSSM:
Type: "AWS::Events::Rule"
Properties:
Name: Alert-OSUpdate
Description: "Alert to SNS topic when OSUpdate by SystemsmManager"
EventPattern: {
"source": [
"aws.ssm"
],
"detail-type": [
"EC2 Command Status-change Notification"
]
}
Targets:
- Arn: arn:aws:sns:xxx:xxxxxxxxxxxxxx:xxxxxxxxx
Id: OSupdateEventTarget
RunCommandが実行されると、こんな感じでInprogressとSuccessのタイミングでSlackに通知がきます。

コマンドを変えればいろいろと活用できそうです。
SSMは便利で面白い機能がたくさんあるので、今後も使っていきたいと思います!