AWS Budget action で予算を超えたAWSアカウントに制御アクションを実行する

記事タイトルとURLをコピーする

SRE部 佐竹です。
今回は新しい機能、AWS Budgets Actions (Budget action) について記載します。

はじめに

本日は、以下のアナウンスを受け、Budget action を検証した結果を記載します。

aws.amazon.com

AWS Budgets Actions とは

AWS Budgets Actions は、AWS Budgets で設定した予算(Budget)の閾値を超えた場合に、AWS Budget の機能内で完結してアクションを実行することができる機能です。

今まででも AWS Budgets で閾値を超えた場合、SNSによる通知が行えたためそれをトリガーに何らかの処理を実行することはできました。今回のリリースでは、AWS Budgets の中で完結してアクションができるというものです。

実行可能なアクションは現在以下の3種類です。

  1. Identity and Access Management (IAM) ポリシーの適用アクション
  2. Service Control ポリシー (SCP) の適用アクション
  3. 実行中のインスタンス (EC2 または RDS) の停止アクション

今回このうち IAM ポリシーの適用アクションと、EC2 Instance の停止アクションを検証しました。

なお、AWSの公式リリースでは Budgets Actions と複数形になっていますが、コンソールや公式ドキュメントでは Budget action と単数形で表示されています。ややこしいので、ここではサービスとその機能の全体を Budgets Actions と記載し、実際設定時には Budget action を用いることにします。

公式ドキュメント(ユーザガイド)は「こちら」です。2020年10月29日現在は、英語ページのみが存在します。

Budget action を設定する

f:id:swx-satake:20201029132129p:plain

AWS Budgets にて、 Monthly Budget を設定したものを変更していきます。本 Budget は、月額のAWS利用料が $36.00 を超えたらアラートをあげるという予算設定です。既に今月は$35を超える利用料があり、後少しで予算を超えてしまうことがわかります。

画面右上にある「Edit Budget」から編集画面に入ります。

f:id:swx-satake:20201029132433p:plain

次の画面は、そのまま右下の「Configure thresholds」を押下して進みます。

f:id:swx-satake:20201029132612p:plain

「Define your budget threshold」で、閾値を設定します。今回は Actual cost かつ 100% で設定しました。なお Forecasted Cost でも設定頂けます。

「Set up your notifications」は SNS に対して email 通知を送る設定にしました。SNSの通知を設定しておくことで、Budget action が実行されたタイミングで通知を受け取れます。

f:id:swx-satake:20201029132922p:plain

「Add a budget action」を押下すると、Budget action の設定画面が現われます。

AWS Budgets requires specific IAM permissions to execute an action on your behalf. Selecting an IAM role with incorrect permissions will prevent AWS Budgets from executing actions. For the specific permissions needed, reference here

上記記載の英文 here にURLリンクがあります。このリンクを押下して記載されている情報を参考に Budget action 用の IAM Role を作成します。以下の情報はマネジメントコンソールからもコピーできますが、念のため記載します。

  • Trust policy
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "budgets.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
  • Permissions policies
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ec2:DescribeInstanceStatus",
        "ec2:StartInstances",
        "ec2:StopInstances",
        "iam:AttachGroupPolicy",
        "iam:AttachRolePolicy",
        "iam:AttachUserPolicy",
        "iam:DetachGroupPolicy",
        "iam:DetachRolePolicy",
        "iam:DetachUserPolicy",
        "organizations:AttachPolicy",
        "organizations:DetachPolicy",
        "rds:DescribeDBInstances",
        "rds:StartDBInstance",
        "rds:StopDBInstance",
        "ssm:StartAutomationExecution"
      ],
      "Resource": "*"
    }
  ]
}

作成が完了したら、IAM Role を指定します。

f:id:swx-satake:20201029133358p:plain

次に action type を選択します。冒頭で紹介しました以下の3つのアクションから選択可能ですが、本AWSアカウントは Organizations の Root ではないため、SCPの設定は選択できません。

  1. Identity and Access Management (IAM) ポリシーの適用アクション
  2. Service Control ポリシー (SCP) の適用アクション
  3. 実行中のインスタンス (EC2 または RDS) の停止アクション

そのため、「IAMポリシー」もしくは「EC2 または RDSの停止」アクションを選択します。今回はどちらのアクションも実行します。

参考までに、Organizations の Root アカウントで確認したところ、以下のように SCP のアクションも選択可能でした。

f:id:swx-satake:20201029140542p:plain

ただしこの場合の注意なのですが、「対象とする EC2 Instance と RDS DB.Instance は、対象のAWSアカウントの AWS Budgets」でないと見えません。つまり、Organizations の Root であれば、 Root アカウントに構築されたインスタンスしか制御ができない、となります。

そのため「複数のAWSアカウントにおいて EC2 Instance の停止を行いたい場合」は、「各AWSアカウントの AWS Budgets にそれぞれ設定を行わなければならない」となります。

Identity and Access Management (IAM) ポリシーの適用アクション

IAM ポリシーはコンソールに Select the IAM policy you want to apply と記載されている通り、どの IAM ポリシーを制御用として使うか決める必要があります。つまり、設定において制御用の IAM ポリシーを用意する必要があります。今回は、AWSが管理しているポリシーである arn:aws:iam::aws:policy/AWSDenyAll を利用します。以下の通りの表記で「何もできなくする」というポリシーになっています、

  • arn:aws:iam::aws:policy/AWSDenyAll
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "*"
            ],
            "Effect": "Deny",
            "Resource": "*"
        }
    ]
}

補足ですが、これはつまり IAM ポリシーでは「明示的なDeny(拒否)」が最も強いことを Budget action において利用しています。「何でもできるAWSの操作権限」を持っていたとしても、上記のポリシーがアタッチされてしまうと強制的に何もできなくなります。

また、SCP を利用した制御でも同様のことが言えます。明示的な拒否や SCP についての基本的な内容は以下のブログに記載していますため、よろしければご参照ください。

blog.serverworks.co.jp

f:id:swx-satake:20201029133826p:plain

選択したポリシーを、IAM User, Group, Role のうち、どれに適用を行うのか選択できます。今回は、 satake という名前の IAM User を選択しました。

f:id:swx-satake:20201029133727p:plain

最後に Do you want to automatically execute this action when this threshold is exceeded? に対して No か Yes を選択します。デフォルト No になっています。これは「予算の閾値を超えた場合に、自動的にこのアクションを実行するかどうか」という問いです。

今回、IAM ポリシーの制御では「No」で設定しました。

実行中のインスタンス (EC2 または RDS) の停止アクション

f:id:swx-satake:20201029134904p:plain

EC2 Instance では Region とその Region 内の EC2 Instance 選択します。Select all instance IDs を押下すると、全てのインスタンスが選択可能です。今回は全てのインスタンスを選択しました。

f:id:swx-satake:20201029135545p:plain

自動的なアクションの実行は「Yes」で設定しました。

設定まとめ

  • IAM ポリシーの適用アクション
    • satake という IAM User に AWSDenyAll が適用される
    • 適用タイミングは手動(承認)
  • 実行中のインスタンス (EC2 または RDS) の停止アクション
    • 全 EC2 Instance(3台)を停止
    • 適用タイミングは自動

f:id:swx-satake:20201029135439p:plain

設定が完了したら、画面右下の「Confirm budget」を押下します。確認画面が表示されますので、「Done」で設定を完了します。

なお、Budget action ごとに SNS の設定が使われるのですが、今回は閾値での通知と、Budget action での通知2種類で、3つ利用しています。それぞれについて1回ずつ SNS で設定が完了した Notification が送信されてしまうのでご留意ください。

f:id:swx-satake:20201029140118p:plain

設定が完了すると、Budget の右上に There are no pending actions. と表記されるようになります。また、Budget の一覧画面では 2 standby と表記されます。

f:id:swx-satake:20201029140323p:plain

これらの設定を全て完了したのは、2020年10月28日 2:51 PM前後になります。

Budget action 実行前の設定確認

Budget action が実行される前に、現在の設定を確認します。

IAM User satake の権限

satake の権限は以下の通りです。なお、IAM ロールまたはユーザにアタッチできる管理ポリシーは最大 10 個までという制限に注意してください。

f:id:swx-satake:20201029140252p:plain

今回アタッチされている IAM ポリシーは10個ですが、1つはインラインポリシーのため、残り1つのポリシーがアタッチ可能です。

参考までにポリシーが10を超えておりアタッチできない場合は、以下のエラーが発生します。

f:id:swx-satake:20201029182647p:plain

Failed to attach policy arn:aws:iam::aws:policy/AWSDenyAll to IAM user satake : Error from AmazonIdentityManagement : Cannot exceed quota for PoliciesPerUser: 10

Please review the unsuccessful action details below before trying to execute this action again.

EC2 Instance の状態

f:id:swx-satake:20201029140440p:plain

今回、Running となっている EC2 Instance は上画像の1台のみです。指定した残り2台の EC2 Instance は停止(Stopped)状態です。

Budget action の実行を確認する

2020年10月29日 4:53 AM 、SNS による通知が2通届いていました。

AWS Budgets Action: 2ff309f0-ac15-499d-8e2b-5650a619be79 Approval Needed for Monthly Budget

1通目、これは IAM ポリシーの適用アクションに関する通知です。承認を求められています。

通知内容は、以下のjsonの通りです。

{
    "accountId": "772300000000",
    "timeStamp": "2020-10-28T19:53:38.848Z",
    "message": "You requested that we alert you and begin 2ff309f0-ac15-499d-8e2b-5650a619be79 action, when your actual value associated with your Monthly Budget budget exceed $36.00 for the current month. Currently, you are forecast to spend $39.72 this month",
    "budget": {
        "budgetName": "Monthly Budget",
        "budgetLimit": {
            "amount": 36,
            "unit": "USD"
        },
        "budgetType": "COST",
        "forecastedSpend": {
            "amount": 39.718,
            "unit": "USD"
        },
        "timeUnit": "MONTHLY"
    },
    "request": "Execute",
    "overallStatus": "Pending",
    "action": {
        "actionId": "2ff309f0-ac15-499d-8e2b-5650a619be79",
        "notificationType": "actual",
        "actionThreshold": {
            "value": 100,
            "unit": "percentage"
        },
        "taskTobeExecuted": [
            "Apply policy arn:aws:iam::aws:policy/AWSDenyAll to IAM user satake"
        ]
    },
    "approvalMessage": "Would you like to approve [this/these] [Action(s)]?",
    "approvalLink": "https://console.aws.amazon.com/billing/home#/budgets/details?name=Monthly%20Budget"
}

承認が必要なものは、json 内で taskTobeExecuted に記載されており、"Would you like to approve [this/these] [Action(s)]?"と承認するか否かが求められるメッセージになっています。

AWS Budgets Action: 7fc107cc-af0b-414e-99e0-98c127a3e7dd has successfully executed for Monthly Bu...

2通目は、自動的に EC2 Instance が停止された通知です(件名が途中で切れてしまっているのが気になりますが)。

通知内容は、以下のjsonの通りです。

{
    "accountId": "772300000000",
    "timeStamp": "2020-10-28T19:53:53.045Z",
    "message": "You requested that we alert you and execute the 7fc107cc-af0b-414e-99e0-98c127a3e7dd action on your behalf when your actual value associated with your Monthly Budget budget exceed $36.00 for the current month. Currently, you are forecasted to spend $39.72 this month.",
    "budget": {
        "budgetName": "Monthly Budget",
        "budgetLimit": {
            "amount": 36,
            "unit": "USD"
        },
        "budgetType": "COST",
        "forecastedSpend": {
            "amount": 39.718,
            "unit": "USD"
        },
        "timeUnit": "MONTHLY"
    },
    "request": "execute",
    "overallStatus": "Success",
    "action": {
        "actionId": "7fc107cc-af0b-414e-99e0-98c127a3e7dd",
        "notificationType": "actual",
        "actionThreshold": {
            "value": 100,
            "unit": "percentage"
        },
        "taskExecuted": [
            {
                "taskDescription": "run AWS-StopEC2Instance with parameters {InstanceId=[i-0c678d2c038786416, i-001a4fd7ae75266c0, i-0acb4edec031ddcbe]} in region ap-northeast-1",
                "status": "Success",
                "errorMessage": "N/A",
                "timestamp": "2020-10-28T19:53:51.614Z"
            }
        ]
    },
    "nextStep": "reverse",
    "nextStepLink": "https://console.aws.amazon.com/billing/home#/budgets/details?name=Monthly%20Budget"
}

承認が不要な自動実行のものは、json 内で taskExecuted に記載されており既に実行済なことがわかります。

マネジメントコンソールで状況を確認する

自動実行されて停止されている EC2 Instance の停止を先に確認します。

自動実行済のインスタンス (EC2 または RDS) 停止アクション

対象の EC2 Instance は問題なく停止されていましたが、Config がどうなっているのか確認します。

f:id:swx-satake:20201029142356p:plain

Config で確認すると、4:56 AM に Config に記録がされており、EC2 Instance が Stopped に遷移していたことがわかります。

f:id:swx-satake:20201029142613p:plain

紐づいている CloudTrail の履歴を見ると、User NameInsightsActionWorker1603914817518 となっていました。なぜか2回実行されていますが、どちらも同じ処理でした。CloudTrail を確認するに、Budget action による停止対象は指定した3台の EC2 Instance 全てとなっていましたが、3台のうち2台は既に停止されていましたので、1台だけ停止されていました。

2020年11月13日 追記

Config に CloudTrail の停止履歴が2回記載されているのは、以下の仕様のためでした。

今回設定した IAM Role に "ssm:StartAutomationExecution" が含まれている通り、Instance の停止と起動の制御は、Systems Manager (SSM) の Automation を利用して行われます。実際にマネジメントコンソールより SSM の Automation 実行履歴を確認したところ、以下の通り実行された履歴が存在していました。

f:id:swx-satake:20201113104719p:plain

少し補足すると、Systems Manager の実行には SSM Agent が必須と思われる方もいらっしゃるのですが、Automation は Systems Manager の Agent がなくても動作するものです。今回実行されていたのは停止と起動においてそれぞれ以下の通りでした。

  1. AWS-StopEC2Instance
  2. AWS-StartEC2Instance

このうち AWS-StopEC2Instance というドキュメントは stopInstancesforceStopInstances をそれぞれ実行し強制的に EC2 Instance を停止するものです。

f:id:swx-satake:20201113105216p:plain

このドキュメントを実行した場合、2度 Instance を停止させるコマンドが発行されるため CloudTrail の履歴が2回残っていた、となります。以上追記でした。

IAM ポリシーの適用アクションの承認

次に、IAM ポリシーの適用アクションが保留されているため、これを承認しに行きます。

f:id:swx-satake:20201029142930p:plain

Budget のコンソールを見ると「1 pending」となっています。

f:id:swx-satake:20201029143213p:plain

画面右上にある「More Info」を押下して状態を確認します。

f:id:swx-satake:20201029143416p:plain

Stop EC2 は Execution success となっていますが、Pending actions に「AWSDenyAll」があることがわかります。

f:id:swx-satake:20201029160231p:plain

「AWSDenyAll」 のペインを開き「Execute action」を押下することで承認が可能です。

f:id:swx-satake:20201029144252p:plain

「Execute action」を押下すると上画像の画面が表示されます。「Yes, I am sure」を押下することで承認され、操作が実行されます。

f:id:swx-satake:20201029144956p:plain

実行すると「Execution in progress」に状態が遷移します。

f:id:swx-satake:20201029145042p:plain

実行が完了すると、 Execution success に遷移しました。

IAM ポリシーの適用アクションの確認

f:id:swx-satake:20201029145420p:plain

承認後、IAM ユーザのポリシーを確認すると無事に「AWSDenyAll」がアタッチされていることがわかります。

この状態で、実際に satake ユーザでログインしてみてみます。

f:id:swx-satake:20201029150025p:plain

すると、上画像の通り EC2 Instance は全て閲覧できず、操作は不可能になりました。

つまり「EC2 Instance は全て Budget actionで停止されてしまった」かつ「IAM User での操作(停止された EC2 Instance の起動)も、権限を Deny されてできない」という状況に追い込むことができたわけです。

Budget action の実行を取り消す

Budget action の実行は、Undoする(取り消す)ことができます。

f:id:swx-satake:20201029151846p:plain

画像の通り、一度実行された Action は Action history の画面から「Undo」可能です。実際に実行してみます。

f:id:swx-satake:20201029152101p:plain

Undo も同様に「Yes, I am sure」を押下することで操作が実行されます。

f:id:swx-satake:20201029152137p:plain

Undo を実行すると「Reverse in progress」に遷移します。ステータスが「Reverse success」になれば完了です。

IAM ポリシーの適用アクションのUndo

f:id:swx-satake:20201029152251p:plain

Undo された結果、上画像の通り「AWSDenyAll」がデタッチされました。

この操作は、

自動実行済のインスタンス (EC2 または RDS) 停止アクションのUndo

f:id:swx-satake:20201029152409p:plain

Undo された結果、停止対象のインスタンスは3台とも起動されました。

もともと Budget action 実行時に起動されていたインスタンスは1台だけだったのですが、停止対象を3台全てに指定していたため、Undoによる起動も3台全てに実行されました。

Budget action の実行をリセットする

Undo された Reverse success 状態の Budget action はその Budget の設定期間中は二度と実行されない状態になるため、必要があれば今一度 Budget action をトリガーするためにスタンバイの状態に復帰させる必要があります。

f:id:swx-satake:20201029152626p:plain

「Reset action」を実行することで、それが可能になります。

f:id:swx-satake:20201029152654p:plain

同様に「Yes, I am sure」を押下することで操作が実行されます。

f:id:swx-satake:20201029152714p:plain

無事に Standby 状態になりました。なぜか「Stop EC2」で2つ表示がされてしまっていますが、気にせず進めます。

f:id:swx-satake:20201029152951p:plain

Standby 状態に戻った Budget action は上画像の通り再度実行されました。承認が必要な IAM ポリシー側は、再度 Pending 状態となっています。

※新規の AWSDenyAll が Action history 側にもなぜか2つ出てきているのが謎ですが、表示の問題だけだと思うので一旦スルーしました

ステータスの遷移まとめ

自動実行の場合

  1. 設定直後:Standby
  2. 自動実行後:Execution success
  3. Undo後:Reverse success
  4. Reset後:Standby

承認が必要な場合

  1. 設定直後:Standby
  2. 閾値を超えた後(承認待ち):Pending
  3. 承認実行後:Execution success
  4. Undo後:Reverse success
  5. Reset後:Standby

実行してみて気になったポイント

実際に本機能を検証してみて感じたことを記載します。

EC2 Instance の指定が全て Instance ID指定

ターゲットとするインスタンスを選択するには、Instance IDで選択するのが GUI として厳しいと感じました。何らかの管理用のタグが使えればより柔軟な設定ができそうです。

ただAWSアカウントを本番環境と検証環境で完全に分離しているような場合は「全てのインスタンス」を選択すれば設定は容易です。

ただし、インスタンスを追加構築した場合に再度設定に入れなおす必要があります。その場合ですが、再設定時にはなぜか Select all instance IDs が消えており選択できません。再設定時には一旦設定を全部消して再度 Select all instance IDs を押下したほうが楽なこともあるかもしれません。

インスタンスを停止したからといって起動できないわけではない

今回 IAM ポリシーと合わせて設定したのは、Budget action による停止は強制的に実行されるものの、停止されたインスタンスが二度とその月内は起動できないというようなことにはならないためです。停止したインスタンスを起動させないようにするには IAM ポリシーの制御も同時に実施する必要があります。

補足すると、EC2 Instance を強制的に停止する必要がない場合もあります。例えば Cloud Automator を利用して夜間停止をしているような場合は、早朝にインスタンスを起動するCAジョブで利用している IAM User(もしくは IAM Role)にインスタンスの起動を Deny する IAM ポリシーを適用し制御することで、早朝の起動ジョブを実行させないようなことも可能です。

RDS DB.Instance の停止は疑問が残る

RDS は7日間停止が最大で、その後自動的に起動してしまいます。月の前半に予算を超えてしまい停止されたとしても、7日後に自動的に起動してしまうためせっかくの停止も RDS の仕様とうまくかみ合っていないように思えます。

インスタンス停止の Undo では対象サーバ全てが起動されてしまう

Budget action で停止対象としたインスタンス全てが Undo の実行により起動されてしまいます。Budget action によって実際に停止されたものかどうかは判定されないため、Budget action によって停止されたインスタンスだけではなく、元から停止状態であったインスタンスまでもが起動されてしまう可能性がある点に注意が必要です。

Organizations の Root から設定を行えない

Organizations の Root ではあくまで SCP による制御が主で、それをもって「明示的なDeny」を配布することはできますが既存のリソースの停止は不可能です。というのは、多くの場合 Organizations の Root はその Root の機能のみをもっており、そこにインスタンスなどのリソースを構築することはほとんどないためです。

わざわざ全てのAWSアカウントにログインして設定していくのはあまりにも手間のため、CloudFormation などを利用する横展開を考えないといけないでしょう。

IAM のポリシーの最大数が10 / SCP のポリシーの最大数が5

先ほど IAM ポリシーの最大数については記載しましたが SCP は最大数が5です。これは以下のブログに記載しています。既に OU に5つの SCP がアタッチされている場合は、制御用のポリシーのアタッチが失敗する点に注意してください。

blog.serverworks.co.jp

月初に Undo されるのかどうか

最も気になるのは、Monthly Budget 設定でその月が終了した場合に、翌月月初に制御された IAM ポリシーは元に戻る(Undoされる)のかという点です。これが元に戻らない場合は、手動で全てを Undo しに行くという手間がかかります。

しかし Undo が実行されると仮定すると EC2 Instance が全台起動してしまうということにもなりえます。私としては IAM ポリシーは元に戻してほしいですが、EC2 Instance は起動してほしくありません。この点については2020年11月月初に追記します。

2020年11月4日 追記

こちらに続けて記載するには少し長くなってしまったため、上記の件は以下のブログにて補足としました。合わせてご確認ください。

blog.serverworks.co.jp

まとめ

f:id:swx-satake:20201029154523p:plain:w150

本ブログ記事では AWS Budgets の新機能である Budget action を検証しました。AWS Budgets で完結してリソースの制御アクションが実行できる機能となっており、現在制御対象は3つと少ないものの「実用最小限の機能」としてまずはリリースされたことを喜びたいと思います。

Budget action の実行においては「承認が必要な設定」と「承認が不要な自動実行の設定」とを同時に検証してみました。承認が必要なシナリオは、大手企業に配慮された良い機能だと感じます。ですが、私が利用するなら運用の楽さから特に検証環境に対しては「自動実行」で設定したいと考えます。できれば社内の全AWS検証アカウントに Budget action を配布してしまいたいとも思っています。

ですが、実行には先に記載した通り、それぞれのAWSアカウントで設定を行わないとならないため、横並びに配布する仕組みを考えなければなりません。Budget action の配布方法は別途考えたいと思います。

では、またお会いしましょう。

佐竹 陽一 (Yoichi Satake) エンジニアブログの記事一覧はコチラ

マネージドサービス部所属。AWS資格全冠。2010年1月からAWSを利用してきています。2021-2022 AWS Ambassadors/2023 Japan AWS Top Engineers/2020-2023 All Certifications Engineers。AWSのコスト削減、最適化を得意としています。