AWS CloudTrail Processing Libraryを試してみた

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

よく訓練されたアップル信者、都元です。AWS APIへのアクセスログ機能を提供するCloudTrail、皆様ご利用でしょうか。正直よく分からなければ、何も考えずにこのスクリプトを流して設定しておくことをお勧めします。

そういえば先日、フランクフルトリージョンがオープンしましたね。フランクフルトのCloudTrail有効化はお済みでしょうか? *1 まだであれば今すぐ設定しましょう!

CloudTrailログの活用

前述の通り、CloudTrailのログ出力は、とりあえず何も考えずに有効化しておくことがお勧めです。万一、セキュリティ事故を疑うような場面に遭遇しても、頑張ってログを解析することにより、いつ、だれが、何をしたのか、が克明に記録されており、追跡が可能になります。

しかしこのようなCloudTrailの活用法では、事故が発生したとしても、気づかなければ何もできません。言わば消極的な活用法です。可能であるならば、事故を疑うような場面が発生した際には、自動的に気付ければいいですよね。

とまぁ言うのは簡単ですが、正直なところ実装は難しいです。しかし、ある程度開発コストを掛けることができるのであれば、ログをリアルタイム *2に解析し、普段と違う動きがあった場合にアラートを上げる、というシステムを組むことも可能です。

CloudTrailのSNS通知機能

CloudTrailには、新しいログファイルが配信された時、Simple Notification Service (SNS)による通知を発生させることができます。システムによるログの自動解析を意識した機能だと思われます。

SNSで発生したメッセージは、その後に Simple Queue Service (SQS) をつなぎ込み *3、キューに貯めておきます。こうすることにより、仮にメッセージ発生時点でシステムが落ちていたとしても、復旧し次第解析にとりかかることができ、メッセージの取りこぼしが無くなります。

ログを煮るなり焼くなりする

あとは、メッセージに基いてログを取寄せ、解析します。

2014-11-06_1551

まぁ、口で言うのは簡単ですが恐らくこの「解析」が一番大変です。例えば「今まで見たことのないIPアドレスからのアクセスがあったら」、とかまぁ色々考えることは多いでしょう。だからここには深く触れません。

本エントリーはAWS CloudTrail Processing Libraryの紹介だから、それでいいんです。。。

AWS CloudTrail Processing Library

やっと本題。結局、SQSからメッセージを受け取って、S3からログをDLして、JSONを解析してオブジェクトにマッピングする、というところに本質的じゃない面倒臭さ *4があります。この部分を楽にしてくれるのがAWS CloudTrail Processing Libraryというわけです。

眠くなる前にコード行きましょう。CloudTrailからSNS→SQSの流れは設定しておき、Queue URLの準備はしておいてください。その上で'com.amazonaws:aws-cloudtrail-processing-library:1.0.0'をクラスパスに通し…。

AWSCredentialsProvider cred = ...;
ClientConfiguration config = new ClientConfiguration(QUEUE_URL, cred);

AWSCloudTrailProcessingExecutor executor = new AWSCloudTrailProcessingExecutor.Builder(
    new EventsProcessor() {
      
      @Override
      public void process(List<CloudTrailEvent> events) {
        for (CloudTrailEvent event : events) {
          logger.info(event.getEventData().toString());
        }
      }
    }, config).build();
executor.start();

うわー簡単。これだけでバックグラウンドでスレッドが1つ動き出します。CloudTrailがログを配信したタイミングで、そのログの内容がCloudTrailEvent型のオブジェクトにマッピングされ、EventsProcessorでハンドリングできます。

CloudTrailEventの中身はだいたいこんな感じです。

{
  CloudTrailEventData: {
    eventID = d9404158-09b4-4038-b88f-a5e20EXAMPLE,
    awsRegion = ap-northeast-1,
    eventVersion = 1.02,
    responseElements = null,
    sourceIPAddress = 0.0.0.0,
    eventSource = cloudtrail.amazonaws.com,
    requestParameters = {
      "trailNameList":[]
    },
    userAgent = signin.amazonaws.com,
    userIdentity = {
      UserIdentity: {
        accessKeyId = ASIAJ6FRHCZDZEXAMPLE,
        sessionContext = {
          SessionContext: {
            attributes = {
              mfaAuthenticated = true,
              creationDate = 2014-11-06T04:56:44Z
            }
          }
        },
        accountId = 000011112222,
        principalId = AIDAJXCUYSBS5NEXAMPLE,
        type = IAMUser,
        arn = arn:aws:iam::000011112222:user/miyamotodaisuke,
        userName = miyamotodaisuke,
        invokedBy = signin.amazonaws.com
      }
    },
    eventType = AwsApiCall,
    accountId = 000011112222,
    requestID = 838ff5c5-657b-11e4-867e-e5f0aEXAMPLE,
    eventTime = Thu Nov 06 15:09:49 JST 2014,
    eventName = DescribeTrails,
    recipientAccountId = 000011112222
  }
}

あとは煮るなり焼くなり…。

参考文献

脚注

  1. 本エントリー執筆時点で、前述のスクリプトは、まだフランクフルトに対応できません。近日修正されるはずです!
  2. APIアクセスの発生からログの出力まで十数分掛かるので、正確にはリアルタイムになりませんが。。。
  3. 参考: 【AWS】SQSキューの前には難しいこと考えずにSNSトピックを挟むと良いよ、という話
  4. オブジェクトになった後は、本質的なところなので各々が頑張ればいいのです。私も将来頑張るかもしれません。