APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

S3レプリケーション完了をトリガーにLambdaでファイルを日付リネームする

S3レプリケーション完了をトリガーにLambdaでファイルを日付リネームする自動化

はじめに

こんにちは、クラウド事業部の松岡です。 インフラエンジニア3年目、AWS経験3か月の私が、S3のレプリケーション機能とEventBridge + Lambdaを組み合わせて、同期されたファイルを自動で整理(日付リネーム)する仕組みを構築しました。

「AWSの複数リソースを組み合わせて触ってみたい」という初級〜中級者の方に向けて、実務で意識すべき最小権限の原則を含めた手順を紹介します。


システム構成図

本構成では、S3間のレプリケーションが完了したことをEventBridgeで検知し、即座にLambdaがファイル名を変更して特定のディレクトリへ整理する仕組みを採用しています。

処理の流れ

  1. アップロード: ユーザーが filetransfer-dev-source-bucket へファイルを配置。
  2. 同期: S3のレプリケーション機能により filetransfer-dev-destination-bucket へ自動コピー。
  3. 検知: EventBridgeが送信先バケットへの配置(Object Created)をリアルタイムで検知。
  4. リネーム: Lambdaが起動。配置時間をファイル名に付与し、processed/ ディレクトリへ移動。

構築リソース一覧

リソース名は {systemname}-{Env}-{Resourcename} の規則に従い、管理を容易にしています。

下記にYAMLファイルを配置しているので必要でしたらご利用ください

https://github.com/tmatusoka-apc/s3-filetransfer.git

カテゴリ リソース名 備考
S3 (Source) filetransfer-dev-source-bucket バージョニング有効 / レプリケーション元
S3 (Dest) filetransfer-dev-destination-bucket バージョニング有効 / EventBridge通知有効
EventBridge filetransfer-dev-s3-put-rule Object Created イベントを監視
Lambda filetransfer-dev-rename-function Python 3.12 / 無限ループ防止実装済み
IAM Role filetransfer-dev-replication-role S3間のコピー権限(最小権限)
IAM Role filetransfer-dev-lambda-role 送信先S3の操作とログ出力権限

1. S3レプリケーションの設定

S3間のデータ同期を安全に行うための設定です。

設定のポイント

  • バージョニング: レプリケーションの必須要件のため、両バケットで有効化します。
  • 最小権限のIAMロール:
    • s3.amazonaws.com を信頼ポリシーに設定。
    • 許可ポリシーでは、Sourceからの GetObject と Destinationへの ReplicateObject に限定して記述します。

2. Lambdaによるファイル転送の実装

EventBridgeから起動されるLambdaを構築します。

権限周りの設計

本番環境を意識し、以下の権限を持つIAMロールを作成します。 * S3: GetObject, PutObject, DeleteObject(送信先バケットのみ)。 * CloudWatch Logs: 実行ログ(/aws/lambda/filetransfer-dev-rename-function)の書き込み権限。

Lambdaコード(抜粋)

S3には「リネーム」コマンドが存在しないため、「コピー + 削除」の手順を踏みます。

import boto3
import os
from datetime import datetime

s3 = boto3.client('s3')

def lambda_handler(event, context):
    bucket = event['detail']['bucket']['name']
    old_key = event['detail']['object']['key']
    
    # 無限ループ防止: 既に処理済みディレクトリにある場合はスキップ
    if old_key.startswith('processed/'):
        return

    # 配置された時間を取得(YYYYMMDD-HHMMSS形式)
    timestamp = datetime.now().strftime('%Y%m%d-%H%M%S')
    new_key = f"processed/{timestamp}_{os.path.basename(old_key)}"
    
    print(f"Moving: {old_key} -> {new_key}")
    
    # 同一バケット内でのコピー&元のオブジェクト削除
    s3.copy_object(
        Bucket=bucket,
        CopySource={'Bucket': bucket, 'Key': old_key},
        Key=new_key
    )
    s3.delete_object(Bucket=bucket, Key=old_key)
    
    return {"status": "success"}

3. 実行確認

  1. Sourceへアップロード: test.png をアップロード。
  2. レプリケーション確認: Destinationへ test.png が届くのを確認。
  3. CloudWatch Logsを確認: Lambdaが正常に起動し、Moving... のログが出ているかチェック。
  4. 最終結果: Destinationの processed/ 配下に 20260129-120000_test.png が生成され、元のファイルが消えていれば成功。

おわりに

インフラエンジニアとして、単に「動く」だけでなく、「権限が適切か」「後で削除や変更がしやすい命名規則になっているか」を意識した構築を心がけました。

今後は、エラー発生時にSNSで通知する仕組みや、Step Functionsを用いたより複雑なワークフローにも挑戦してみたいと思います。