はじめに
S3のクロスアカウントアクセスを試していきます。
前回の記事では、データを使わせてもらう側のアカウントのLambdaから、データを作る側のアカウントにあるS3を参照しました。
今回、別アカウントのS3にファイルが置かれたときにLambdaを起動することを考えます。
S3のイベント通知は、送信先に
- Lambda
- SNS
- SQS
を選べるようです。
データを作る側にしてみると、データを使う側のLambda関数名を覚えておくのは嫌だと思うので、今回は送信先にSNSを選びました。 システムにつき1つ、SNSトピックを1つだけ設定しておき、あとは通知を受けて好きにするという形にしてみました。
もっと良い案がありましたらぜひコメントください。
前提
- AWSアカウントを2つ用意できていること。
- アカウントA(データを作る側)
- アカウントB(データを使わせてもらう側)
- S3とLambdaは、前回の記事のとおり用意できているものとします。
準備:(アカウントB)SNSトピックの作成
(アカウントB)SNSトピックの作成
SNSトピックを作成します。
(アカウントB)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画面に飛ぶことができます。
どんなログが出るか?
ログを見てみます。
{
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にアクセスする仕組みを作ってみました。
突っ込みどころはあるかもしれませんが今回はここまでです!