はじめに
先日、EventBridge
でCloudTrail
に記録されたイベントを契機にするルールを作成した際、四苦八苦しながら少しだけサンドボックスの機能を使ってみたので、残しておこうと思います。
EventBridgeのサンドボックス機能とは
EventBridge
のルールを「イベントパターンを持つルール」の形式で作成する場合、各サービス等から出力されるイベントに合致するように「イベントパターン」を記載して、イベントに合致した場合にルールを実行する動作となりますが、「イベントパターン」の記載方法があっているかを確認するためには実際にイベントを発生させて確認する必要があります。
ただ、記載方法があっているかを確認するのに毎回イベントを発生させるのは非常に手間なので、2022年3月に新たに「サンドボックス」の機能が加わりました。
各サービスごとに用意されている「サンプルイベント」からサンプルを選択して、サンプルのイベントに対して、自分で作成した「イベントパターン」が合致するかを確認するか、もしくはイベント発生時に呼び出されるイベントオブジェクトをサンプルとして登録して、「イベントパターン」が合致するかを確認する方法があります。
今回やりたかったこと
今回EventBridge
で最終的にやりたかったこととしては、Fargate
をブルーグリーンデプロイメントでデプロイ途中、デプロイを手動で停止した際のイベントを検知して通知することをやりたかったというのが本来の目的です。
ただ、イベントパターンを作成する際に、イベントパターンの書式確認のため毎回Fargate
のデプロイを実施するのは骨が折れるため、「サンドボックス」で書式があっていることを確認してみようと思います。
カスタムサンプルイベントの作成
元々用意されているサンプルイベントを使うのもよいですが、今回はCloudTrail
に記録されるイベントを使いたかったので、カスタムでサンプルイベントを作成しようと思います。
ただ、CloudTrail
に記録されるイベントの履歴は、実際にイベントが発生した際に呼び出されるイベントオブジェクトの書式と異なるようで、CloudTrail
に記録されるJSON形式のイベント履歴をそのままサンドボックスのサンプルイベントにコピペしてチェックしても「サンプルイベントは無効です。」と出てしまい、チェックに失敗してしまいます。
ちなみに以下がCloudTrail
に記録されるイベント例。
CloudTrailに記録されるイベント例(展開してください)
{
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"principalId": "XXXXXXXXXXXXXXXXXXXXX",
"arn": "arn:aws:iam::123456789012:user/testuser",
"accountId": "123456789012",
"accessKeyId": "YYYYYYYYYYYYYYYYYYYY",
"userName": "testuser",
"sessionContext": {
"sessionIssuer": {},
"webIdFederationData": {},
"attributes": {
"creationDate": "2022-11-20T03:11:57Z",
"mfaAuthenticated": "true"
}
}
},
"eventTime": "2022-11-20T11:27:02Z",
"eventSource": "codedeploy.amazonaws.com",
"eventName": "StopDeployment",
"awsRegion": "ap-northeast-1",
"sourceIPAddress": "AWS Internal",
"userAgent": "AWS Internal",
"requestParameters": {
"deploymentId": "d-3LVK9RJSK",
"autoRollbackEnabled": true
},
"responseElements": {
"status": "Succeeded",
"statusMessage": "No more commands will be scheduled for execution in the deployment instances"
},
"requestID": "2ed04e08-daee-4ace-b132-f61e802f6cd0",
"eventID": "69c587a6-eb5c-4fa3-a7cb-b9e735f81ba1",
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "123456789012",
"eventCategory": "Management",
"sessionCredentialFromConsole": "true"
}
また、後述する方法で取得したイベントオブジェクト例。
イベント発生時に実行されるイベントオブジェクト例(展開してください)
{
"version": "0",
"id": "fbc9cc14-052e-06c5-0b96-51965c1ca766",
"detail-type": "AWS API Call via CloudTrail",
"source": "aws.codedeploy",
"account": "123456789012",
"time": "2022-11-20T11:27:02Z",
"region": "ap-northeast-1",
"resources": [],
"detail": {
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"principalId": "XXXXXXXXXXXXXXXXXXXXX",
"arn": "arn:aws:iam::123456789012:user/testuser",
"accountId": "123456789012",
"accessKeyId": "YYYYYYYYYYYYYYYYYYYY",
"userName": "testuser",
"sessionContext": {
"sessionIssuer": {},
"webIdFederationData": {},
"attributes": {
"creationDate": "2022-11-20T03:11:57Z",
"mfaAuthenticated": "true"
}
}
},
"eventTime": "2022-11-20T11:27:02Z",
"eventSource": "codedeploy.amazonaws.com",
"eventName": "StopDeployment",
"awsRegion": "ap-northeast-1",
"sourceIPAddress": "AWS Internal",
"userAgent": "AWS Internal",
"requestParameters": {
"deploymentId": "d-3LVK9RJSK",
"autoRollbackEnabled": true
},
"responseElements": {
"status": "Succeeded",
"statusMessage": "No more commands will be scheduled for execution in the deployment instances"
},
"requestID": "2ed04e08-daee-4ace-b132-f61e802f6cd0",
"eventID": "69c587a6-eb5c-4fa3-a7cb-b9e735f81ba1",
"readOnly": false,
"eventType": "AwsApiCall",
"managementEvent": true,
"recipientAccountId": "123456789012",
"eventCategory": "Management",
"sessionCredentialFromConsole": "true"
}
}
上記2つのJSON
を比較したもの。
左がCloudTrail
で記録されたJSON、右がイベント発生時に実行されるイベントオブジェクトのJSONです。
イベント発生時に実行されるAPI
CloudTrail
で記録されたイベントのJSON
と、イベント発生時に実行されるAPIのJSON
を比較すると、イベント発生時に実行されるイベントオブジェクトは以下のようにdetail
の箇所に、CloudTrail
に記録されるイベントが含まれることがわかるかと思います。
{
"version": "0",
"id": "fbc9cc14-052e-06c5-0b96-51965c1ca766",
"detail-type": "AWS API Call via CloudTrail",
"source": "aws.codedeploy",
"account": "123456789012",
"time": "2022-11-20T11:27:02Z",
"region": "ap-northeast-1",
"resources": [],
"detail": {
"CloudTrail のイベント記録"
}
}
サンドボックスで試すだけならdetail
より上に記載されている箇所を自分で適当に作って書式を合わせてもできるかと思いますが、それはそれで手間なので、イベント発生時に実行されるイベントオブジェクトを記録する仕組みを仕込んだ上で一度デプロイ停止のテストを行い、確認してみようと思います。
【参考】
イベントオブジェクトの出力
Lambda
のデベロッパーガイドにイベントオブジェクトの内容をログに記録するコードが書かれていたため、こちらを使っていこうと思います。
exports.handler = async function(event, context) {
console.log("EVENT: \n" + JSON.stringify(event, null, 2))
return context.logStreamName
}
Lambda関数の作成
AWS Lambda
のダッシュボードより「関数の作成」から、以下のように設定して「関数の作成」を選択します。
EventBridgeルールの作成
Amazon EventBridge
のダッシュボードより「ルール」→「ルールを作成」から以下のように設定して次へ進みます。
そのまま下に進み、「イベントパターン」 の設定を以下の様に設定して次へ進みます。
今回の場合、CloudTrail
に記録された情報を見ると、「AWSのサービス」、「イベントタイプ」は以下のような設定となるため、選択後、次へ進みます。
ターゲットは先程作成したLambda
を指定して次へ進みます。
そのまま次へ進み、「ルールの作成」ができたら完了です。
イベントオブジェクトの出力
EventBridge
のイベントが作成終わったら、実際にイベントを発生させてイベントオブジェクトを出力させます。
私の場合は、ブルーグリーンデプロイを停止したタイミングで出力されるため事象を発生させてみます。
今回Lambda
でイベント発生時のイベントオブジェクトを記録するようにしているので、ログはCloudWatch Logs
に出力され、output_event_object
と言った名前で設定した場合は「/aws/lambda/output_event_object
」といったロググループに出力されております。
ログストリームにdetail
等の項目を含んだJSON
形式のログが出力されていれば成功です。
サンドボックスへのログ貼り付け
EventBridge
に戻り、「サンドボックス」→「イベントパターン」を選択し、以下のようにして先程CloudWatch Logs
に出力されたログをサンプルイベントにコピペします。
※1行目のCloudWatch Logsのログメッセージは不要
項目 | 設定 |
---|---|
イベントソース | AWSイベントまたはEventBridgeパートナーイベント |
サンプルイベント | ご自身名前を入力 |
入力欄 | CloudWatch Logsに出力されたログのコピペ |
イベントパターンの作成
いよいよイベントに合致させるイベントパターンを作成し、書式があっているかを確認してみようと思います。
イベントパターンは自分で最初から作成することもできますが、それだと大変なので、以下のようにメニューから選択して雛形を作ってから必要な部分を自分で追加してみます。
今回は「特定のオペレーション」に、デプロイを停止した際のオペレーションとなる「StopDeployment
」を指定して、デプロイ停止時のアクションをトリガーとするイベントパターンを作成してみます。
入力し終わって「テストパターン」ボタンを押すとサンプルイベントとイベントパターンのチェックが行われ、イベントパターンに一致すれば以下のように表示されます。
イベントパターンに一致したサンプルイベント
イベントパターンの内容が一致しなければ以下のように表示されます。
サンプルイベントがイベントパターンと一致しませんでした
そもそもサンプルイベントの書式が誤っていたりする場合は以下のように表示されます。
サンプルイベントは無効です。
最初、CloudTrail
のログそのままコピペすれば良いものだと思って試していた際は、JSON
のフォーマットチェックは通るのにイベントパターンに何を書いても失敗していたので、ここに何を書けば通るのかわからずだいぶ悩みました。
イベントパターンの編集
上記ではeventName
をStopDeployment
に指定してチェックしましたが、「パターンを編集」を選択することで、以下のように直接編集できる画面に切り替わります。
イベントパターンに記載される内容はCloudWatch Logs
に出力されたJSON
形式のログのうち、マッチさせたい内容を記載すればOKです。
但し、CloudWatch Logs
のログをそのままイベントパターンに記載するのではなく、階層構造はそのままで、Value
(値の部分)は[]
でくくる必要があります。
以下はautoRollbackEnabled
とstatus
の値もパターンマッチの条件にした場合の例。
おわりに
いちいち事象を発生させてトライアンドエラーで進めていかなくても、一度イベントログを出力してからサンドボックスで確認すれば、イベントパターンがマッチするかを試せるのは非常にやりやすいと感じました。