やりたいこと

AWSのリソースが使うIPアドレスレンジは、以下に公開されています。

https://ip-ranges.amazonaws.com/ip-ranges.json

ちょくちょく更新されますが、FireWallやWAFの設定に反映させる必要があるシステムをお持ちのプロジェクト担当者へ、正確かつ迅速に通知することを目標に自動化システムを構築しました。

実現

AWSのリソースが使うIPアドレスレンジの変更は、SNSで受信することができるようです。 また、担当者への連絡はBacklogを使うこととします。

以下のような構成で実現します。

20151216134539

S3

S3に通知を受ける直前のIPアドレスレンジを保管しておきます。 バケット名は適当に。

Lambdaファンクション

IAMロールには、S3の読み書き権限を付けておきます。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import httplib
import json
import difflib

import boto3

s3 = boto3.resource('s3')

import pprint
pp = pprint.PrettyPrinter(indent=4)



API_KEY               = "<Backlogより発行>"
BACKLOG_HOST          = "<Backlogスペース + ドメイン>"

S3_BACKET_NAME        = "<バケット名>"
S3_LAST_IP_RANGE_OBJ  = "last-ip-range.json"


def get_project_id(project_code):

    uri = "/api/v2/projects/%s?apiKey=%s" % (project_code, API_KEY)

    connect = httplib.HTTPSConnection(host = BACKLOG_HOST, port = 443)
    connect.request("GET", uri)
    response = connect.getresponse()

    body = response.read()

    connect.close()

    data = json.loads(body)

    project_id = data['id']

    return project_id


def post_issue(project_id, summary, issue_type_id, priority_id, description):

    data = {
        "projectId"   : project_id,
        "summary"     : summary,
        "issueTypeId" : issue_type_id,
        "priorityId"  : priority_id,
        "description" : description
    }

    params = json.dumps(data)
    headers = {
        "Accept":"application/json",
        "Content-Type":"application/json",
    }
    uri = "/api/v2/issues?apiKey=%s" % (API_KEY)

    connect = httplib.HTTPSConnection(host = BACKLOG_HOST, port=443)
    connect.request("POST", uri , params, headers)
    response = connect.getresponse()

    connect.close()

def download_ip_range(file):
    uri = "/ip-ranges.json"

    connect = httplib.HTTPSConnection(host = "ip-ranges.amazonaws.com", port = 443)
    connect.request("GET", uri)
    response = connect.getresponse()

    body = response.read()

    f = open(file, "w")
    f.write(body)
    f.close()

    connect.close()

    return

def construct_description(diff):
    description =  u"AWSの使用するIPアドレスレンジに更新がありました。"
    description += u"変更内容は以下です。"
    description += 'n'
    description += "{code}n"
    for buf in diff:
        description += buf
    description += "{/code}n"

    print(description)

    return description

def lambda_handler(event, context):

    last_ip_range_file    = '/tmp/' + S3_LAST_IP_RANGE_OBJ + '_last'
    current_ip_range_file = '/tmp/' + S3_LAST_IP_RANGE_OBJ + '_current'

    download_ip_range(current_ip_range_file)
    s3.meta.client.download_file(S3_BACKET_NAME, S3_LAST_IP_RANGE_OBJ, last_ip_range_file)

    last_ip_range    = open(last_ip_range_file, "r")
    current_ip_range = open(current_ip_range_file, "r")

    diff = difflib.context_diff(last_ip_range.readlines(),
                                current_ip_range.readlines(),
                                fromfile='before',
                                tofile='after')

    description = construct_description(diff)

    summary = "[連絡] AWSリソースのIPアドレスレンジに更新がありました"
    issue_type_id = 3
    priority_id   = 3

    # 通知したいプロジェクトを追加
    project_ids = []
    project_ids.append(get_project_id("HOGE"))
    project_ids.append(get_project_id("FUGA"))

    for project_id in project_ids:
        post_issue(project_id, summary, issue_type_id, priority_id, description)

    response = s3.meta.client.upload_file(current_ip_range_file, S3_BACKET_NAME, S3_LAST_IP_RANGE_OBJ)

SNS

こちらのサイトを参考にTopic ARNを設定します。 ProtocolはLambda、Endpointは先ほど作ったファンクションを選択します。

20151216152842

Lambdaのイベントソースに反映されます。

20151216153044

結果

ちゃんとBacklogに投稿されました! Lambdaの恩恵、デカすぎです!!

20151216160000

元記事はこちら

AWSのIPアドレスレンジ変更をBacklogに通知する(SNS + Lambda + S3)【cloudpack大阪BLOG】