概要
- S3へのObject Uploadイベントを検知するのにCloudTrail + EventBridge を使っていたが、イベントが発行されない事象があった
- 泣く泣く S3 Bucket Notification にした
S3 Bucket Notification vs EventBridge
S3にObjectがPutされた、などのS3関連のEventを補足するには一般に2つのやりかたがあります。
S3 Bucket Notification と EventBridgeです。
イベントタイプの比較
Bucket Notificationでサポートされるイベントタイプ
EventBridge (+Cloudtrail)でサポートされるイベントタイプ
だいたいは取れるものが一緒なのでどちらを使ってもいいのですが、Infrastructure as Code をしているとEventBridgeのほうが柔軟で取り回しがいい印象でしたので、積極的にそちらをつかっています。
大きな理由としては、S3 Bucket NotificationはBucketに対して1:1の設定なのに対し、EventBridgeは処理をしたいSubscriber側が個々にいくつも購読者になれるからです。
EventBridgeのインフラ
(データの流れではなくインフラ構築上の購読関係=デプロイの依存関係を表現しています。)
上記のように、仮に上記図の点線がterraformのtfstate
やcloudformationの stack
をおおまかに表現しているとすると、S3 Bucket Notificationを依存関係順に適切にデプロイするにはbackendを用意->アプリ層を用意->イベント層を用意...というふうに行う必要があります。
EventBridgeは各種アプリがそれぞれ好きに購読イベントを貼ればいいため、ちょっとだけ楽だったわけです。
イベント発火しない問題
ここからが問題です。
EventBridgeを使って「動画ファイルがS3にUploadされたらLambdaが発火してエンコードが始まる」というような処理を書いていたわけですが、「サイズが25GB~の動画でエンコードが始まらない」という事象がありました。
調査の結果、原因としては、**「Cloudtrailで証跡イベントが一定サイズを超えるとイベントがEventBridgeに渡らない仕様がある」**ことでした。
AWS CloudTrail におけるクォータ
EventBridgeとしてはS3のPutObject
イベント、CompleteMultiPartUpload
を購読していました。
大きいサイズのファイルは分割アップロードが基本なので、該当するイベントはCompleteMultiPartUpload
になります。
このイベントの中身は例えばこうなっています。
{
"version": "0",
"id": "c93b9948-ffd0-f7fb-9518-2e036abbc3af",
"detail-type": "AWS API Call via CloudTrail",
"source": "aws.s3",
"account": "xxxxxx",
"time": "2021-06-01T14:37:21Z",
"region": "ap-northeast-1",
"resources": [],
"detail": {
"eventVersion": "1.08",
"userIdentity": {
"type": "IAMUser",
"principalId": "xxxxx",
"arn": "arn:aws:iam::xxxx:user/yyyy",
"accountId": "xxxxxx",
"accessKeyId": "xxxxx",
"userName": "yyyy"
},
"eventTime": "2021-06-01T14:37:21Z",
"eventSource": "s3.amazonaws.com",
"eventName": "CompleteMultipartUpload",
"awsRegion": "ap-northeast-1",
"sourceIPAddress": "xxxxxx",
"userAgent": "[aws-cli/2.1.24 Python/3.7.4 Darwin/19.6.0 exe/x86_64 prompt/off command/s3.cp]",
"requestParameters": {
"bucketName": "xxxxxxxx",
"Host": "xxxxx.s3.ap-northeast-1.amazonaws.com",
"uploadId": "avdaeqpdx99lXz70Yft62YJxmgVdeM5VWcaH8rYIKrAnwjerhkfbO8dHfJJzAKav3oW4SdIgoK3BahaSNC6YgdvEFa0A_OsMhWbqkpeMmSpYZoCWz.gD49Exw1sAAvvsmA--",
"key": "lite.mp4",
"CompleteMultipartUpload": {
"xmlns": "http://s3.amazonaws.com/doc/2006-03-01/",
"Part": [
{
"PartNumber": 1,
"ETag": "\"5ed2be71e6bef670c7416d70361718a4\""
},
{
"PartNumber": 2,
"ETag": "\"c397ab42f91201229c1f454d2a9e14a5\""
},
{
"PartNumber": 3,
"ETag": "\"6b2cea0de956e1002ea5c5e940c8a00a\""
},
{
"PartNumber": 4,
"ETag": "\"cdc0bd651f02f3b21911f118c94de567\""
},
{
"PartNumber": 5,
"ETag": "\"47d9aebf4a08f28cc69c6a9e0d1abdf2\""
},
{
"PartNumber": 6,
"ETag": "\"33c4597cda25c160e897c3ba9e606820\""
},
{
"PartNumber": 7,
"ETag": "\"623a099d0940864338ae85e17e37944f\""
},
{
"PartNumber": 8,
"ETag": "\"88e2e2da7b12c94ffbc314cbb0d17992\""
},
{
"PartNumber": 9,
"ETag": "\"347d6cb0c889c3abec82daeaadf75401\""
},
{
"PartNumber": 10,
"ETag": "\"68ccb3e5635a54da35b825f15441f02c\""
},
{
"PartNumber": 11,
"ETag": "\"1ea383c8b5651e2d642f4ee2eafcdd7a\""
},
{
"PartNumber": 12,
"ETag": "\"10b73a3237d4f8197bf49f9eb7e6793e\""
}
]
}
},
"responseElements": null,
"additionalEventData": {
"SignatureVersion": "SigV4",
"CipherSuite": "ECDHE-RSA-AES128-GCM-SHA256",
"bytesTransferredIn": 1134,
"AuthenticationMethod": "AuthHeader",
"x-amz-id-2": "XXXHJCHoPaHbqiIp792mjON0KCoNqkAlTRe0ZEyfpk4to79vEh0nGWG4=",
"bytesTransferredOut": 361
},
"requestID": "DFT0HJM8XKDAEBA",
"eventID": "defc50a8-a853-4dcb-b223-7e09c17aae94",
"readOnly": false,
"resources": [
{
"type": "AWS::S3::Object",
"ARN": "arn:aws:s3:::xxxx/lite.mp4"
},
{
"accountId": "xxxxx",
"type": "AWS::S3::Bucket",
"ARN": "arn:aws:s3:::xxxx"
}
],
"eventType": "AwsApiCall",
"managementEvent": false,
"recipientAccountId": "xxxxxxxxxx",
"eventCategory": "Data"
}
}
detail.requestParameters. CompleteMultipartUpload
に注目すると、分割uploadに使ったファイルのhash値が羅列されています。
一方で、EventBridgeに渡らなかったイベントをClpoudtrail側で確認すると、こうなっています。
{
"eventVersion":"1.08",
"userIdentity":{
"type":"IAMUser",
"principalId":"AAASDCDVSUUN7AAA2TU",
"arn":"arn:aws:iam::xxxx:user/yyyy",
"accountId":"xxxxx",
"accessKeyId":"xxxxx",
"userName":"yyyy"
},
"eventTime":"2021-06-01T15:00:03Z",
"eventSource":"s3.amazonaws.com",
"eventName":"CompleteMultipartUpload",
"awsRegion":"ap-northeast-1",
"sourceIPAddress":"xxxxx",
"userAgent":"[aws-cli/2.1.24 Python/3.7.4 Darwin/19.6.0 exe/x86_64 prompt/off command/s3.cp]",
"requestParameters":{
"omitted":true,
"originalSize":209614.0,
"reason":"requestParameters too large"
},
"responseElements":null,
"additionalEventData":{
"SignatureVersion":"SigV4",
"CipherSuite":"ECDHE-RSA-AES128-GCM-SHA256",
"bytesTransferredIn":282635.0,
"AuthenticationMethod":"AuthHeader",
...
requestParameters too large
の項目があります。このメッセージは、s3 eventに限らず、証跡データが大きすぎる時記載されるようです。
EventBridge responseElements too large
おそらくですが、detail.requestParameters. CompleteMultipartUpload
に全てのPart情報が記載されるとすると、巨大な分割アップロードで数千Partあるような場合、jsonオブジェクトのサイズも膨大になり、CloudtrailのQuotaを超えるのではないかと予想されます。
対応
ひとまずの対応として、おとなしくインフラを再構成し、EventBridgeの代わりに S3 Bucket Notification をつかっていくことにしました。
解せぬ。