LoginSignup
5
3

More than 5 years have passed since last update.

IAM/S3のアクションをCloudTrailから通知する

Last updated at Posted at 2018-06-26

動機

AWSの操作についてはCloudTrailで記録できる訳ですが、セキュリティの観点から「ヤバそうな操作」は検知・通報されたほうが何かとエンタープライズな組織では安心かと思います。
AWS Configルールで打ち取る、GuardDutyを使う、evident.ioなどの3rdパーティーソリューション利用も考えられますが、お財布のご都合もあるので「まずはざっくりと拾おうぜ」という考え方もあろうかと思いやってみました。

(お財布のご都合がなければ全体的にAWS Configでいい(1項目につき\$0.003、1ルールにつき\$2.00)と思われます)

ヤバそうな操作

IAM関連の操作(ユーザー作成、ロール作成、ポリシーアタッチなど)やS3関連操作(バケット作成、バケットポリシー変更、Website Hostingの設定)あたり。

CloudTrail

  • まず「証跡情報」(Trail)を作成
    • S3バケットにLogを送るようにすると、そのイベントをSNSトピックに送ることができる
    • 届くのは、s3bucket名、ObjectKey。これをトリガーにobjectを取りに行ってgz解凍して、という流れになりそう
    • ただ、全部通知が来るので、全量欲しい訳ではない場合は過剰になる
    • 「IAMとS3関連のアクションだけ通知したい」には不向きかも
    • 今回はCloudWatch Logsに送って、そこからフィルタしたい

CloudTrail Logs

  • メトリクスフィルタからのアラームでやると、詳細が分からない
    • 検知はできるので、詳細は別途見ればいいという考えならばこれでもOKかも
  • そこでログストリーミングをサブスクリプション
  • サブスクリプションは1つのロググループに1つしか指定できない
    • Lambdaか、Elastic SearchServiceか
    • 変更もできない。。(削除して作成)
  • サブスクリプションフィルタ
    • フィルタパターンの書き方:https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html
    • ここで大枠を絞っておき、Lambda側で詳細を絞るのが良さそう
    • 例:{ (($.eventSource = "s3.amazonaws.com") || ($.eventSource = "iam.amazonaws.com")) && ($.eventName != "Get*") && ($.eventName != "List*") && ($.eventName != "Describe*")}
    • ただしログが大量になる場合にはLambdaだとつらそうなのでここで絞る案もありえる
  • 参考:セキュリティーグループが変更されたらSlackに通知する | ハンズラボエンジニアブログ

LambdaでSNSにPublish

log2sns/index.js
var zlib = require('zlib');
var aws = require('aws-sdk');
var sns = new aws.SNS({ region: 'ap-northeast-1' });

exports.handler = function(input, context, callback) {
    var data = new Buffer(input.awslogs.data, 'base64');
    zlib.gunzip(data, function(e, result) {
        if (e) {
        callback(e);
        } else {
            result = JSON.parse(result.toString('utf-8'));
            var events = result['logEvents'].filter(
                        function(evt) { return evt['message'].match(process.env.FILTER_PATTERN);}
                    ).filter(
                        function(evt) { return !evt['message'].match(process.env.FILTER_PATTERN_EXCLUDED) ;}
                    ).map(
                        function(evt) { return evt['message'] }
                    );
            console.log('processing ' + events.length + '/' + result['logEvents'].length + ' events.');
            if (events.length === 0) {
                callback();
                return;
            }
            if (0 < events.length) {
                // has error log
                var subject = 'CloudWatch logs by lambda';
                var payload = { default: '' };
                payload['default'] += 'NotifyAt: ' + new Date() + '\n';
                payload['default'] += 'Log: ' + result['logGroup'] + ' - ' + result['logStream'] + '\n';
                payload['default'] += 'Filter: ' + result['subscriptionFilters'] + '\n';
                payload['default'] += 'Messages:\n';
                payload['default'] += events.join('\n---\n');
                sns.publish({
                    Subject: subject,
                    Message: JSON.stringify(payload),
                    MessageStructure: 'json',
                    TargetArn: process.env.SNS_ARN
                }, function(err, data) {
                    if (err) {
                      callback(err);
                    } else {
                      callback(null, data);
                    }
                });
            }
        }
    });
};
  • あとはこのSNSにサブスクライブすれば各種通知が可能に。

つまづいたポイント

  • IAMのTrailがストリーミングされてこない・・・
    • リージョンがus-east-1のtrailだからではないか?Trailにはあるが、Logsに出ていない。
    • 東京のCloudTrail設定が「証跡情報を全てのリージョンに適用」が「いいえ」であるためと思われる。
    • us-east-1のTrailを有効化、CloudWatch Logsのロググループは共通とするように設定してみる。
      • 名前は同じでもLoggroupは別になった・・・(リージョンごとにある)
    • ストリーミング先のLambdaも別になる
      • Publish先のSNSは同じものを指定できる、とはいえLambdaのロジックが二重管理となってしまう
      • そのまま内容を別のLambdaに転送するようにする、など解決策はあろうかと思われるが、シンプルさに欠ける。

雑感

  • ”エンタープライズな組織”ならカスタムルールは入れないまでも、AWS Configの費用は誤差範囲のような気もしてきました。
  • SNSを挟んでいるので、これをトリガーにSlackへ通知やConnectで電話連絡なんかもできそう。
    • さらに「本当にヤバいやつ」はLambdaを呼んで直接Killしにいくような事もできそう。
    • でもそこまでやるならCloud Custodianのようなものを検討したほうがいいような気もする。。
5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3