AWSのセキュリティインシデントを捕捉する

by yayohei | November 09, 2020
infrastructure | #aws

こんにちは、 IT 基盤部第一グループの山本です。

今回は AWS のセキュリティインシデント通知のエスカレーションの仕組みについて紹介したいと思います。

概要

AWS 上のリソースで不審な動きをしているものが検知された場合、AWS はメールまたはサポートケースによって利用者へ通知を行います。セキュリティグループの設定不備によって EC2 インスタンスに侵入されたり、IAM の credential の漏洩によってリソースに対する操作が不正になされたりした際に送られる Abuse Report がその代表例です。このような不正利用はセキュリティインシデントにつながりうるため、即座に検知し対応する必要があります。

一方、DeNA は数百個の AWS アカウントを管理しているため、これらすべてのアカウントの通知を日々目視で確認することには限界があり、前述の通知を見落としたり初動が遅れたりする可能性がありました。

そこで、AWS からのセキュリティインシデントの通知を確実かつ即座に担当者にエスカレーションする仕組みが必要になりました。本記事ではその具体的な内容について紹介します。

構成図

PagerDuty の利用

PagerDuty とは

様々なシステムのアラートを集約して担当者へ通知し、アラートの対応状況を管理することができるインシデント管理サービスです。

PagerDuty Email integration の設定

PagerDuty の Email integration を利用することで設定した条件に一致した場合のみエスカレーションすることができます。

  • aws-incident1@example.pagerduty.com へのメールについては件名に関わらずエスカレーション
  • aws-incident2@example.pagerduty.com へのメールについては件名に Abuse Report が含まれている場合にのみエスカレーション

通知経路

AWS からのセキュリティインシデントの連絡経路は2種類あるとされています。

  • サポートケース経由の連絡
  • @amazon.com から AWS アカウントの root のメールアドレスへの連絡

サポートケース経由の検知

DeNA では、 AWS Organizations の機能を用いてアカウントを一元管理しています。 マスターアカウントという課金やアカウントの管理を行う親アカウントが存在し各アカウントはこの親アカウントに紐づいています。 マスターアカウントの IAM の credential を用いることで IAM の switch role という機能を用いて各アカウントの API を実行することができます。 この機能を用いて各子アカウントのサポートケースの API を叩き、対象となるケースが存在するかを確認します。もし該当するケースが存在した場合は PagerDuty に通知します。

セキュリティインシデントとみなす条件は、以下のように設定しています。

  • 言語は en
  • ステータスは 未解決
  • @amazon.com からのメールである
  • カテゴリが security を含む
  • 重要度は urgent もしくは、 critical

具体的には以下サンプルのように抽出を行います。

import datetime
import boto3

seconds = 60 * 5
delta = datetime.datetime.now(datetime.timezone.utc) - \
    datetime.timedelta(seconds=seconds)
after_time = delta.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'

credentials = boto3.session \
  .Session(profile_name='sts_profile') \
  .client('sts') \
  .assume_role(
      RoleArn='arn:aws:xxx:role/xxx',
      RoleSessionName='sts_session',
  )['Credentials']

support_client = boto3.client(
    'support',
    region_name='us-east-1',
    aws_access_key_id=credentials['AccessKeyId'],
    aws_secret_access_key=credentials['SecretAccessKey'],
    aws_session_token=credentials['SessionToken'],
)
cs = support_client.describe_cases(
    afterTime=after_time,
    language='en',
    maxResults=30,
    includeResolvedCases=False,
)
for c in cs['cases']:
    if c['categoryCode'].lower().find('security') > -1 and \
        c['submittedBy'].lower().endswith('@amazon.com') and \
            c['severityCode'].lower() in ['urgent', 'critical']:

この条件に合致するケースが存在するかを確認し、もし存在すれば PagerDuty を発火させる、というバッチスクリプトを定期的に実行することでサポート経由で通知がなされた場合の検知を行なっています。

メール経由の検知

AWS からのセキュリティインシデントの通知は対象 AWS アカウントの root のメールアドレスには必ず通知される一方で、同時にサポートケースも切られるかどうかはケースバイケースです。したがって AWS アカウントの root へのメールも監視する必要があります。

まず、全 AWS アカウントの root へのメールを一箇所に集約する方法を考えます。DeNA では AWS アカウントの root のメールアドレスに Google Group を利用しています。AWS アカウントごとに固有の Google Group を用いていますが、これらの Google Group のメンバに、ある特定の Google Group (以降、集約用 Google Group と呼ぶ) を含めることで、集約用 Google Group にすべてのメールを集めることができます。

次に、集約用 Google Group のメンバに aws-incident2@example.pagerduty.com を含めます。このようにすることで全 AWS アカウントの root へのメールが PagerDuty にも流れるようになります。

最後に PagerDuty に集められたメールに対するフィルタリングを考えます。 AWS アカウントの root へのメールはセキュリティインシデント以外にも様々な通知がなされるため、サポートケースの場合と同様の条件で該当するメールのみを抽出します。具体的な設定方法は公式ドキュメントに譲ります。

以上で、メールのみでの通知の場合でも検知できるようになりました。

まとめ

本記事では、AWS からのセキュリティインシデントの通知をサポートケース、メールいずれの場合でも検知し、エスカレーションする仕組みについて紹介しました。前者は AWS Organization を利用したサポートケースの全探索およびフィルタリング、後者は Google Group によるメール集約と PagerDuty のフィルタリングによって実現しています。本記事がクラウド利用におけるセキュリティ強化の一助となれば幸いです。