AWS CloudFormationスタック強制削除ツール

概要

AWS CloudFormationスタックの削除時、削除に失敗する(DELETE_FAILEDになる)リソースは手動で対応しないとスタックの削除ができないのが面倒ですよね。

そんなリソースを含むスタックでも1コマンドでまるごと楽々削除できるCLIツールを、OSSで公開しました。

スタック検索できたりと、普段使いにも中々便利になりました。


目次

目次


delstack

という名前のツールです。


機能

ざっくり言うと以下のようなツールになります。

  • 削除に失敗する(DELETE_FAILEDになる)リソースを含むスタックも
  • そうでない普通のスタックも
  • 1コマンドでスタックまるごと削除できる(複数スタックの一括削除も可能!)


対話モードでのスタック名検索やリソース種類選択などの機能もあります。


リポジトリ

こちらです。Go言語で実装しました。スターなど頂けたら泣いて喜びます。

github.com


詳細

仕組み

今まで手動で行っていたことを自動で処理するというような仕組みとなります。

従来(手作業)

  1. CloudFormationスタック削除
    • 一部のリソースの削除に失敗(DELETE_FAILED)
  2. 該当リソースに対して以下の対応
    • スタック削除で同時に消せるように諸々対応
      • S3バケットを空にしたり、ECRのイメージを削除したり
    • またはそこでリソース自体削除したり、スタック削除にスキップ対象にして後で対処したり
  3. 再度CloudFormationスタック削除
  4. スキップしたリソースがあればそれぞれ削除


ツール

※1コマンドで以下を実施

  1. CloudFormationスタック削除
    • 一部のリソースの削除に失敗(DELETE_FAILED)
  2. 削除に失敗したリソースをそれぞれで削除
  3. 該当リソースをスキップして再度CloudFormationスタック削除


強制削除対応リソース

以下は、通常のCloudFormation削除に失敗するリソースでも強制削除出来るリソース一覧です。通常の削除に失敗しないリソースは全てそのまま削除出来ます。

削除に失敗する全AWSリソースに対応しているわけではなく、私が遭遇したことがあるものを対象にして実装しています。

私が遭遇したことのないリソースもあるかとは思うので、他にもあれば随時対応したいと思っています。

もし対応して欲しいリソースがあれば、GitHubにissueを立ててくださると嬉しいです!

github.com

リソース 詳細
AWS::S3::Bucket 空でない、またはバージョニングオンのものも含む。DeletionPolicyがRetainのものは削除しない。(それらは削除すべきでないと判断)
AWS::S3Express::DirectoryBucket 空でないものも含む、S3 Express One Zone用のディレクトバケットDeletionPolicyがRetainのものは削除しない。(それらは削除すべきでないと判断)
AWS::IAM::Group スタック外部のIAMユーザーがアタッチされたものも含む。その場合は、IAMユーザーをデタッチしてIAMグループを削除する(IAMユーザー自体の削除はしない)。
AWS::ECR::Repository すでにイメージが登録されているもの、EmptyOnDeletetrueでないものも含む。
AWS::Backup::BackupVault すでにバックアップが取得されているものも含む。
AWS::CloudFormation::Stack これらのリソースを子スタックが持つことで削除に失敗したネスト(子)スタック。子スタック内のDELETE_FAILEDリソースも自動で削除されます。
Custom::Xxx カスタムリソース。SUCCESSを返さないものも含む。


また後述しますが、対話モードにて削除したいリソースを選択できるようになっています。これによって、本当に削除したくないリソースを削除しないようにできます。


使い方

インストール

Homebrew

brew install go-to-k/tap/delstack

Linux / Darwin (macOS) / Windows

curl -fsSL https://raw.githubusercontent.com/go-to-k/delstack/main/install.sh | sh
delstack -h

# To install a specific version of delstack
# e.g. version 1.2.0
curl -fsSL https://raw.githubusercontent.com/go-to-k/delstack/main/install.sh | sh -s "v1.2.0"
delstack -h

aqua

aqua g -i go-to-k/delstack

バイナリ

ソースビルド(開発版)

※Go環境が必要です。

git clone https://github.com/go-to-k/delstack.git
cd delstack
make install


実行方法

delstack [-s <stackName>] [-p <profile>] [-r <region>] [-i]


オプション

  • -s, --stackName(オプション)
    • CloudFormationスタック名
      • 対話モードでないとき必須です
      • 対話モードでは指定が必須ではなく、対話フローの中で検索・指定が可能です
    • 複数スタックの指定が可能です
      • delstack -s test1 -s test2
      • スタック間の依存関係を考慮して、新しいスタックから順に削除していきます
  • -p, --profile(オプション)
    • AWSプロファイル名
    • (デフォルト: 実行環境のデフォルトのプロファイルが使用されます)
  • -r, --region(オプション)
    • AWS Region
    • (デフォルト: ap-northeast-1)
  • -i, --interactive(オプション)
    • 対話モード


対話モード

スタック検索・選択

もし対話モード(-i, --interactive)でのコマンドオプション(-s, --stackName)でスタック名を指定しなかった場合、対話フローの中でスタックの検索・指定が可能です。また、大文字小文字の区別はしないのでより手軽に検索できます。


まずはスタック名を絞るキーワードを入力します。

空でも大丈夫です(全スタックが返ります)。


するとキーワードに一致するスタック一覧が出力されるので、削除したいスタックを選択します。


ネストスタックの子スタックは表示しないようにしています。実際、親スタックを消さずにネストスタックの子スタックだけ消すケースはあまり考えられないのと、スタック一覧に子スタックがあると親スタックが埋もれてしまったり誤削除の可能性が考えられたため、このようにしています。

ただし、コマンド実行オプションの-sでは現状子スタック名を指定すれば削除可能にしてあるので、どうしてもな場合はこちらをご利用ください。

また、同じタイミングでCloudFormationスタックに対して操作中の状態ROLLBACK_IN_PROGRESSなど)のスタックも表示しないようにしています。操作中の状態のスタックに対して削除などの操作を行おうとするとそもそもエラーになるからです。

さらに、削除保護が有効のスタックも表示しないようにしています。


リソースタイプ選択

-i, --interactiveオプションを指定すると、強制削除したいリソースタイプを選択することができます。この機能で「削除リソースタイプを選択しない」ことにより、消したくないリソースを保護することができます!


ただし、通常のCloudFormationのスタック削除機能によってDELETE_FAILEDにならずに削除できてしまうリソースの場合、そのリソースタイプを選択しなかったとしても、そのリソースは削除されます

(このツールは通常のCloudFormationのスタック削除機能から特定のリソースを守るためのものではないため、本当に削除してはいけないものだけ強制削除しないようにする、というニュアンスでこの機能を実装しました。)


また、スタックにDELETE_FAILEDとなるリソースが含まれているが選択はしなかった場合、選択した・していないに関わらず全てのDELETE_FAILED(削除失敗)リソースとスタックは削除されずに残ります


GitHub Actions

また、GitHub Actions(カスタムアクション)でも使うことができます。

withにて"stack-name"と"region"を指定して実行できます。複数スタックを一括で削除するには、"stack-name"にスタック名をカンマ区切りで指定してください。

jobs:
  delstack:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
          # Or specify access keys.
          # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Delete stack
        uses: go-to-k/delstack@main # Or specify the version instead of main
        with:
          stack-name: YourStack
          # stack-name: YourStack1, YourStack2, YourStack3 # To delete multiple stacks
          region: us-east-1

さらにインストールだけして、生のコマンドを実行することも可能です。

jobs:
  delstack:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v3
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v3
        with:
          role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
          # Or specify access keys.
          # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1
      - name: Install delstack
        uses: go-to-k/delstack@main # Or specify the version instead of main
      - name: Run delstack
        run: |
          echo "delstack"
          delstack -v
          delstack -s YourStack1 -s YourStack2 -r us-east-1


補足

削除に失敗するリソースがない場合

もちろんこのコマンド一発で同様に削除可能です。

削除失敗リソースがある・ないを意識せず、スタック削除はこのコマンド投げておけばいいみたいな使い方をしています。


削除保護がオンの場合

削除保護(Termination Protection)がオンのスタックは削除せず、その旨のメッセージを出力して終了します。

削除保護オンのものは削除したくない意図があると踏み、間違えて削除してしまうミスなどの安全性を考慮してこのようにしています。

(スタックやEC2を削除保護している場合も消せるオプションをつけるのも考えています。)


対応外の削除失敗リソースがある場合

その旨のメッセージを出力して、削除を終了します。(削除失敗リソースはそのスタックごと残ります。)


スタック外から参照されている場合

他のスタック・リソースで使われていることで削除に失敗するリソース、つまりスタック外から参照(依存)されているものがあるリソースの削除は対象外としています。

あくまでそのスタック内で完結するリソースの強制削除を対象としています。

(これを対応するのは思わぬ破壊を生む可能性がある、またすごく大変なのでやりません。)


速度

あくまでCloudFormationの削除機能を使用したスタック・リソースの削除なので、CloudFormationの削除操作(delete-stack)以上に速くはできません。

速く削除するツールではなく、楽に削除するツールという目的としました。

(スタック削除機能を使わずスタック内のリソースを全部消すのは、依存関係・削除順番を考慮する必要があったり、全AWSリソースのDelete APIに対応しないといけないのでさすがに無理でした。。。)


しかし、可能な限り(実行環境の論理CPUコア数を考慮して)並列処理でリソースの削除を行っているので、そこそこ速いです。


スタック名の指定

削除したいスタック名を指定してコマンドを実行するため、スタック名を特定する必要があります。

serverless frameworkやCDKのdestroy機能のようなスタック名指定がいらないものとは使い勝手が違うかもしれません。

あるソースリポジトリ内での開発しながらのスタック削除というより、スタック一覧からいらないものを消していく・または開発の最中というより作った後で削除する、というようなシチュエーションに合うかなと思います。

(自分は開発しながらのケースでも、スタック名を控えておいて存分にツールを使っています。)


しかし、対話モードでスタックの検索・指定が可能なので、そこまで支障はないかと思われます。


最後に

あくまで個人使用の範囲内で開発したため、動作の保証は出来かねます。

ただ、こんなバグがあったなどあればできるだけ対応したいと思っております。

その上でもし便利だと思って使ってみて頂けたら嬉しいです!