スケジュールに従ってEC2を自動起動・自動停止する(SSMAutomation編)


Lambda編の記事ではPythonのコードをLambdaに登録してCloudWatchEventsから呼び出してEC2起動/停止のスケジューリングを実現しました。一昔前まではこの手法が王道だったようですが、現在はコードを書かずともCloudWatchEvents + SystemsManager(SSM)の組み合わせでできちゃいます。こちらの方法も試してみました。

IAMロールの作成

あらかじめIAMのメニューからロール、ポリシーを作成します。以下の権限が必要となります。

  • CloudWatchからSSMのオートメーションを実行するための権限
  • CloudWatchからEC2を停止/起動するための権限

ロール作成時、信頼されたエンティティはCloudWatch Eventsを選択し、以下のポリシーで作成します。
まず、ssm:StartAutomationExecutionでSSMAutomationの実行権限を与えていて、対象のドキュメントをEC2停止/起動に限定しています。<account_id>の箇所は適宜読み替えてください。$DEFAULTはバージョン指定です。

次に、EC2停止/起動の権限を付与しています。ec2:DescribeInstanceStatusは起動/停止後のステータスチェックに使われているようです。この権限がなくともEC2の起動/停止はされますが、SSMAutomationの実行結果は「失敗」となるので付与しておきます。

※ポリシーの定義が面倒な場合はAmazonSSMAutomationRoleの管理ポリシーを利用しても良いかと思います。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:StartAutomationExecution"
            ],
            "Resource": [
                "arn:aws:ssm:ap-northeast-1:<account_id>:automation-definition/AWS-StartEC2Instance:$DEFAULT",
                "arn:aws:ssm:ap-northeast-1:<account_id>:automation-definition/AWS-StopEC2Instance:$DEFAULT"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:StartInstances",
                "ec2:StopInstances",
                "ec2:DescribeInstanceStatus"
            ],
            "Resource": "*"
        }
    ]
}

CloudWatch Eventsにスケジュールを登録

Lambda編と違うのはターゲットの選択です。種類は「SSMAutomation」を選択して、AWS-StartEC2InstanceまたはAWS-StopEC2Instanceのドキュメントを選択します。あとは、対象のEC2のインスタンスID、あらかじめ作成したIAMロールを選択すればOKです。(cronのスケジュールは適当です)

ちなみに、ドキュメントのパラメータ指定にあるAutomationAssumeRoleは、SSMがドキュメントを実行する場合の権限を個別に割り当てたい場合に利用するようです。(※後述)

実行結果を確認

Systems Manger → 自動化の画面から履歴を確認することができます。
エラーになった場合は、実行IDをクリックして中身を確認してみましょう。
CloudWatch Eventsにスケジュールしたのにそもそも履歴が出ない場合は、おそらくSSMAutomationの実行権限が不足していますので、IAM設定を見直しましょう。

まとめ

今回はCloudWatchEvents + SystemsManagerでEC2自動起動・自動停止を試してみました。コードを書く必要がなく、簡単に設定できるのでとても便利ですね。個人的には、IAMの理解が深まった検証になりました。

簡単に設定できてコスト削減に直結しますので、積極的に使っていきたいですね。前回のLambda編と合わせて参考になれば幸いです。

AutomationAssumeRoleを指定する理由

2021/4/20追記
AutomationAssumeRoleを指定する意味がよくわからなかったのでサポートに問い合わせてみました。
公式ドキュメントだと以下のページが参考になります。

委任管理者を使用して、オートメーションを実行する
ランブックの詳細リファレンス - AWS-StartEC2Instance

まとめると次のようになります。

  • AutomationAssumeRoleを指定しない場合、Systems Manager オートメーションはこのドキュメントを実行するユーザーのアクセス許可を使用する

  • AWSとしてはAutomationAssumeRoleを指定して(権限を分けて)実行することを推奨している

  • AutomationAssumeRoleに指定するロールの権限は管理ポリシーのAmazonSSMAutomationRoleが推奨されている

つまり、AutomationAssumeRoleを利用して権限を分離し、最小にすることがベストプラクティスとなっています。AutomationAssumeRoleを指定しない場合、CloudWatch Eventsには本来必要のないEC2起動/停止の権限を割り当てていることとなり管理上わかりづらくなるためです。

絵にするとこんな感じでしょうか。

CloudWatch Eventsのロールには、SSMAutomationにPathRoleする権限が必要なので注意。
PathRoleについては以下の記事が参考になります。

IAM ロールの PassRole と AssumeRole をもう二度と忘れないために絵を描いてみた

冒頭のポリシーからEC2関連を削除してPassRoleを追加しています。パスするロールはssm.amazonaws.comを信頼したものを管理ポリシーと同じ名前で作成しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ssm:StartAutomationExecution"
            ],
            "Resource": [
                "arn:aws:ssm:ap-northeast-1:<account_id>:automation-definition/AWS-StartEC2Instance:$DEFAULT",
                "arn:aws:ssm:ap-northeast-1:<account_id>:automation-definition/AWS-StopEC2Instance:$DEFAULT"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": "arn:aws:iam::<account_id>:role/AmazonSSMAutomationRole",
            "Condition": {
                "StringLikeIfExists": {
                    "iam:PassedToService": "ssm.amazonaws.com"
                }
            }
        }
    ]
}

CloudWatch Eventsのルールで指定するAutomationAssumeRoleにはIAMロールのARNを入力すればOKです。

参考リンク

CloudWatch Events と Systems Manager で EC2の起動/停止をスケジュール化する

委任管理者を使用して、オートメーションを実行する

IAM ロールの PassRole と AssumeRole をもう二度と忘れないために絵を描いてみた

ランブックの詳細リファレンス - AWS-StartEC2Instance

ランブックの詳細リファレンス - AWS-StopEC2Instance