AWS:クロスアカウントのS3イベントをSNSで検知する

2022/8/28

(最終更新: 2022/8/28

アイキャッチ

はじめに

S3のクロスアカウントアクセスを試していきます。

前回の記事では、データを使わせてもらう側のアカウントのLambdaから、データを作る側のアカウントにあるS3を参照しました。

AWS:S3のクロスアカウントアクセスを試してみよう

AWS:S3のクロスアカウントアクセスを試してみよう

AWSで、ほかのアカウントに対してもS3でデータ提供することが可能です。AWS初心者が試してみました。

https://bunsugi.com/s3-cross-acount-access

今回、別アカウントのS3にファイルが置かれたときにLambdaを起動することを考えます。

S3のイベント通知は、送信先に

  • Lambda
  • SNS
  • SQS

を選べるようです。

イベント通知送信先

データを作る側にしてみると、データを使う側のLambda関数名を覚えておくのは嫌だと思うので、今回は送信先にSNSを選びました。 システムにつき1つ、SNSトピックを1つだけ設定しておき、あとは通知を受けて好きにするという形にしてみました。

システム構成図 システム構成図

もっと良い案がありましたらぜひコメントください。

前提

準備:(アカウントB)SNSトピックの作成

(アカウントB)SNSトピックの作成

SNSトピックを作成します。

SNSトピックを作成

(アカウントB)SNSのアクセスポリシーを設定

アクセスポリシーに、以下ポリシーを追加します。

アクセスポリシー

SNSのアクセスポリシー
{
  "Version": "2008-10-17",
  "Id": "__default_policy_ID",
  "Statement": [
    {
      "Sid": "__default_statement_ID",
      "Effect": "Allow",
      "Principal": {
        "AWS": "*"
      },
      "Action": [
        "SNS:Publish",
        "SNS:RemovePermission",
        "SNS:SetTopicAttributes",
        "SNS:DeleteTopic",
        "SNS:ListSubscriptionsByTopic",
        "SNS:GetTopicAttributes",
        "SNS:AddPermission",
        "SNS:Subscribe"
      ],
      "Resource": "arn:aws:sns:ap-northeast-1:<<アカウントBのID>>:cross-acount-s3-to-lambda",
      "Condition": {
        "StringEquals": {
          "AWS:SourceOwner": "<<アカウントBのID>>"
        }
      }
    },
    {      "Sid": "S3-policy",      "Effect": "Allow",      "Principal": {        "Service": "s3.amazonaws.com"      },      "Action": "SNS:Publish",      "Resource": "アカウントBのSNSのARN(arn:aws:sns:ap-northeast-1:アカウントBのアカウントID:cross-acount-s3-to-lambda)",      "Condition": {        "StringEquals": {          "AWS:SourceArn": [            "arn:aws:s3:::バケット名①",            "arn:aws:s3:::バケット名②"          ]        }      }    }  ]
}
  • ActionにはSNS:Publishを設定します。
  • Resourceには、SNSのARNを設定します。
  • AWS:SourceArnには、SNSにイベントを送りたいS3バケット(ここではアカウントAのバケット)を設定します。複数設定してみました。
    • アカウントA(データを作成するシステムがデータをおくバケット)
    • アカウントB(練習用のバケット)

(アカウントB)サブスクリプション作成

サブスクリプション作成画面

サブスクリプション作成設定

(アカウントA)S3のイベント設定

(アカウントA)イベント通知を作成

プロパティイベント通知イベント通知を作成

バケットのイベント通知を作成

(アカウントA)イベント通知の設定

イベントタイプ:すべてのオブジェクト作成イベントにしてみる。

イベントタイプ

送信先をSNSトピック(アカウントB)にします。

送信先

イベント通知が作成できた。

イベント通知が作成

イベントが動くことの確認

(アカウントB)Lambda関数の中でeventを出力しておく

Lambda関数の引数になるeventを出力するようにしておきます。

import boto3
import json

def lambda_handler(event, context):    print("--------")
    print(event)
    省略

(アカウントA)S3バケットにアップロードする

S3バケットに、適当なファイルをアップロードする。

(アカウントB)Lambdaログの確認

Lambda画面からCloudWatch画面に飛ぶことができます。

Lambdaログの確認

ログ出力画面

どんなログが出るか?

ログを見てみます。

{
    Records: [
        {
            EventSource: "aws:sns",
            EventVersion: "1.0",
            EventSubscriptionArn: "SNSのARN",            Sns: {
                Type: "Notification",
                MessageId: "xxxxxxx",
                TopicArn: "SNSのARN",
                Subject: "Amazon S3 Notification",                Message:
                    '★次に記載します★',
                Timestamp: "2022-08-27T13:49:42.167Z",
                SignatureVersion: "1",
                Signature:
                    //省略,
                SigningCertUrl:
                    //省略,
                UnsubscribeUrl:
                    //省略,
                MessageAttributes: {},
            },
        },
    ],
}

どんなイベントがS3に起こったのかは、Messageオブジェクトの中にありました。

{
    Records: [
        {
            eventVersion: "2.1",
            eventSource: "aws:s3",
            awsRegion: "ap-northeast-1",
            eventTime: "2022-08-27T13:49:40.369Z",
            eventName: "ObjectCreated:Put",            userIdentity: // 省略,
            s3: {                s3SchemaVersion: "1.0",                configurationId: "aa",                bucket: {                    name: "バケット名",                    ownerIdentity: xxx,                    arn: "バケットのARN",                },                object: {                    key: "%E3%81%A6%E3%81%99%E3%81%A8%E3%81%A6%E3%81%99%E3%81%A8.txt",                    size: 0,                    eTag: "xxxxx",                    sequencer: "xxxxx",                },            },        },
    ],
}

アカウントAのバケットに、イベント通知を設定したときにもログが出ているように見えます。

"Event":"s3:TestEvent"という記述になっています。

おわりに

別のシステムのデータを使いたいときに、ファイルアップロード契機でクロスアカウントアクセスでS3にアクセスする仕組みを作ってみました。

突っ込みどころはあるかもしれませんが今回はここまでです!



個別連絡はこちらへ→Twitterお問い合わせ

プロフィール

プロフィールイメージ

はち子

事業会社のシステム部門で働きはじめて5年目の会社員。システム企画/要件定義/システムアーキテクチャ等。

Twitter→@bun_sugi

過去の記事について

はてなブログに掲載の記事(主にプログラミングメモ)についてはこちらに掲載しております。(本ブログに移行中)

タグ一覧

関連記事

Copyright© 2023, エンジニアを目指す日常ブログ

お問い合わせ|プライバシーポリシー