- ハンズラボさんのブログにslackに通知する記事が出てたのでmattermost版を作ってみた
セキュリティーグループが変更されたらSlackに通知する
仕組みは上記のものとほとんど同じで、
CloudTrailが検知したイベントログをCloudWatchLogsに吐いて
そのログをトリガーにLambda Functionを実行してmattermostにwebhookします。
手順
CloudTrailの設定
- Trailsから任意のtrailを選択する
- CloudWatch LogsセクションのConfigureをクリック
- Log Groupを作成(Continue)
- Log GroupとLog Streamを作成してよいか的なことを聞かれるのでAllowをクリック
webhook用のURLの取得
- サイドメニューから総合機能>>内向きのウェブフック>>内向きのウェブフックを追加するをクリック
- 表示名と説明を入力し、通知したいチャンネルを選択して保存します。
- URLが表示されるので記録しておきます。
Lambda Functionの作成
作業ディレクトリの作成
$ mkdir lambda-work
$ cd lambda-work
requestsのインストール
今回はpythonの外部ライブラリのrequestsを使用したのでそれをインストールします
$ pip install requests -t .
mattermost-echo.pyの作成
Lambdaハンドラーから呼び出されるプログラムです。
# -*- 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。
トリガーの設定
- CloudWatchLogsの画面を開く
- 先程作成したLog Groupのチェックボックスを選択する(デフォルトならCloudTrail/DefaultLogGroup)
- Stream to AWS Lambdaをクリック
- mattermost-echoを選択
- ログ形式を選択します。AWS CloudTrailを選択
- filter patternを聞かれるので下記を入力してNextをクリックした後、Start Streamingをクリックします。
{ ($.eventName = "CreateSecurityGroup") || ($.eventName = "DeleteSecurityGroup") || ($.eventName = "AuthorizeSecurityGroupIngress") || ($.eventName = "RevokeSecurityGroupIngress")}
この時点でセキュリティグループに変更があれば通知されると思います。
CloudTrailの保存間隔が5分のため若干ラグがあるのでリアルタイムではないですが、十分です。
かなり一部分ですが、こんな感じの通知が来ます。
他にもアカウントIDや変更操作したユーザー名等も出すようになっています。
mattermostのテーブル表示を使っているのでslackの人はslackの記法でtextを整形してあげると綺麗になると思います。
- いつのまにかSGのルールが変わってる!?っていう環境下の人は是非使ってみてください。
以上!!