EC2インスタンスの自動起動/停止をSystems Managerから実行する


はじめに

とある案件で新規にAWSアカウントを作成し、それなりに環境構築を完了。
アプリケーション側の開発がある程度進んだところで、検証環境は土日夜間は誰も触らないから自動起動/停止を実装して欲しいとリクエストされました。

とりあえずググった

以前別案件でも同じ仕組みを導入したことがあったので、まぁ同じようにやればいいか…と調べてみると最近は主流のやり方が異なる模様。以前はLambdaでEC2を制御するコードを書いて、Lambdaの呼び出しをCloudWatchからコントロールしてましたが、現在はSystems Managerと連携してEC2を制御するほうがシンプルで簡単らしいです。

実装方法を読むとインスタンスid直指定であればCloudWatchイベントだけで出来るようですが、今後を考えると出来ればタグで制御したい。皆同じことを考えるはず…と調べたらあっさり見つかりました。

タグを指定するだけでEC2インスタンスを自動起動・停止する
今回の実装は主にこちらの記事を参考にさせていただいています。

ちょっといじった

参考にした記事では起動/停止の時間をValueに個別に設定してインスタンス単位で制御するようになっていましたが、自分の要件だと環境単位で起動/停止の時間はどのインスタンスも同じなので、特定タグ「State-Schdule-Stag:enable」があればStop/Startどちらも動くようにちょっとだけ修正します。

停止

description: 'StopEC2Instances Using Tags:state-scheduler-stag'
schemaVersion: '0.3'
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
  StopStart:
    type: String
    default: enable
    description: (Required) enable
    allowedValues:
      - enable
  AutomationAssumeRole:
    type: String
    description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
    default: ''
mainSteps:
  - name: StopEC2Instances
    action: 'aws:executeAwsApi'
    inputs:
      Service: ssm
      Api: StartAutomationExecution
      DocumentName: AWS-StopEC2Instance
      TargetParameterName: InstanceId
      Targets:
        - Key: 'tag:state-scheduler-stag'
          Values:
            - '{{ StopStart }}'

起動

description: 'StartEC2Instances Using Tags:state-scheduler-stag'
schemaVersion: '0.3'
assumeRole: '{{ AutomationAssumeRole }}'
parameters:
  StopStart:
    type: String
    default: enable
    description: (Required) enable
    allowedValues:
      - enable
  AutomationAssumeRole:
    type: String
    description: (Optional) The ARN of the role that allows Automation to perform the actions on your behalf.
    default: ''
mainSteps:
  - name: StartEC2Instances
    action: 'aws:executeAwsApi'
    inputs:
      Service: ssm
      Api: StartAutomationExecution
      DocumentName: AWS-StartEC2Instance
      TargetParameterName: InstanceId
      Targets:
        - Key: 'tag:state-scheduler-stag'
          Values:
            - '{{ StopStart }}'

実装した

ssmドキュメントの投入や手動実行での動作確認は、先ほどの参考リンクの手順を元に実装します。CloudWatchイベントからの呼び出しには別途実行Roleの割り当てやcron式の記述が必要ですが、それらは以下の記事が分かりやすいです。なお末尾でも触れられていますが、cronで曜日指定する場合「日フィールドと曜日フィールドを同時に指定することはできない」ので注意です。

[AWS] CloudWatchでEC2の自動起動・停止をスケジュールする

スケジュール登録すると動かない…

これで問題ないはず!と終わったつもりでいましたが、翌日になって状況確認するとstop/startどちらも動いていません…
手動では動いていたのに何故?とSystems Manager > 自動化(オートメーション) のところにある実行履歴を確認すると、見慣れぬエラーが発生しています。

どうやらCloudWatchイベントに割り当てたロールに 「tag:GetResource」の権限がない と言われているようです。

tag:getresourceの権限を実行roleに追加

そもそもtag:getresourceって何?とググってみると、公式のドキュメントが出てきます。

リソースグループを使用するための前提条件

ドキュメントを斜め読みすると「SSMからタグ情報を取得する時はリソースグループおよびタグエディタオペレーションを呼び出すので、実行ロールにtag:getresourceの権限が必要」という意味?のようです。割り当てたSSMロールにアタッチした「AmazonSSMAutomationRole」ポリシーに「ec2:DescribeTags」があるのになんで?と思っていましたが、タグを読むために使われるところが違う?という事でしょうか。

とりあえずIAMから「tag:getresource」が含まれているポリシーを検索すると「ResourceGroupsandTagEditorReadOnlyAccess」がちょうど良さそうです(「AWSResourceGroupsReadOnlyAccess」でもいけそうでしたが、なるべく付与する権限は少なくしておいた方が安全でしょう)このポリシーをCloudWatchイベントを実行するロールにアタッチします。

無事動いた

設定変更後翌日になって動作を確認すると、無事に自動起動/停止が動いているのを確認できました。これで一件落着です。

最後に

呼び出す時刻の制御はCloudWatchイベント側でやるので、SSMドキュメント内でtagのvalueを判定してstopなら停止/startなら開始のapiを呼ぶ…ように改良できれば、登録するドキュメントも一つで完結してスマートかなと思います。

あとタグエディタとか今更ながら存在を知ったんですが、これはかなり便利ですね。マネジメントコンソールからの操作だと都度「更新」しないとEC2で変更したタグ情報が確認できずに不便を感じてたのですが、タグエディタ側から操作した方がレスポンス早くて効率も良さそうです。