2014-11-24
■[AWS][Lambda]Lambdaを使って、CloudTrailログをCloudSearchに入れて検索する
来週JAWS-UG名古屋でAWS LambdaのLTをするためにいくつかデモ案を作っていますが、実用的なものも必要だろうということで、表題の通りLambdaを使って、CloudTrailログをCloudSearchに入れて検索するサンプルを作成しました。
CloudTrailのログはS3に上がってきますが、ログが出来た通知をLambdaで受けて、そのログを整形してCloudSearchに入れます。従来ではEC2などから定期的にログ確認をしないといけなかったので、非常に楽ですね。
事前準備(入力側)
はじめにLambdaコンソールから、新しいFunctionを登録します。適当な名前をつけます。
コードの中身は後で変えるのでサンプルのままにしておき、つぎにIAMロールを設定します。これはLambdaが実行されるときのロールなので、アクセスするサービス(今回はS3とCloudSearch)への権限をつけたロールを作り、設定します。新規に作ると、arnが自動的に設定されます。
次にS3バケットを設定します。バケットにはIAMロールの設定をいけないですが、簡単な方法としては、先にバケットを作っておき、Lambda側からアクセス権をつける方法です。
実行するLambda関数と同じリージョンに、S3バケットを作成します(別リージョンはNG)。
次に、先ほど作成したLambda関数をコンソールから選択します。画面の下の方に「Configure Event Source」というのがありますのでこれをクリックします。
そうすると、バケット選択画面が出てきますので、先ほど作ったバケットを設定します。またここでもIAMロール設定が出てきます。このIAMロールは、S3バケットからLambdaを呼び出すためのロール設定なので、Lambda呼び出しだけの権限を設定します。
最後に、CloudTrailの画面から、ログ出力先として先ほどのS3バケットを設定します(画面省略)
事前準備(出力側)
次に出力側の設定のため、CloudSearchのドメインを作ります。今回CloudSearchはLambdaやS3バケットと同じリージョンに作りましたが、これは別でも大丈夫です。
ドメインに適当な名前をつけて、マニュアルでIndexをつけます。
出力される主要な部分の項目をIndex対象にします。
ドメインが出来たら、データを挿入するためのDocument Endpointを控えておきます(コードに埋め込みます)
Lambda Functionのコード
今回作成したのは、以下のようなコードになります。
var aws = require('aws-sdk'); var zlib = require('zlib'); exports.aws = aws;// for local test purpose var CLOUDSEARCH_ENDPOINT = "CloudSearchのDocument Endpoint"; exports.handler = function(event, context) { console.log('Received event:'); var bucket = event.Records[0].s3.bucket.name; var key = event.Records[0].s3.object.key; var region = event.Records[0].awsRegion; var s3 = new aws.S3({ apiVersion : '2006-03-01', region : region }); s3.getObject({ Bucket : bucket, Key : key }, function(err, data) { if (err) { context.done('error', 'error getting file' + err); } else { var contentType = data.ContentType; var contentEncoding = data.ContentEncoding; if (contentType === "application/json" && contentEncoding === "gzip") { var logFileName = key.substr(key.lastIndexOf("/") + 1); var buf = data.Body; zlib.gunzip(buf, function(_, dezipped) { var json = JSON.parse(dezipped.toString('utf-8')); sendToCloudSearch(context,region,logFileName, json); }); } } }); }; function sendToCloudSearch(context,region,logFileName, json) { var records = json.Records; var searchRecords = []; for (var i = 0; i < records.length; i++) { var record = records[i]; var searchRecord = { "type" : "add", "id" : record.eventTime + "-" + record.requestID, "fields" : { "usertype" : record.userIdentity.type, "arn" : record.userIdentity.arn, "accesskeyid" : record.userIdentity.accessKeyId, "username" : record.userIdentity.userName, "eventtime" : record.eventTime, "eventsource" : record.eventSource, "eventname" : record.eventName, "awsregion" : record.awsRegion, "sourceipaddress" : record.sourceIPAddress, "useragent" : record.userAgent, "requestid" : record.requestID, "eventid" : record.eventID, "logfilename" : logFileName } }; searchRecords[i] = JSON.stringify(searchRecord); } var cloudsearchDomain = new aws.CloudSearchDomain({ endpoint : CLOUDSEARCH_ENDPOINT, region:region }); var params = { contentType : 'application/json', documents : "[" + searchRecords.join() + "]" }; cloudsearchDomain.uploadDocuments(params, function(err, data) { if (err) { context.done("error", err); } else { context.done(null, 'success'); } }); }
ポイントとしては、CloudTrailのログがgzip圧縮されているため解凍している点と、CloudSearchへデータを入れるため、データを整形している点です。CloudTrailのJSONはそのままCloudSearchに入れられないため、Lmabda内で整形しています。またこの際、ログファイル名やリージョンもCloudSearchの項目に入れていますので、後で元のログを取りやすくなっています。
検索してみる
CloudSearchのTest Searchを使って検索してみます。
今回はじめてCloudSearchを使いましたが、ソースIPやイベントで検索できるので、結構便利ですね。
開発について
今回開発はEclipse(+nodeclipse)で行いました。テストやモック、npmのインストールなど簡単に行えるので便利でした。
- 11 https://www.facebook.com/
- 7 http://t.co/XyTgOXpSNR
- 4 http://t.co/RoB6qu599E
- 3 http://l.facebook.com/l.php?u=http://d.hatena.ne.jp/c9katayama/20141124/1416789876&h=lAQEc1plR&enc=AZPreDLjBkqdrP5_Q_0lvPXpb8ooCeL1M2PQA1eL2yPo2gt1StWNovaWH2WNKGYvfVYj5VhbwXwwu0OUexF4lZPI6kv86usS9RrOUrPa4TZvyQ3fUDD-kB38EOodiiuROPrfB-iEJigwEBe1
- 2 http://m.facebook.com
- 2 http://t.co/Qoabke0HCf
- 2 http://www.google.co.jp/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CCAQFjAB&url=http://d.hatena.ne.jp/c9katayama/20141124/1416789876&ei=3YpyVLjWEODo3QGAlAE&usg=AFQjCNGkEOV4tm9q0ECin1IHLpcfZgSP1w
- 1 http://api.twitter.com/1/statuses/show/536682133666811904.json
- 1 http://api.twitter.com/1/statuses/show/536701583312949249.json
- 1 http://api.twitter.com/1/statuses/show/536706747147104257.json
- 2014-11-23 ngtokuの日記 3/19 15%
- 2014-11-23 老い耄れしんすけ日記 3/54 5%