Amazon S3の誤った公開に気づく! 通知の仕組み

Amazon S3の誤った公開に気づく! 通知の仕組み|ANDPAD Advent Calendar 2022

こちらは ANDPAD Advent Calendar 2022 の19日目の記事です。

こんにちは。

アンドパッドSREの宜野座です。

今回はアドベントカレンダーということで、Amazon S3の公開を検知してSlackに通知する仕組みをシンプルに行う方法に関して書こうと思います。

Amazon S3の重要性

※ 以降、本文中ではAmazon S3をS3と短縮表記します。

AWSを利用されている場合、S3はさまざまなデータを溜め込みデータレイクとして利用されている方も非常に多いかと思います。

オブジェクトストレージとして、多様なデータを大量に投入することができ、非常に耐久性も高く、容量も無制限(単一データサイズの制限はアリ)に利用することができます。

aws.amazon.com

顧客の情報、画像、資料やログデータを溜め込んで利用しているケースもあり、非常に重要なデータが置かれる場所です。

そのためAWSでは、S3を保護するためにバケットポリシーやバケットACL、ブロックパブリックアクセス、暗号化などさまざまな対策法が用意されています。

重要な場所でありデータを保護するための設定が多数存在しますが、やはりS3からの情報漏洩というのはなくなりません。

そしてそのケースの多くが設定ミスだと言われています。

news.mynavi.jp

www.trendmicro.com

iototsecnews.jp

S3のセキュリティ全般の注意点は以下の記事も参考になります。

blog.flatt.tech

S3バケットの公開を防ぐには

S3はいくつかクリックしたり、CLIを実行したり非常に簡単に作成することができます。

設定もシンプルであるが故に、詳しい方でも設定ミスをする可能性があり、正しいと思って公開設定を入れたが実は必要なかったなどのケースはあるかと思います。

では、S3バケットの誤った公開を防ぐにはどうしたらよいのでしょうか。

S3バケットの公開を防ぐには例として以下のような対策が挙げられるかと思います。

  • S3バケットの公開を禁じる
  • S3の公開を検知して、対応する
    • S3が公開されたことを検知してオブジェクトが投入される前に不必要な公開を防ぐ

前者はシンプルに設定でき参考になる記事もありますが、アカウント全体に影響があり導入をしにくいケースもあるかと思います。

そのため、今回は後者の検知をする方法の一例を紹介します。

S3の公開検知の例

S3の公開検知にもいくつか方法があり、今回は次の2つを掲載しています。

  • AWS Config を利用する方法
  • Amazon Guard Duty を利用する方法

AWS Config を利用する方法

以下のアーキテクチャでS3が公開されたことを検知しようと思います。

検知フローとしてはざっくり以下になります。

  1. S3が公開されたことをAWS Config マネージドルールで検知する
  2. EventBridgeでAWS Configのコンプライアンスステータスの変更をトリガーにLambdaを実行する
  3. LambdaでS3のバケット名と注釈を合わせて、Slackに通知する

それでは実現していくためにリソースの作成を行います。

Lambdaの作成

まずはLambdaを作成していきます。

本記事ではPython3.9でランタイムを設定していますが、使いやすい言語で作成していただけたらと思います。

  • Lambda名: <任意の名前>
  • ランタイム: Python 3.9
  • アーキテクチャ: arm64 (x86_64でも動きますが、コストパフォーマンスの観点で選択)
  • 環境変数に以下の値を設定
    • CHANNEL: <通知先のSlackチャンネルを指定>
    • ENV: <アカウントが複数ある場合に、どのアカウントなのかを指定>
    • WEB_HOOK_URL: <Slackのwebhook url を指定 >

<以下のコードをLambdaにDeployする>

import json
import subprocess
import urllib.request, urllib.parse, urllib.error
import os

WEB_HOOK_URL = os.environ['WEB_HOOK_URL']
CHANNEL = os.environ['CHANNEL']
ENV = os.environ['ENV']

def lambda_handler(event, context):
    if event['detail']['newEvaluationResult']['complianceType'] == "NON_COMPLIANT":
      print("Received event: " + json.dumps(event))
      message = create_message(event['detail'])
      return post_slack(message, CHANNEL, WEB_HOOK_URL)

def create_message(detail):
    bucket_name = detail['resourceId'] # バケット名
    check_reason = detail['newEvaluationResult']['annotation'] # どのルールで検出されたかの注釈
    message = "公開設定が適切か確認してください。\n" \
      "・バケット名: " + bucket_name + "\n" \
      "・注釈: " + check_reason
    return message

def post_slack(message, channel, web_hook_url):
    # メッセージの内容
    send_data = {
        "text": message,
        "channel": channel,
        "username": ENV + "でS3が全体公開されました",
        "icon_emoji": ":aws_s3:" # 任意のSlack emoji
    }

    send_text = ("payload=" + json.dumps(send_data)).encode('utf-8')

    request = urllib.request.Request(
        web_hook_url,
        data=send_text,
        method="POST"
    )
    with urllib.request.urlopen(request) as response:
        response_body = response.read().decode('utf-8')

    return response_body

AWS Configでマネージドルールを有効化

次にAWS Configでマネージドルールを有効化していきます。

有効化するルールは次の2つです。

  • s3-bucket-public-write-prohibited

Amazon S3 バケットでパブリック書き込みアクセスが許可されていないかどうかを確認します。このルールは、パブリックアクセスのブロック設定、バケットポリシー、およびバケットアクセスコントロールリスト (ACL) を確認します。 - https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-bucket-public-write-prohibited.html

  • s3-bucket-public-read-prohibited

Amazon S3 バケットでパブリック読み取りアクセスが許可されていないかどうかを確認します。このルールは、パブリックアクセスのブロック設定、バケットポリシー、およびバケットアクセスコントロールリスト (ACL) を確認します。 - https://docs.aws.amazon.com/ja_jp/config/latest/developerguide/s3-bucket-public-read-prohibited.html

またこの2つのルールのチェックは以下の頻度で行われるため、公開設定などが行われた時は迅速に気づくことができるかと思います。

  • 設定変更時 (S3の該当設定に変更が入った時)
  • 定期的 (ルールで1〜24時間の指定した頻度で定期的)

※ AWS Config自体の初期セットアップは公式ドキュメントが詳しいため、以下をご参照ください。

docs.aws.amazon.com

Event Bridgeを作成する

作成したLambdaをターゲットに以下のJSONを貼り付けて、カスタムパターンのEventBridgeを作成します。

  • 名前: <任意の名前>
  • イベントバス: default
  • ルールタイプ: イベントパターンを持つルール
  • イベントソース: その他
  • Creation method: Custom pattern (JSON editor)
  • イベントパターン: 以下のJSONを貼り付ける
{
  "source": ["aws.config"],
  "detail-type": ["Config Rules Compliance Change"],
  "detail": {
    "configRuleName": ["s3-bucket-public-write-prohibited", "s3-bucket-public-read-prohibited"]
  }
}
  • ターゲットタイプ: AWSのサービス
    • ターゲットを選択: Lambda
      • 機能: 上記で作成したLambdaを指定

これでリソースの作成作業は以上です。

動作確認

バケットポリシーやACLで公開されたS3バケットを作成してみます。

その後しばらく待機し、以下のような通知が確認できれば完了となります!

通知が来ない場合は、AWS Configのルールで対象のバケットが検出されているかを確認したり、検出されている場合はLambdaのログなどを確認すると良いかと思います。

※ AWS Config は次の小ネタに記載の方法で評価を手動実行することも可能です。

小ネタ: AWS Configで任意のタイミングでルールの評価を行う方法

AWS Configの評価をなるべく早く実行したい時は、各ルールの「再評価」をすることで即座にこのルールに引っ掛かっているかを確認することができます。

Amazon Guard Dutyを利用する方法

Guard DutyでS3の公開を通知する方法もあります。

Guard Dutyでは、S3の検出結果タイプとしてS3が公開されたことを検知する機能を備えています。

docs.aws.amazon.com

通知の仕組みは、以下の記事が詳しくまとまっておりますので参考にご覧ください。

dev.classmethod.jp

こちらも他のさまざまなリソースが検出対象となりますが、非常にシンプルなのでオススメです。

コストを抑えたかったり、通知をわかりやすくしたいなどを考えたときは AWS Config の通知も併せて検討すると良いかと思います。

まとめ

今回はアドベントカレンダーということで、S3の公開を検知する方法に関してご紹介させていただきました。

重要なデータの入っているS3ですので、気にされている方も多いかと思います。

少しでもそういった方の参考になれば、何よりです。

お読みいただきありがとうございました!

終わりに

アンドパッド SRE ではAWSアカウントのセキュリティ改善以外にも、様々なことに取り組んでいます。

SREチームの仲間を大募集中ですので、是非以下をご覧ください!

hrmos.co

その他にも、さまざまなポジションを募集しています!

詳しくは下記サイトをご覧ください。

engineer.andpad.co.jp

hrmos.co

明日は、図面チームの田上さんがDB設計で意識していることについての記事を公開する予定です! お楽しみに!