エンジニア

2021.10.12

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

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は便利で面白い機能がたくさんあるので、今後も使っていきたいと思います!

一覧に戻る