AWS CloudFormationの指定のStackで管理されている全てのS3 Bucketを一括で空にするシェルスクリプトを作ってみた

2022.08.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

S3 Bucketのbucketを削除する際に、Bucketが空でなければ削除できないというのは周知の事実かと思います。

Make sure the bucket is empty – You can only delete buckets that don't have any objects in them. Make sure the bucket is empty.

なのでbucketを削除したい時には「bucketを空にする」→「bucketを削除する」を1セットで行う必要があります。これはAWS CloudFormation(AWS CDK)で作成したbucketの場合も同様で、CloudFormation Stackで管理しているrecourceを本来なら一括で削除できる(removal policyをDESTROYにしている場合)ところ、事前に手動でbucketを空にしておかないといけません。

そこで今回は、AWS CloudFormationの指定のStackで管理されている全てのS3 Bucketを一括で空にするシェルスクリプトを作ってみました。

やってみた

シェススクリプト

作成したシェルスクリプトは以下となります。

empty-cfn-managed-buckets.sh

targetStackName=${1}

buckets=$( \
  aws cloudformation describe-stack-resources \
    --stack-name ${targetStackName} \
    --query 'StackResources[?ResourceType==`AWS::S3::Bucket`].PhysicalResourceId[]')

bucketsLen=$(echo ${buckets} | jq length)

if [ bucketsLen -eq 0 ]; then
  echo "Bucket resources not found in specified stack."
  exit
fi

echo ""
echo "Buckets:"
echo ${buckets} | jq .
echo ""

read -p "Do you empty these buckets ? (y/N): " yn
case "$yn" in [yY]*) ;; *) echo "abort." ; exit ;; esac

for i in $( seq 0 $((${bucketsLen} - 1)) ); do
  bucket=$(echo ${buckets} | jq -r .[$i])
  aws s3 rm --recursive s3://${bucket}
done
  • AWS CLIのcloudformation describe-stack-resourcesコマンドで指定のCloudFormation StackのResoucreをListし、ResourceTypeがAWS::S3::BucketのResouceのみ変数に格納しています。
  • 取得した各Bucketに対してfor文でs3 rmコマンドを--recursiveオプションを使用して実行し、Bucket内のすべてのオブジェクトを削除して空にしています。

シェルスクリプトのファイルに実行可能権限を付与します。

$ chmod +x empty-cfn-managed-buckets.sh

動作確認

管理しているBucketが空ではないStackProcessStackがあります。cdk destroyコマンドでDestroyしようとすると案の定エラーとなります。

$ cdk destroy ProcessStack
Are you sure you want to delete: ProcessStack (y/n)? y
ProcessStack: destroying...
12:27:25 AM | DELETE_IN_PROGRESS   | AWS::CloudFormation::Stack           | ProcessStack
12:27:28 AM | DELETE_FAILED        | AWS::S3::Bucket                      | hogeBucket
The bucket you tried to delete is not empty (Service: Amazon S3; Status Code: 409; Error Code: BucketNotEmpty; Request ID: XMNQMWW
P38RT6KBE; S3 Extended Request ID: LdExLHGa0BZenrReyjCLKjScvwh//DygdIGSe0F8p/Ah+2zReMF7AgbBcE3ThRZ6ALXLgdv6aKc54T4ySZxRlw==; Proxy
: null)

そこでProcessStackを指定して前述のスクリプトを実行します。Yes/Noの確認プロンプトを挾み、管理されている2つのbucketを空にすることができました。

$ sh ./empty-cfn-managed-buckets.sh ProcessStack
./empty-cfn-managed-buckets.sh: line 10: [: bucketsLen: integer expression expected

Buckets:
[
  "processstack-databucketd8691f4e-1qncl1zy7gvfm",
  "processstack-hogebucketd41d3f4e-w59igilmmrsb"
]

Do you empty these buckets ? (y/N): y

delete: s3://processstack-databucketd8691f4e-1qncl1zy7gvfm/deliveryStream-1-2022-08-10-13-55-33-04431990-8c8d-465f-b41b-fcda45713eac
delete: s3://processstack-hogebucketd41d3f4e-w59igilmmrsb/deliveryStream-1-2022-08-10-13-55-33-04431990-8c8d-465f-b41b-fcda45713eac

bucketを空にした後は、同じcdk destroyコマンドでstackをdestroyすることができました!

$ cdk destroy ProcessStack                      
Are you sure you want to delete: ProcessStack (y/n)? y
ProcessStack: destroying...

 ✅  ProcessStack: destroyed

おわりに

AWS CloudFormationの指定のStackで管理されている全てのS3 Bucketを一括で空にするシェルスクリプトを作ってみました。

案件やブログの執筆のために検証用のAWS resourceをCDKで作ったり壊したりをしょっちゅう繰り返すウノで、こんなシェルスクリプトがあるといいな、ということで作ってみました。

参考

以上