🛑

AWS CloudFormation で SSM Automation を利用したインスタンス停止処理

2023/03/03に公開

はじめに

以前、AWS CloudFormation で踏み台サーバー構築という記事を書きました。
このような踏み台サーバーなどを EC2 で作った場合は、夜間など未利用の時間は止めたくなることが多くあります。
今回は SSM Automation を利用してインスタンスを自動で起動/停止する CloudFormation テンプレートを紹介します。

EC2 の夜間停止用テンプレート

EC2 の夜間停止用テンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Rules for starting and stopping EC2 using SSM Automation

# Rules for starting and stopping EC2 using SSM Automation

Parameters:
  TargetEC2Id:
    Description: Target EC2 ID
    Type: String
    Default: i-XXXXXXXXXXXXXXXXX

Resources:
  # SSM Automation EC2 起動/停止用 IAM ロール
  InstanceMaintenanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${TargetEC2Id}-maintenance
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ssm.amazonaws.com
            Action: sts:AssumeRole
      # ManagedPolicyArns:
      Policies:
        - PolicyName: AllowAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ec2:StartInstances
                  - ec2:StopInstances
                Resource: !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${TargetEC2Id}
              - Effect: Allow
                Action: ec2:DescribeInstanceStatus
                Resource: '*'

  # SSM Automation 実行 EventBridge 用 IAM ロール
  InstanceMaintenanceEventRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${TargetEC2Id}-maintenance-event
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: AllowAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: ssm:StartAutomationExecution
                Resource:
                  - !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StartEC2Instance:*
                  - !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StopEC2Instance:*
              - Effect: Allow
                Action: iam:PassRole
                Resource: !GetAtt InstanceMaintenanceRole.Arn
                Condition:
                  StringLikeIfExists:
                    iam:PassedToService: ssm.amazonaws.com

  # SSM Automation 実行 EventBridge ルール
  InstanceStartEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub ${TargetEC2Id}-start-instance
      Description: !Sub Start EC2(${TargetEC2Id}) instance
      ScheduleExpression: cron(55 23 ? * 1-5 *) # UTC Cron 式, JST 平日 8:55 起動, 1:Sun-7:Sat
      State: ENABLED
      Targets:
        - Arn: !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StartEC2Instance:$DEFAULT
          Id: start-instance
          RoleArn: !GetAtt InstanceMaintenanceEventRole.Arn
          Input: !Sub
            - |
              {
                "InstanceId": [ "${TargetEC2Id}" ],
                "AutomationAssumeRole": [ "${AutomationAssumeRole}" ]
              }
            - AutomationAssumeRole: !GetAtt InstanceMaintenanceRole.Arn
  InstanceStopEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub ${TargetEC2Id}-stop-instance
      Description: !Sub Stop EC2(${TargetEC2Id}) instance
      ScheduleExpression: cron(5 9 ? * * *) # UTC Cron 式, JST 毎日 18:05 停止
      State: ENABLED
      Targets:
        - Arn: !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StopEC2Instance:$DEFAULT
          Id: stop-instance
          RoleArn: !GetAtt InstanceMaintenanceEventRole.Arn
          Input: !Sub
            - |
              {
                "InstanceId": [ "${TargetEC2Id}" ],
                "AutomationAssumeRole": [ "${AutomationAssumeRole}" ]
              }
            - AutomationAssumeRole: !GetAtt InstanceMaintenanceRole.Arn

以降、テンプレート内容を補足します。

パラメーター

  • TargetEC2Id : 夜間停止をする EC2 の ID i-XXXXXXXXXXXXXXXXX を指定してください

EC2 起動/停止用ロール

EC2 の起動/停止を行うためのロールを作成します。
同一テンプレートを使いまわした際のロール名の重複を避けるため、ロール名にインスタンス ID を含むようにしています。

  # SSM Automation EC2 起動/停止用 IAM ロール
  InstanceMaintenanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${TargetEC2Id}-maintenance

指定した EC2 のみ起動/停止できるように対象リソースを絞り込んでいます。

              - Effect: Allow
                Action:
                  - ec2:StartInstances
                  - ec2:StopInstances
                Resource: !Sub arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/${TargetEC2Id}

SSM Automation 実行 EventBridge 用ロール

EventBridge のルールを利用して、 SSM Automation を実行するためのロールを作成します。

  # SSM Automation 実行 EventBridge 用 IAM ロール
  InstanceMaintenanceEventRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${TargetEC2Id}-maintenance-event

EC2 起動用 SSM Automation 実行 EventBridge ルール

SSM AutomationEventBridge から呼び出します。
平日の8:55に起動するように Cron 式で指定しています。
時間は業務に合わせて適宜修正ください。

  # SSM Automation 実行 EventBridge ルール
  InstanceStartEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub ${TargetEC2Id}-start-instance
      Description: !Sub Start EC2(${TargetEC2Id}) instance
      ScheduleExpression: cron(55 23 ? * 1-5 *) # UTC Cron 式, JST 平日 8:55 起動, 1:Sun-7:Sat

EC2 停止用 SSM Automation 実行 EventBridge ルール

停止は毎日行うようにしています。
こちらも業務に合わせて適宜修正ください。

  InstanceStopEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub ${TargetEC2Id}-stop-instance
      Description: !Sub Stop EC2(${TargetEC2Id}) instance
      ScheduleExpression: cron(5 9 ? * * *) # UTC Cron 式, JST 毎日 18:05 停止

RDS インスタンスの夜間停止用テンプレート

RDS のインスタンス用です。
RDS クラスターを停止する場合は、RDS クラスター用の SSM Automation に書き換える必要があるため注意ください。

RDS インスタンスの夜間停止用テンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: Rules for starting and stopping RDS using SSM Automation

# Rules for starting and stopping RDS using SSM Automation

Parameters:
  RoleName:
    Description: DB maintenance event role name
    Type: String
  TargetDBInstanceID:
    Description: Target DB Instance ID
    Type: String

Resources:
  # SSM Automation RDS 起動/停止用 IAM ロール
  InstanceMaintenanceRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${RoleName}-maintenance
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ssm.amazonaws.com
            Action: sts:AssumeRole
      # ManagedPolicyArns:
      Policies:
        - PolicyName: AllowAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - rds:StopDBInstance
                  - rds:StartDBInstance
                Resource: !Sub arn:aws:rds:${AWS::Region}:${AWS::AccountId}:db:${TargetDBInstanceID}
              - Effect: Allow
                Action: rds:DescribeDBInstances
                Resource: '*'

  # SSM Automation 実行 EventBridge 用 IAM ロール
  InstanceMaintenanceEventRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub ${RoleName}-db-maintenance-event
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: AllowAccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: ssm:StartAutomationExecution
                Resource:
                  - !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StartRdsInstance:*
                  - !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StopRdsInstance:*
              - Effect: Allow
                Action: iam:PassRole
                Resource: !GetAtt InstanceMaintenanceRole.Arn
                Condition:
                  StringLikeIfExists:
                    iam:PassedToService: ssm.amazonaws.com

  # SSM Automation 実行 EventBridge ルール
  InstanceStartEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub ${RoleName}-start-rds-instance
      Description: !Sub Start DB(${TargetDBInstanceID}) instance
      ScheduleExpression: cron(35 23 ? * 1-5 *) # UTC Cron 式, JST 平日 8:35 起動, 1:Sun-7:Sat
      State: ENABLED
      Targets:
        - Arn: !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StartRdsInstance:$DEFAULT
          Id: start-rds-instance
          RoleArn: !GetAtt InstanceMaintenanceEventRole.Arn
          Input: !Sub
            - |
              {
                "InstanceId": [ "${TargetDBInstanceID}" ],
                "AutomationAssumeRole": [ "${AutomationAssumeRole}" ]
              }
            - AutomationAssumeRole: !GetAtt InstanceMaintenanceRole.Arn
  InstanceStopEventsRule:
    Type: AWS::Events::Rule
    Properties:
      Name: !Sub ${RoleName}-stop-rds-instance
      Description: !Sub Stop DB(${TargetDBInstanceID}) instance
      ScheduleExpression: cron(35 9 ? * * *) # UTC Cron 式, JST 毎日 18:35 停止
      State: ENABLED
      Targets:
        - Arn: !Sub arn:aws:ssm:${AWS::Region}::automation-definition/AWS-StopRdsInstance:$DEFAULT
          Id: stop-rds-instance
          RoleArn: !GetAtt InstanceMaintenanceEventRole.Arn
          Input: !Sub
            - |
              {
                "InstanceId": [ "${TargetDBInstanceID}" ],
                "AutomationAssumeRole": [ "${AutomationAssumeRole}" ]
              }
            - AutomationAssumeRole: !GetAtt InstanceMaintenanceRole.Arn

以降、 EC2 と異なる点の補足をします。

パラメーター

  • RoleName : RDS 起動/停止用のロール名を指定します
    • EC2 のようにロール名にインスタンス ID を利用すると64文字の制限に収まらないため明示的に指定します
  • TargetDBInstanceID : 夜間停止をする RDS の DB インスタンス ID を指定してください

さいごに

EC2 や RDS のインスタンスを自動で起動/停止する CloudFormation テンプレートの紹介でした。
昔は Lambda で行うことが多かったのですが、今は SSM Automation に準備されているタスクも多いため、オートメーションを活用して運用を簡素化したいと思います。

モリサワ Tech Blog

Discussion