やったこと
- LambdaからS3 batch operations のjobを作成する処理をPythonで実装した
- S3 batch operationsのjobはS3 inventoryで生成されるmanifest.jsonを使用してコピー処理を行う
- Lambdaを実行することで「S3 batch job作成 –> job実行(copy処理) –> report出力」を行ってくれる
この記事に記載していない設定
コピーしたいデータの一覧の出力設定(S3 inventory)については記載していません。実際はS3 inventoryの設定を行いmanifest.jsonとデータ一覧のcsvが毎日自動でs3://copy-distination-bucket/copy_from_inventry
に出力されるよう設定しています。
処理内容
- S3 inventoryから出力されたmanifest.jsonを使用して、S3 bucket
copy-distination-bucket
にコピー - S3 batch jobのreportはs3://copy-distination-bucke/reportに出力する
作成したIAM Role
作成したRoleはlambda_func_name-role-xxxxxx
とtest-batch-operation-role
の2つ
S3 batch jobにセットするlambda_func_name-role-xxxxxx
management consoleからLambda作成時に自動で作成されるRoleを使用
設定されているpolicyは以下
- AmazonS3FullAccess
- IAMPassRoleAccess
- AWSLambdaBasicExecutionRole-xxxx
- (policy)AWSLambdaBasicExecutionRole-xxxx(Lambda作成時に自動で生成されるpolicy)
※2022/12/15 追記
AmazonS3FullAccessから権限を絞り込んでみるとS3 batch operationのjobを作成するためには下記の権限が必要なことがわかりました
- s3:CreateJob
- s3:DescribeJob
- s3:UpdateJobStatus
- s3:PutJobTagging(jobにタグ設定をする場合)
S3 batch jobにセットするtest-batch-operation-role
設定されているpolicyは以下
- AmazonS3FullAccess
※AmazonS3FullAccess については必要最低限のPolicyに絞り込む予定です
ソースコード
import json
import boto3
import time
import datetime
import os
s3ControlClient = boto3.client('s3control')
def lambda_handler(event, context):
accountId = boto3.client('sts').get_caller_identity().get('Account')
response = s3ControlClient.create_job(
AccountId=accountId,
ConfirmationRequired=True,
Operation={
'S3PutObjectCopy': {
'TargetResource': 'arn:aws:s3:::copy-distination-bucket',
'TargetKeyPrefix': 'backup/202209151102',
'StorageClass': 'STANDARD',
'AccessControlGrants': [
{
'Grantee': {
'TypeIdentifier': 'id',
'Identifier': 'b82a4exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
},
'Permission': 'FULL_CONTROL'
}
],
'MetadataDirective': 'COPY'
}
},
Report={
'Bucket' : 'arn:aws:s3:::copy-distination-bucket',
'Format' : 'Report_CSV_20180820',
'Enabled' : True,
'Prefix' : 'report',
'ReportScope' : 'AllTasks'
},
Manifest={
'Spec': {
'Format': 'S3InventoryReport_CSV_20161130',
},
'Location': {
'ObjectArn' : 'arn:aws:s3:::copy-distination-bucket/copy_from_inventry/2022-09-11T01-00Z/manifest.json',
'ETag' : 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
}
},
Description = time.strftime('%Y-%m-%d')+' - Created from Lambda',
Priority = 10,
RoleArn = 'arn:aws:iam::xxxxxxxxxxxxx:role/test-batch-operation-role',
Tags = [
{'Key': 'tagA', 'Value': 'test'}
]
)
print(response)
注意する箇所、ハマった箇所
ManifestでFieldsの設定は不要
下記のようにFormatにS3InventoryReport_CSV_20161130 を指定して、かつFieldsの設定を記述するとjob作成時にエラーが発生します。InventoryReportのmanifestファイルを読み込む場合はFields
の設定は不要のようでした。
Manifest={
'Spec': {
'Format': 'S3InventoryReport_CSV_20161130',
# 'Fields': [
# 'Bucket', 'Key'
# ]
},
Bucket is missing ObjectLockConfiguration
このエラーはjob作成が正常終了し、jobの実行時に発生したものです。詳しい原因は調べ切っていませんが、ObjectLockLegalHoldStatus
という設定値を入れていたのが原因でした。おそらくこの設定が存在する場合は他の設定値も必須になるのかと想像しています。
jobの詳細情報を取得する
job作成と実行時のエラー内容がわかりずらかった印象です。対処法として、まずmanagement consoleから正常終了するjobを作り、boto3から「正常終了するジョブ」と「失敗するジョブ」2つのjob設定情報を取得して、設定に過不足が無いか比較するのが手っ取り早そうです。
下記でjobの設定内容を取得できます
res_succeeded_job = s3ControlClient.describe_job(
AccountId=accountId,
JobId='xxxxxxx-yyyy-xxx-xxxx-xxxxxxxxxxxx'
)
まとめ
- LambdaでのS3 batch job作成に関する情報が想像以上に少なかった
- jobの作成エラー、実行エラーの原因が掴めない場合は、一度management consoleから手動でjobを作ってboto3 からjobの詳細情報を取得し、設定内容に違いが無いかを確認するのが良さそう