Lambda(Python)でS3 batch operations のjobを作成

やったこと

  • 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-xxxxxxtest-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の詳細情報を取得し、設定内容に違いが無いかを確認するのが良さそう