【小ネタ】 Lambda 関数を利用して、バージョニングが有効化された Amazon S3 バケットを空にしてみた
はじめに
テクニカルサポートの 片方 です。
今回は小ネタとして、Lambda 関数 (Python3.13) を利用して、バージョニングが有効化された Amazon S3 バケットを空にする方法をご紹介します。
なお、AWS CLI コマンドを利用する場合は、弊社ブログをご参考ください。
実装してみた
実行ロール
※ 信頼関係
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
※ アタッチするポリシー例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucketVersions",
"s3:ListBucket",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"s3:DeleteBucket"
],
"Resource": [
"arn:aws:s3:::YOUR_BUCKET_NAME",
"arn:aws:s3:::YOUR_BUCKET_NAME/*"
]
}
]
}
※ 適宜修正してください。
Lambda関数
今回は Python3.13 で実装しました。
import boto3
import os
s3 = boto3.client('s3')
bucket_name = os.environ['BUCKET_NAME']
def lambda_handler(event, context):
print(f"Deleting all versions and delete markers in bucket: {bucket_name}")
paginator = s3.get_paginator('list_object_versions')
page_iterator = paginator.paginate(Bucket=bucket_name)
delete_markers = []
versions = []
for page in page_iterator:
if 'Versions' in page:
for version in page['Versions']:
versions.append({
'Key': version['Key'],
'VersionId': version['VersionId']
})
if 'DeleteMarkers' in page:
for marker in page['DeleteMarkers']:
delete_markers.append({
'Key': marker['Key'],
'VersionId': marker['VersionId']
})
# Combine all versions and delete markers
objects_to_delete = versions + delete_markers
# Delete in batches of 1000 (S3 limit)
for i in range(0, len(objects_to_delete), 1000):
batch = objects_to_delete[i:i+1000]
response = s3.delete_objects(
Bucket=bucket_name,
Delete={'Objects': batch}
)
print(f"Deleted {len(batch)} objects")
return {
'statusCode': 200,
'body': f"Deleted {len(objects_to_delete)} object versions from {bucket_name}"
}
- 環境変数
BUCKET_NAME : YOUR_BUCKET_NAME
※ 適宜修正してください。
補足
併せて S3 バケットも削除したい場合は以下をご参考ください。
import boto3
import os
s3 = boto3.client('s3')
bucket_name = os.environ['BUCKET_NAME']
def lambda_handler(event, context):
print(f"Starting full cleanup and deletion of bucket: {bucket_name}")
paginator = s3.get_paginator('list_object_versions')
page_iterator = paginator.paginate(Bucket=bucket_name)
delete_markers = []
versions = []
for page in page_iterator:
if 'Versions' in page:
for version in page['Versions']:
versions.append({
'Key': version['Key'],
'VersionId': version['VersionId']
})
if 'DeleteMarkers' in page:
for marker in page['DeleteMarkers']:
delete_markers.append({
'Key': marker['Key'],
'VersionId': marker['VersionId']
})
objects_to_delete = versions + delete_markers
# Delete in batches of 1000
for i in range(0, len(objects_to_delete), 1000):
batch = objects_to_delete[i:i+1000]
response = s3.delete_objects(
Bucket=bucket_name,
Delete={'Objects': batch}
)
print(f"Deleted {len(batch)} objects")
# 確認のため再チェック(念のため)
remaining_objects = list(s3.get_paginator('list_object_versions').paginate(Bucket=bucket_name))
if any('Versions' in page or 'DeleteMarkers' in page for page in remaining_objects):
return {
'statusCode': 500,
'body': f"Bucket {bucket_name} is not empty after deletion attempt."
}
# バケットを削除
try:
s3.delete_bucket(Bucket=bucket_name)
print(f"Bucket {bucket_name} deleted successfully.")
return {
'statusCode': 200,
'body': f"Bucket {bucket_name} and all object versions deleted."
}
except Exception as e:
print(f"Error deleting bucket: {str(e)}")
return {
'statusCode': 500,
'body': f"Error deleting bucket: {str(e)}"
}
検証してみた
バージョニングが有効化されていて、既に複数のオブジェクトが存在する Amazon S3 バケットを空にしてみます。
テストします。
成功しました。
まとめ
Lambda には 実行時間制限(最大15分) があり、オブジェクト数が多いと、1 回の実行では終わらない場合があります。
タイムアウト値を引き上げることや、もしオブジェクト数が非常に多い場合は、Step Functions や バッチ処理との併用を検討してください。
本ブログが誰かの参考になれば幸いです。
参考資料
- AWS CLI を使ってバージョニングが有効化された Amazon S3 バケットを空にしてみた | DevelopersIO
- delete_object - Boto3 1.35.9 documentation
アノテーション株式会社について
アノテーション株式会社は、クラスメソッド社のグループ企業として「オペレーション・エクセレンス」を担える企業を目指してチャレンジを続けています。「らしく働く、らしく生きる」のスローガンを掲げ、様々な背景をもつ多様なメンバーが自由度の高い働き方を通してお客様へサービスを提供し続けてきました。現在当社では一緒に会社を盛り上げていただけるメンバーを募集中です。少しでもご興味あれば、アノテーション株式会社WEBサイトをご覧ください。