サーバ(EC2)レスでCloudTrailのログを処理してみた (新CDP提案)

※この記事は CDP Advent Calendar 2013 12/3 の記事です
前回の記事 CloudTrailのログを検索してみた - log4moto では、ローカルのMongoDBにCloudTrailのログを入れて検索をしてみました。
しかしどうにもスマートではないので、AWSで完結するようにしてみました。

動作イメージ

Searchを押すとログをフェッチして画面に表示します。
処理はすべて AWS SDK for JavaScript in the Browserを使っていて、S3のstatic web hostingで動作しています。

構成

構成図です。

  1. 各リージョンのCloudTrailは、そのリージョン内のSNS topicへログファイルの更新を通知します。
  2. そのSNSへ、1つのリージョン(今回はap-northeast-1)のSQS queueをsubscribeします。
    これによって、1つのキューを見張るだけで今後追加されるすべてのリージョンのログファイルも処理する事が出来ます。
  3. 上記ページを見ているクライアントは、同時にワーカーとしてSQSからメッセージを受け取り、新規のログファイルをgzip解凍、JSONのパース、DynamoDBへのputを行います。

実装

JavaScriptなのでソースを見ていただくのが一番早いのですが、苦労した点などを。

JavaScriptgzipを解凍する必要があった

CloudTrailのオブジェクトは json.gz というファイルなので、JavaScriptでパースを行うには解凍を行う必要があります。ググって 高度な JavaScript 技集inflate.js を使用させて頂く事にしました。その際に、gzipのヘッダを読み飛ばして、inflateの実データ部だけを抜き出さないといけないので注意です。
というか、そもそもS3 objectのContent-typeがapplication/octet-streamなのが原因で、Content-typeがtext/jsonかつContent-Encodingをgzipにすると

> bucket.getObject({Key: 'AWSLogs/hogepuge.json'}, function(err,data){console.log(err,data.Body.toString())});
null "{
    "hoge": "hogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehogehoge",
    "puge": "pugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepugepuge"
}
" 

と解凍された状態で取れるので、置かれた時点でそのような状態になっているといいなー*1、という事でフィードバックしたいと思います。

CORS設定

最初S3 bucketのCORS設定でAllowedHeaderが足りなくて、ハマりました。 @memorycraft さんの記事に助けられました!ありがとうございました!

まとめ

EC2に処理させる事も考えましたが、"EC2を使ったら負けだと思っている"の名言を思い出し、どうせデータを見るクライアントがあるならそのCPUリソースを借りて処理してしまえ!という事でこのような構成にしてみました。
実際には誰かが見ていないとデータが更新されない&SQSのデータは最大14日間しか保持されないので、素直にEC2でやった方がいいんじゃないかという気がしつつ、これを新パターン "Client as a Worker"パターンと名付けてみました。きっともっといいユースケースがあるはずです。

*1:fetch前にmeta-dataをセットするのもありですが。