LoginSignup
6
1

More than 3 years have passed since last update.

AWS: lambdaを使わないでEC2の定期起動・定期停止するCloudFormationを作る

Last updated at Posted at 2020-07-29

はじめに

EventBridgeを使ってEC2の定期起動・停止するCFnを作る時たくさん悩んだので、未来の私がCFn見直した時に思い出せるようにするためのメモ。

※投稿してしまったのですが確認したら今CFnが思うとおりに動いていないので修正中です(2020/07/30)
=>修正しました!(2020/08/13)

CloudFormation

1. このCFnでつくられるもの。

■ CloudWatch Event Rule

  • 起動させるイベントルール
  • 停止させるイベントルール


■ IAM Role

  • 自動化用のAutomationAssumeRole
    • AWSマネージドポリシー
  • 起動イベント用のロール
    • カスタムポリシー
  • 停止イベント用のロール
    • カスタムポリシー

2. つくったテンプレート。

AWSTemplateFormatVersion: 2010-09-09
Description: EC2_Start_Stop

Parameters: 
  EC2InstanceID1:
    Type: String
    Description: EC2InstanceID1
    Default: "i-xxxxxxxxxxxxxxx"
  EC2InstanceID2:
    Type: String
    Description: EC2InstanceID2
    Default: "i-yyyyyyyyyyyyyy"

  StartTime:
    Type: String
    Description: start time of Ec2
    Default: 00 00 ? * MON-FRI *
  StopTime:
    Type: String
    Description: stop time of Ec2
    Default: 00 09 ? * MON-FRI *




Resources:
# ------------------------------------------------------------#
# Event
# ------------------------------------------------------------# 
  EventRuleEc2Start:
    Type: AWS::Events::Rule
    Properties:
      Name: Ec2StartRule
      Description: !Sub ${StartTime} Start
      ScheduleExpression: !Sub 'cron(${StartTime})'
      State: ENABLED
      Targets:
        - Arn: arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StartEC2Instance:$DEFAULT
          Id: TargetStartEC2Instance1
          RoleArn: !Sub ${StartEc2Role.Arn}
          Input: !Sub "{\"InstanceId\":[\"${EC2InstanceID1}\"],\"AutomationAssumeRole\":[\"${EC2AmazonSSMAutomationRole.Arn}\"]}"
        - Arn: arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StartEC2Instance:$DEFAULT
          Id: TargetStartEC2Instance2
          RoleArn: !Sub ${StartEc2Role.Arn}
          Input: !Sub "{\"InstanceId\":[\"${EC2InstanceID2}\"],\"AutomationAssumeRole\":[\"${EC2AmazonSSMAutomationRole.Arn}\"]}"

  EventRuleEc2Stop:
    Type: AWS::Events::Rule
    Properties:
      Name: Ec2StopRule
      Description: !Sub ${StopTime} Stop 
      ScheduleExpression: !Sub 'cron(${StopTime})'
      State: ENABLED
      Targets:
        - Arn: arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StopEC2Instance:$DEFAULT
          Id: TargetStopEC2Instance1
          RoleArn: !Sub ${StopEc2Role.Arn}
          Input: !Sub "{\"InstanceId\":[\"${EC2InstanceID1}\"],\"AutomationAssumeRole\":[\"${EC2AmazonSSMAutomationRole.Arn}\"]}"
        - Arn: arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StopEC2Instance:$DEFAULT
          Id: TargetStopEC2Instance2
          RoleArn: !Sub ${StopEc2Role.Arn}
          Input: !Sub "{\"InstanceId\":[\"${EC2InstanceID2}\"],\"AutomationAssumeRole\":[\"${EC2AmazonSSMAutomationRole.Arn}\"]}"


# ------------------------------------------------------------#
# AutomationAssumeRole
# ------------------------------------------------------------# 
  EC2AmazonSSMAutomationRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - ssm.amazonaws.com
              - ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole
      Path: "/"



#------------------------------------------------------------#
# StartEc2
# ------------------------------------------------------------# 
  StartEc2Role:    
    Type: AWS::IAM::Role
    Properties: 
      RoleName: "StartEC2Role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "events.amazonaws.com"
            Action: 
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: StartEc2Role_policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ssm:StartAutomationExecution
                Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-StartEC2Instance:$DEFAULT
              - Effect: Allow
                Action: "iam:PassRole"
                Resource: !GetAtt EC2AmazonSSMAutomationRole.Arn
                Condition: 
                  StringLikeIfExists: 
                    iam:PassedToService: ssm.amazonaws.com

# ------------------------------------------------------------#
# StopEc2
# ------------------------------------------------------------# 
  StopEc2Role:    
    Type: AWS::IAM::Role
    Properties: 
      RoleName: "StopEC2Role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "events.amazonaws.com"
            Action: sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: StopEc2Role_policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ssm:StartAutomationExecution
                Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-StopEC2Instance:$DEFAULT
              - Effect: Allow
                Action: "iam:PassRole"
                Resource: !GetAtt EC2AmazonSSMAutomationRole.Arn
                Condition: 
                  StringLikeIfExists: 
                    iam:PassedToService: ssm.amazonaws.com

3. テンプレートのなかみ。

■ parameter

Parameters: 
  EC2InstanceID1:
    Type: String
    Description: EC2InstanceID1
    Default: "i-xxxxxxxxxxxxxxx"
  EC2InstanceID2:
    Type: String
    Description: EC2InstanceID2
    Default: "i-yyyyyyyyyyyyyy"

  StartTime:
    Type: String
    Description: start time of Ec2
    Default: 00 00 ? * MON-FRI *
  StopTime:
    Type: String
    Description: stop time of Ec2
    Default: 00 09 ? * MON-FRI *

定期起動・停止したいインスタンスのインスタンスIDと、実行する時間をparameterで出してます。

同じ時間で起動・停止させるEC2インスタンス2つに対して設定したかったのでIDを入力するところは2つ。
時間はcron式で指定します。このテンプレートはデフォルトで日本時間の平日9:00に起動、18:00に停止するようになってます。

■ イベント

  EventRuleEc2Start:
    Type: AWS::Events::Rule
    Properties:
      Name: Ec2StartRule
      Description: !Sub ${StartTime} Start
      ScheduleExpression: !Sub 'cron(${StartTime})'
      State: ENABLED
      Targets:
        - Arn: arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StartEC2Instance:$DEFAULT
          Id: TargetStartEC2Instance1
          RoleArn: !Sub ${StartEc2Role.Arn}
          Input: !Sub "{\"InstanceId\":[\"${EC2InstanceID1}\"],\"AutomationAssumeRole\":[\"${EC2AmazonSSMAutomationRole.Arn}\"]}"
        - Arn: arn:aws:ssm:ap-northeast-1::automation-definition/AWS-StartEC2Instance:$DEFAULT
          Id: TargetStartEC2Instance2
          RoleArn: !Sub ${StartEc2Role.Arn}
          Input: !Sub "{\"InstanceId\":[\"${EC2InstanceID2}\"],\"AutomationAssumeRole\":[\"${EC2AmazonSSMAutomationRole.Arn}\"]}"

AWS::Events::Rule - AWS CloudFormation

トリガーとなるイベントの作成。

Targetsにルールがトリガーされたときに呼び出されるリソースをリスト型で書いていきます。

EventRuleEc2Startでは起動させるロールを割り当てたいので、ArnStartEC2Instanceを参照させて、RoleArnにはルールがトリガーされた時にこのターゲットに使用されるIAMロールの ARNを書きます。ここには、同じCFn内のStartEc2Roleを使いたいので、!Sub ${StartEc2Role.Arn}でStartEc2RoleのARNを参照しています。(!Sub.ArnでARN取ってこれるの知らなかった。)

同様にEventRuleEc2Stopでは停止させるイベントを作成します。Startの部分がStopになるくらいなので割愛。

■ 自動化用ロール

  EC2AmazonSSMAutomationRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
              - ssm.amazonaws.com
              - ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole
      Path: "/"

マネージドポリシーのAmazonSSMAutomationRoleを作成します。

AssumeRolePolicyDocumentにこのロールに関連付けられている信頼ポリシーを書くのですが、ssm.amazonaws.comec2.amazonaws.comをこのロールを引き受けることができるエンティティに指定したいのでServiceにリスト型で書いておきます。

■ 起動・停止用ロール

  StartEc2Role:    
    Type: AWS::IAM::Role
    Properties: 
      RoleName: "StartEC2Role"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "events.amazonaws.com"
            Action: 
              - sts:AssumeRole
      Path: /
      Policies:
        - PolicyName: StartEc2Role_policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ssm:StartAutomationExecution
                Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/AWS-StartEC2Instance:$DEFAULT
              - Effect: Allow
                Action: "iam:PassRole"
                Resource: !GetAtt EC2AmazonSSMAutomationRole.Arn
                Condition: 
                  StringLikeIfExists: 
                    iam:PassedToService: ssm.amazonaws.com

AWS::IAM::Role - AWS CloudFormation

起動・停止用のカスタムロールを作成します。

イベントをトリガーにしているので信頼されるエンティティはevents.amazonaws.com

そして、ロールにStartEc2Role_policyというインラインポリシーを追加させるためにPolicies以下に定義していきます。AWSサービスにロールを渡すにはPassRoleのアクセス許可が必要なので、ここでEC2AmazonSSMAutomationRoleにアクセス許可を付与しています。

イベントと同じくStopの方は割愛。


4. テンプレート展開してみる。

指定した時間通り動いた!わーい!

参考

公式ドキュメントと先人と先輩に感謝。

おわりに

CloudFormationでリソースを作成できても一向にEC2が起きてこなかったり、1つは起動するのにもう1つが起動しなかったりとたくさんはまりました。

間違いや修正点等あったら教えてください!

早くCloudFormationと仲良くなりたい、、

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1