CDKではConstructのコードを削除しても対応するリソースが削除されない場合がある

2022.03.25

S3バケットが削除されなかった

S3バケットにファイルが作成されたことをトリガに、StepFunctionsステートマシーンを実行する構成をCDKで作成していました。

実装としてはこちらにあるように、

  1. まずCloudTrail証跡を作成し、該当S3バケットのイベントをキャプチャできるようにする
  2. EventBridgeルールを作成し、上記CloudTrailでキャプチャしたS3のイベントでトリガされるようにする
  3. 上記EventBridgeルールのターゲットとしてStepFunctionsステートマシーンを設定する

のように、間にCloudTrail証跡とEventBridgeを挟む形になります。

ですが昨年末のアップデートで、CloudTrail証跡なしでEventBridgeで直接S3のイベントを拾えるようになりました。

というわけで、こちらの新構成を早速採用しようということになり、CloudTrail証跡を削除する事になりました。CloudTrail証跡には証跡の保存場所となるS3バケットも別途必要になるので、そちらも併せて削除します。

※色々割愛しています

- const trailS3Bucket = new Bucket(scope, 'TrailS3Bucket', {
-   bucketName: getResourceName(scope),
- });
- const trail = new Trail(scope, 'trail', {
-   isMultiRegionTrail: false,
-   includeGlobalServiceEvents: false,
-   bucket: trailS3Bucket,
- });

上記のように対応するConstructのコードを削除してcdk deployしました。すると、CloudTrail証跡は削除されましたが、S3バケットは削除されず(stack管理外にはなりましたが)残り続けていることが判明しました。

削除されなかった理由

Bucket constructにはremovalPolicyというoptionのpropがあります。

今回の様にバケットがスタックから削除された際の挙動を定義するpropで、デフォルト値はRETAIN=保持、つまりスタックからは削除されるけどリソース削除はされないという挙動になります。今回このremovalPolicyを指定していなかったため、デフォルト値RETAINが適用され、リソース削除されなかったということです。

削除するには

removalPolicy prop値にRemovalPolicy.DESTROYを指定します。もしくはconstruct作成後に applyRemovalPolicy MethodをRemovalPolicy.DESTROYを引数にして実行します。

が、削除するバケット内にオブジェクトが存在している場合、BucketNotEmptyのエラーになります。この場合はさらにautoDeleteObjects propにtrueを指定してオブジェクトも同時に削除されるようにしてください。

他にもデフォルトだと削除されないリソースは色々ある

この挙動、S3バケットに限ったものではありません。調べると色々なリソースのデフォルトのスタック削除の挙動がこのRETAIN=保持でした。ステートフルなリソースにこの傾向があるようです。

以下のリストはremovalPolicy propのデフォルト値がRETAINのconstructの一例です。※ すべてを網羅しているわけではありません。

他にもEventBridge - Ruleなど、removalPolicy propは持っていないけれど applyRemovalPolicy methodは持っているConstructも多数見つけました。こういったリソースのスタックから削除された際のデフォルトの挙動まで調べきれていませんが、注意が必要です。(EventBridge - RuleはRETAINでした)

cdk diffの結果を見よう

cdk diffコマンドの結果にて、以下の様にorphan(=みなし子、孤児の意)と表示されれば、そのリソースはスタックからは削除されるがリソース自体は削除されず残り続けるということです。 ですのでやはりdeploy前はdiffの結果をちゃんと確認しましょう!

参考情報