LoginSignup
5
4

More than 5 years have passed since last update.

セキュリティグループが変更されたのを検知してmattermostに通知する

Last updated at Posted at 2016-10-24

仕組みは上記のものとほとんど同じで、
CloudTrailが検知したイベントログをCloudWatchLogsに吐いて
そのログをトリガーにLambda Functionを実行してmattermostにwebhookします。

手順

CloudTrailの設定

  1. Trailsから任意のtrailを選択する
  2. CloudWatch LogsセクションのConfigureをクリック
  3. Log Groupを作成(Continue)
  4. Log GroupとLog Streamを作成してよいか的なことを聞かれるのでAllowをクリック

webhook用のURLの取得

  1. サイドメニューから総合機能>>内向きのウェブフック>>内向きのウェブフックを追加するをクリック
  2. 表示名と説明を入力し、通知したいチャンネルを選択して保存します。
  3. URLが表示されるので記録しておきます。

Lambda Functionの作成

作業ディレクトリの作成

$ mkdir lambda-work
$ cd lambda-work

requestsのインストール

今回はpythonの外部ライブラリのrequestsを使用したのでそれをインストールします
$ pip install requests -t .

mattermost-echo.pyの作成

Lambdaハンドラーから呼び出されるプログラムです。

mattermost-echo.py
# -*- coding: utf-8 -*-
from __future__ import print_function

import base64
import zlib
import json
import time
import boto3
import requests
import sys
import logging
from ast import literal_eval

print('Loading function')
url = 'https://chat.infra.active-ssa.com/hooks/d1snbwu8wi8g38g7ssu5wj7wtw'
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):
    print(event)
    logger.info(event)
    data = zlib.decompress(base64.b64decode(event['awslogs']['data']), 16+zlib.MAX_WBITS)
    data_dict = literal_eval(data)
    data_list = (data_dict['logEvents'])
    print(data_list)

    for log in data_list:
        print(json.loads(json.dumps(log['message'])))
        log_json = json.loads(log['message'])
        name = str(log_json['eventName'])
        user = str(log_json['userIdentity']['userName'])
        region = str(log_json['awsRegion'])
        aws_account_id = str(log_json['recipientAccountId'])
        if 'ipPermissions' in log_json['requestParameters']:
            target_group = str(log_json['requestParameters']['groupId'])
            changes = json.loads(json.dumps(log_json['requestParameters']['ipPermissions']['items'], indent=2))
        else:
            target_group = str(log_json['responseElements']['groupId'])
            changes = None

        attache = []

        if not changes is None:
            for rule in changes:
                fromport = str(rule['fromPort'])
                if rule['ipRanges']:
                  ipranges = str(rule['ipRanges']['items'][0]['cidrIp'])
                else:
                  ipranges = None

                if rule['groups']:
                    groups = str(rule['groups']['items'][0]['groupId'])
                else:
                    groups = None

                toport = str(rule['toPort'])
                protocol = str(rule['ipProtocol'])

                if rule['ipv6Ranges']:
                    ipv6ranges = json.loads(json.dumps(rule['ipv6Ranges']))
                else:
                    ipv6ranges = None

                property = "|%(protocol)s|%(fromport)s|%(toport)s|%(ipranges)s|%(groups)s|%(ipv6ranges)s|" % locals ()
                attache.append(property)

        columns = ''
        for obj in attache:
            columns = columns + obj + "\n"

        if name == 'AuthorizeSecurityGroupIngress' or name == 'AuthorizeSecurityGroupEgress':
            message = 'セキュリティグループのルールが追加されました。'
        elif name == 'RevokeSecurityGroupIngress' or name == 'RevokeSecurityGroupEgress':
            message = 'セキュリティグループのルールが削除されました。'
        elif name == 'CreateSecurityGroup':
            message = 'セキュリティグループが作成されました。'
        elif name == 'DeleteSecurityGroup':
            message = 'セキュリティグループが削除されました。'

        payload = {
            'icon_url': 'http://recipe.kc-cloud.jp/wp-content/uploads/2014/04/cloudtrail%E3%82%A2%E3%82%A4%E3%82%B3%E3%83%B3.png',
            'username': 'Changes Security Group',
            'text': "\n\
- *Permission changes*\n\
\n\
---\n\
|protocol    |from port   |to port   |ip ranges   |groups    |ipv6 ranges   |\n\
|:-----------|:-----------|:---------|:-----------|:---------|:-------------|\n\
%(columns)s\n\
---\n\
:warning: %(message)s\n\
```\n\
AWSAccountID : %(aws_account_id)s\n\
Region       : %(region)s\n\
TargetGroup  : %(target_group)s\n\
EventName    : %(name)s\n\
UserName     : %(user)s\n\
```" % locals ()
        }

        headers = {'content-type': 'application/json'}
        session = requests.Session()
        session.mount('http://', requests.adapters.HTTPAdapter(max_retries=2))
        session.mount('https://', requests.adapters.HTTPAdapter(max_retries=2))
        try:
            resp = session.post(url,
                                data=json.dumps(payload, ensure_ascii=False),
                                headers=headers,
                                timeout=30)
            logger.info(resp)
        except Exception as e:
            logger.error(e)
            time.sleep(30)
            resp = session.post(url,
                                data=json.dumps(payload, ensure_ascii=False),
                                headers=headers,
                                timeout=30)
            logger.info(resp)

    return str(resp)

URL等は任意に調整してください。
ほとんど初めて書くpythonコードなのでご容赦ください(rubyist)
and 間違いがあればご指摘ください。

これらをzipにかためてアップロードします
$ zip -r mattermost-echo.zip *
"mattermost-echo"という名前のLambda Function作成します。
Upload a ZIP fileを選択して、mattermost-echo.zipをアップロードします。
Handlerはmattermost-echo.lambda_handlerと入力してください。
Timeoutは1minにしました。(とりあえず)
そのままSave。

 トリガーの設定

  1. CloudWatchLogsの画面を開く
  2. 先程作成したLog Groupのチェックボックスを選択する(デフォルトならCloudTrail/DefaultLogGroup)
  3. Stream to AWS Lambdaをクリック
  4. mattermost-echoを選択
  5. ログ形式を選択します。AWS CloudTrailを選択
  6. filter patternを聞かれるので下記を入力してNextをクリックした後、Start Streamingをクリックします。
{ ($.eventName = "CreateSecurityGroup") || ($.eventName = "DeleteSecurityGroup") || ($.eventName = "AuthorizeSecurityGroupIngress") || ($.eventName = "RevokeSecurityGroupIngress")}

この時点でセキュリティグループに変更があれば通知されると思います。
CloudTrailの保存間隔が5分のため若干ラグがあるのでリアルタイムではないですが、十分です。
かなり一部分ですが、こんな感じの通知が来ます。
スクリーンショット 2016-10-24 20.15.19.png
他にもアカウントIDや変更操作したユーザー名等も出すようになっています。
mattermostのテーブル表示を使っているのでslackの人はslackの記法でtextを整形してあげると綺麗になると思います。

  • いつのまにかSGのルールが変わってる!?っていう環境下の人は是非使ってみてください。

以上!!

5
4
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
4