AWS Trusted Advisorを利用したセキュリティ通知について

はじめに

こんにちは/こんばんはー。
クラウドCoEユニットの矢吹です。
「ファイアーエムブレム 風花雪月」が発売されまして、毎日楽しく過ごしています!
クラウドCoEユニットは5月末からメンバーが1人増えまして、現在3人体制で頑張っていて、 新しい方にはGCP領域において大活躍して頂いてるので、いつかこのブログにも登場してもらいたいなーって思っています。

クラウドCoEとしての動き(AWSのみ)

せっかくなんで、今期(2019年4月~)どんなことをやったかをさらっと書きまして、主題に移ろうかなと思います。
現在アドウェイズではAWS環境・GCP環境・vCenter(オンプレ)環境がありますが、年々AWSアカウントやGCPプロジェクトも増え、色んな方面での管理や改善が必要になりました。 その上で今期AWSに関してはセキュリティ・コストに着目して動き出しました。
以下が今期AWSにおいてクラウドCoE主導で動いたところです。(細かいものは省略)

  • セキュリティ関連
    • Trusted Advisorを利用したセキュリティ通知 ⇨ 今回のブログ
    • IAM管理
      • インフラ/サービス側のIAM権限の取り決め
      • SwitchRole導入 (ブログ書かれてます)
      • MFA(ルートユーザーもIAMも)
  • コスト関連
    • RI購入ルール決め
    • AWS Budgets機能を利用した予算アラート設定

動けば動くほど、あれもこれもってなってやることが積まれていくので、優先順位つけて取り組んでる日々です。

今回の話

さて、今回はAWS Trusted Advisorを利用しまして、アドウェイズ で管理しているAWSアカウント全体に対して、セキュリティの項目がアラートになった場合にSlackに通知する仕組みを作ったお話です。

実現したこと

Trusted Advisorのセキュリティの項目がERRORになった時に・・・
f:id:AdwaysEngineerBlog:20190822153325p:plain
Slackに流す!!
f:id:AdwaysEngineerBlog:20190822153344p:plain

仕組み

1.Lambdaの設定(Slack通知する部分)

Lambdaのソースコード(Python3.7)

import json
import os
import boto3
from botocore.vendored import requests
import logging
 
# Slack Incomming Webhooks URL
SLACK_POST_URL ="https://hooks.slack.com/services/WebHookURL記入してください" 
logger = logging.getLogger()
 
# ステータス
def webhook_icon(status=''):
    if status == 'INFO':
        return ':information_source:'
    elif status == 'WARN':
        return ':warning:'
    elif status == 'ERROR':
        return ':error:'
    elif status == 'OK':
        return ':ok:'
    else:
        return ':rotating_light:'
 
# slack表示の時のバー
def attachement_color(status=''):
    if status == 'INFO':
        return '#CCCCCC'  # 灰
    elif status == 'WARN':
        return '#FFFF00'  # 黄
    elif status == 'ERROR':
        return '#FF0000'  # 赤
    else:
        return '00ff00'   # 緑
 
# メイン
def lambda_handler(event, _context):
    account_id = event.get('account','123456789012')
    time = event.get('time')
    region = event.get('region','null')
    detail = event.get('detail', {})
    status = detail.get('status', 'ERROR')
    resource = detail.get('resource_id','null')
    check_name = detail.get('check-name','null')
    check_detail = detail.get('check-item-detail','null')
     
    # pythonでAWSアカウントのエイリアスを表示する
    iam = boto3.client('iam')
    paginator = iam.get_paginator('list_account_aliases')
    for response in paginator.paginate():
        account_aliases = response['AccountAliases']
    print(event)
    print(type(account_aliases))
    slack_post_template = {
        "text": "*AWS Trusted Advisorのステータス変更を検知しました*",
        "username": "Trusted Advisor",
        "icon_emoji": webhook_icon(status=status),
        "attachments": [
            {
                "fallback": check_name,
                "color": attachement_color(status=status),
                "author_name": "Trusted Advisor セキュリティ URLリンク",
                "author_link": "https://console.aws.amazon.com/trustedadvisor/home?#/category/security",
                "fields": [
                    {
                        "title": "ステータス",
                        "value": status,
                        "short": False
                    },
                    {
                        "title": "対応必要箇所",
                        "value": check_name
                    },
                    {
                        "title": "対象AWSアカウント",
                        "value": account_aliases[0] + "(" + account_id + ")"
                        #"value": "{account_aliases}({account_id})".format(account_aliases = account_aliases[0], account_id = account_id)
                    },
                    {
                        "title": "リソース",
                        "value": resource,
                        "short": False
                    },
                ]
            },
            {
                "title": '詳細',
                "fallback": check_name,
                "color": attachement_color(status=status),
                "text": "```\n{0}\n```".format(check_detail)
            }
        ]
    }
    requests.post(SLACK_POST_URL, data=json.dumps(slack_post_template))

2.CloudWatch Eventsのトリガー設定(Trusted Advisorのチェックに引っかかったらLambda動かす)

f:id:AdwaysEngineerBlog:20190822153453p:plain

イベントパターン内容

{
  "detail-type": [
    "Trusted Advisor Check Item Refresh Notification"
  ],
  "source": [
    "aws.trustedadvisor"
  ],
  "detail": {
    "check-name": [
      "Exposed Access Keys",
      "Amazon S3 Bucket Permissions",
      "Amazon RDS Public Snapshots",
      "Amazon RDS Security Group Access Risk",
      "Amazon EBS Public Snapshots",
      "ELB Listener Security",
      "ELB Security Groups",
      "Security Groups - Unrestricted Access",
      "Security Groups - Specific Ports Unrestricted",
      "IAM Password Policy"
    ],
    "status": [
      "ERROR"
    ]
  }
}

3.cron設定(Trusted Advisorが1週間に一回しかチェックしない仕様のため)

定期的に動かしているシェルスクリプト

profile_list=($(cat ~/.aws/credentials | grep -oe "[a-z].*@adways.net"))
 
for profile in ${profile_list[@]}; do
  security_id_list=($(aws support describe-trusted-advisor-checks --region us-east-1 --language en --profile $profile | jq -c ".checks[] | [ .category , .name , .id]" | grep security | sort | cut -f 3 -d "," | cut -f 2 -d "\""))
    for check_id in ${security_id_list[@]}; do
      aws support refresh-trusted-advisor-check --check-id "$check_id" --region us-east-1 --profile $profile
    done
done

仕組みは上記の感じです!
また、実際の展開の時はCloudFormationで書いて、CLIでばっと全体に配布しちゃいました。

最後に

仕組みを作ったのが4月で全体展開したのが8月だったので、ちょっと忘れかけでドキドキしながら展開しましたが、設定の展開自体は上手くいったので良かったです。(大量にアラート流れたけど)
では、またいつか〜。