はじめに
同じ社内の複数システムでファイルをやりとりしたい場合があると思います。その際、双方AWSであればS3のクロスアカウントアクセスが利用できます。
バケットポリシーを設定することで実現してみます。
構成図
オンプレのシステムは、別のシステムにファイル連携したいときはネットワーク接続をする必要がありましたが、AWSは簡単でいいですね。
後編はこちら。クロスアカウントのS3からイベントを受け取り、自身のLambda関数を発火させてみます。→AWS:クロスアカウントのS3イベントをSNSで検知する | エンジニアを目指す日常ブログ
前提
- AWSの2つのアカウント(アカウントA、アカウントB)が作成できていること。
- AWSのマネジメントコンソールに、2つのアカウントでそれぞれログインできること。
下準備:S3バケットとLambda関数の作成
(アカウントA)S3バケット作成
アカウントA(データを作る側のシステム)でS3バケットを作成します。
社内データを模擬しているので、当然パブリックアクセスはブロックします。
(アカウントB)Lambda関数作成
アカウントB(データを使わせてもらう側のシステム)で、S3にアクセスする処理を書くためのLambda関数を準備します。 もちろんLambdaでなくても良いです。
今回はPythonで作ります。
今回、Lambda関数のみ、うっかり東京リージョンではなく、バージニア北部リージョンに作成してしまいました。。東京リージョンでも同じようにできると思います。
練習用のS3バケット作成
次の章で、練習としてアカウントBのLambda関数からアカウントBのS3バケットにアクセスするので、アカウントB側にも適当にS3バケットを作っておきます。
練習①:Lambda関数から自分のアカウントのS3バケットにアクセスする
(アカウントB)LambdaのIAMロールにS3アクセス権限追加
設定⇒アクセス権限から、「実行ロール」に設定されているロールをクリックします。
今回は細かい設定はせず、S3へのフルアクセス権限を付けます。 JSONを直接書いても良いですし、ビジュアルエディターから設定しても良いです。
IAMロールにもともとアタッチしていたポリシーに対して、以下の部分(S3に関するオブジェクト)を追加できればOKです。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:us-east-1:<アカウントID>:*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:us-east-1:<アカウントID>:log-group:/aws/lambda/<Lambda関数名>:*"
},
{ "Sid": "VisualEditor2", "Effect": "Allow", "Action": "s3:*", "Resource": "*" } ]
}
(アカウントB)Lambdaから自分のアカウントのS3にアクセス
S3バケットの中身を1件取得するLambda関数
Lambda関数の中身を書きます。
PythonでAWSのリソースを触るためにはboto3
というモジュールを利用します。
import boto3
import json
def lambda_handler(event, context):
print("--------")
print(event)
client = boto3.client('s3')
obj = client.list_objects(Bucket='<バケット名>')
print("--------")
print(obj['Contents'][0])
print("--------")
(参考)
取得できるobj
の中身は以下のようになっています。(固有情報は--------
に書き換えてます)
上記のソースコードでは、Contents
の1件目を取ってきています。
{
ResponseMetadata: {
RequestId: "----------",
HostId: "----------",
HTTPStatusCode: 200,
HTTPHeaders: {
"x-amz-id-2":
"----------",
"x-amz-request-id": "----------",
date: "Sun, 28 Aug 2022 02:57:37 GMT",
"x-amz-bucket-region": "ap-northeast-1",
"content-type": "application/xml",
"transfer-encoding": "chunked",
server: "AmazonS3",
},
RetryAttempts: 1,
},
IsTruncated: False,
Marker: "",
Contents: [
{
Key: "folder01/",←フォルダ
LastModified: datetime.datetime(2022, 8, 27, 12, 2, 30, (tzinfo = tzlocal())),
ETag: '"----------"',
Size: 0,
StorageClass: "STANDARD",
Owner: {
DisplayName: "----------",
ID: "----------",
},
},
{
Key: "folder01/test.txt",←ファイルのパス
LastModified: datetime.datetime(2022, 8, 27, 12, 2, 39, (tzinfo = tzlocal())),
ETag: '"----------"',
Size: 10,
StorageClass: "STANDARD",
Owner: {
DisplayName: "----------",
ID: "----------",
},
},
{
省略
}
],
Name: "<バケットの名前>",
Prefix: "",
MaxKeys: 1000,
EncodingType: "url",
};
デプロイ
「Deploy」をクリックしデプロイ。
テスト実行
「Test」をクリックして実行します。テスト内容は適当でよいです。
練習①は終わり。
練習②:別のアカウント(アカウントA)のS3にアクセス
次に、そのまま別アカウントのS3にアクセスしようとどうなるか試してみます。結果は当然アクセスNGになります。
(アカウントB)Lambda関数を書き換える
Lambda関数でバケット名を指定している部分を、
アカウントA(データを作る側のシステム)のバケットに変更します。
obj = client.list_objects(Bucket='<バケット名>')
(アカウントB)アクセス拒否された
デプロイしてからテストを実行すると、アクセスが拒否されたことがわかります。
※たまに前回の結果が残ってしまうので、画面更新をしてからTestを押してください。
{
"errorMessage": "An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied",
"errorType": "ClientError",
"requestId": "xxxx",
"stackTrace": [
" File \"/var/task/lambda_function.py\", line 19, in lambda_handler\n obj = client.list_objects(Bucket='<バケット名>')\n",
" File \"/var/runtime/botocore/client.py\", line 391, in _api_call\n return self._make_api_call(operation_name, kwargs)\n",
" File \"/var/runtime/botocore/client.py\", line 719, in _make_api_call\n raise error_class(parsed_response, operation_name)\n"
]
}
本番:別アカウントのS3にアクセスする
(アカウントA)バケットポリシーを変更
アカウントA(データを作る側のシステム)のS3バケットの設定を変更します。
バケット→「アクセス許可」タブ→「バケットポリシー」→編集を選びます。
以下の記載を追加します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "GetObject",
"Effect": "Allow",
"Principal": { "AWS": "<<アカウントBのLambdaに設定したIAMロール(arn:aws:iam::~~)>>" }, "Action": "s3:*",
"Resource": [ "arn:aws:s3:::<<バケット名>>", "arn:aws:s3:::<<バケット名>>/*" ] }
]
}
「アカウントBのLambdaに設定したIAMロール(arn:aws:iam::~~
)」は、IAM設定画面から確認することができます。
(アカウントB)Lambda関数から再度アクセス
今度は情報を取得することができました。
おわりに
Lambdaを使って違うアカウントのS3にアクセスすることができました。
後編:S3にファイルが置かれたことを通知する
アカウントA(データを作る側のシステム)のS3にファイルがおかれたときに、新しいファイルを使った処理をアカウントB(データを使わせてもらう側のシステム)が実行したい場合があります。
そこで次回は、アカウントAからアカウントBに、ファイルを置いたことを教えてあげて、アカウントBの処理が発火する仕組みを考えたいと思います。