AWS SSM Automationを使ってEC2のAlarmを自動作成(削除)する

#何がしたいのか
AutoScalingでEC2が増えたり減ったりしたとき、CloudWatch EventでSSM Automationを実行して自動的にAlarmを作成したり削除したりする。
ちなみにSSM AutomationではなくてLambdaを使ったほうが何かと便利[^1]なので、この記事は何らかの事情でLambdaを使いたくない人向けかも。

#使用するサービス
* Cloud Watch Alarm
* Cloud Watch Events
* SSM Automation(Systems Manager Automation)
* EC2 AutoScaling
* Cloudformation

#全体の流れなど
1. AutoScalingによりEC2 Instanceが作成または削除される
2. CloudWatch Eventがそれらを検知し、Targetに設定しておいたSSM Automationを実行
3. Automationに指定されたパラメータによって、Alarmを作成するか削除するか分岐

また、Cloudformation削除時にAlarmもきちんと削除されるようになっている

#Cloudformation Template 一部解説

全体は[nsk917/ec2-a3](https://github.com/nsk917/ec2-a3)に置いておきました。
ただ、Alarmのステータスが変わったときにSNSへメッセージを飛ばすような設定は省いてます。

以下、Templateを抜粋して少々解説をコメントで記載。

### CloudWatch Events
各イベントのサンプルは下記URLを参考
[Auto Scaling グループスケーリング時の CloudWatch イベント の取得](https://docs.aws.amazon.com/ja_jp/autoscaling/ec2/userguide/cloud-watch-events.html)


```yaml:template.yaml
  PutDeleteAlarmEventRule:
    Type: AWS::Events::Rule
    DependsOn: SSMAutomationCPUAlarm
    Properties:
      Description: Put and Delete Alarm
      State: ENABLED
      EventPattern:
        source:
          - aws.autoscaling
        # どのAutoScalingGroupからのEventなのかを指定する
        # 本来なら !Ref を使いたいところではあるが、AutoScalingGroupと循環参照になってしまうため下記のようにしている
        detail:
          AutoScalingGroupName:
            - EC2-A3-AutoScalingGroup
        # AutoScalingからのeventのdetail-typeのうち、
        # 以下を使ってEC2が起動/削除されたときにAutomationを実行させる
        detail-type:
          - 'EC2 Instance Launch Successful'
          - 'EC2 Instance Terminate Successful'
      Targets:
        - Id: SSMAutomationCPUAlarm
          Arn: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${SSMAutomationCPUAlarm}'
          RoleArn: !GetAtt CWEventsExecuteAutomationRole.Arn
          InputTransformer:
            InputPathsMap:
              DetailType: '$.detail-type'
              EC2InstanceId: '$.detail.EC2InstanceId'
            InputTemplate: '{ "DetailType":[<DetailType>], "EC2InstanceId":[<EC2InstanceId>] }'
```

### SSM Automation
一応マネジメントコンソールから手動実行も可能。
この点はLambdaよりはやりやすいだろうけど、自動化されているのでメリットはあんまりない。
[Systems Manager Automation アクションのリファレンス](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/automation-actions.html)

```yaml:template.yaml
  SSMAutomationCPUAlarm:
    Type: AWS::SSM::Document
    Properties:
      DocumentType: Automation
      Content:
        schemaVersion: '0.3'
        description: Put or Delete Alarm. EC2 High CPU Utilization
        parameters:
          DetailType:
            type: String
            description: 'EC2 Instance Launch Successful|EC2 Instance Terminate Successful'
            allowedPattern: 'EC2 Instance Launch Successful|EC2 Instance Terminate Successful'
          EC2InstanceId:
            type: String
            description: EC2 Instance Id
          AlarmNamePrefix:
            type: String
            description: High CPU Alarm Name Prefix
            default: High CPU Utilization Alarm
        mainSteps:
          # DetailTypeで振る舞いを分岐させるAction
          - name: BranchPutAlarmOrDeleteAlarm
            action: aws:branch
            inputs:
              Choices:
                - NextStep: PutAlarm
                  Variable: '{{ DetailType }}'
                  StringEquals: 'EC2 Instance Launch Successful'
                - NextStep: DeleteAlarm
                  Variable: '{{ DetailType }}'
                  StringEquals: 'EC2 Instance Terminate Successful'
              # 上記のChoicesに当てはまらない場合に実行されるAction
              # これがないと次のActionが実行されてしまうので、強制的に終了させるActionを指定する
              Default: DoNothing
   (以下略)
          - name: DoNothing
            action: aws:sleep
            isEnd: true
            inputs:
              Duration: PT1S
```

### AutoScalingGroup

```yaml:template.yaml
  AutoScalingGroup:
    Type: AWS::AutoScaling::AutoScalingGroup
    # このDependsOnを記述しておくことで、Cloudformationを雑に削除してもAlarmが残り続けたりしないようになっている。
    DependsOn: PutDeleteAlarmEventRule
    Properties:
      AutoScalingGroupName: EC2-A3-AutoScalingGroup
      DesiredCapacity: !Ref Min
      HealthCheckGracePeriod: 60
      HealthCheckType: EC2
      LaunchConfigurationName: !Ref LaunchConfiguration
      MinSize: !Ref Min
      MaxSize: !Ref Max
      VPCZoneIdentifier:
        - !Ref SubnetId
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: 1
        MaxBatchSize: 1
        PauseTime: PT0S
```

#参考URL
[(小ネタ) AutoScaling で増減した EC2 インスタンスに動的に CloudWatch Alarm を設定](https://www.m3tech.blog/entry/ec2-auto-alarm-lambda)
[Auto Scaling に対応した EC2 監視アラーム設定ツール](https://www.m3tech.blog/entry/ec2-auto-metric-alarms)[^2]

[^1]: EC2のTagを使ってS3やParameter StoreからAlarmの設定情報を取得など
[^2]: 1つ目の参考URLを見たあと、どうやったらもっと楽に管理できるだろうかと考えて注釈1[^1]に至ったあとに2つ目の記事があったことに気づいて「やっぱそうなるかー」と感じた