1年使った検証用個人AWSアカウント内のリソースを大掃除してみる

2022.12.27

「AWSアカウントも大掃除だ」

時間で課金されるリソース(EC2、RDS)は都度削除しているのですが、課金されないリソース(IAMロールとか)を削除するのを忘れてしまうことがあります。

検証用のAWSアカウントを使い始めて1年ほど経ち、そこそこ検証時の残骸が溜まってきました。

AWSサービスやツールを活用して、不要リソースの削除をやってみます。

今回使用するAWSサービス・ツール

主に以下のAWSサービスとツールを使用します。

aws-nuke

AWSアカウント内のリソースを一括で削除することができるツールです。

フィルター機能などを使って、特定のリソースを削除から除外することもできます。

できるだけリソースを削除しますが、以下のようなリソースは残したいのでフィルター機能を使って除外していきます。

  • ログイン用のIAMリソース
  • terraformのstate保存用S3バケット
  • cdk bootstrap時に作成されるCFnスタック

AWS Resource Explorer

AWS Resource Explorerはリソース検索および検出サービスです。

aws-nuke実行時に削除対象のリソースを表示できますが、フィルターの設定等によっては削除漏れがあるかもしれないため AWS Resource Explorer を併用します。

GUIで柔軟に検索条件も設定できますし、結果も見やすいです。

ちなみに、AWS Resource Explorerは無料で使用できます。

やってみる

不要なCloudFormationスタックの削除

最終的にはaws-nukeで一括削除します。

しかし、リソースが多いとaws-nukeの実行に時間がかかります。

少しでも実行時間を短くするために、削除可能なCloudFormationスタックは削除しておきます。

aws-nuke用のconfigファイルを作成

configファイルを用意します。

各自の環境によって、残したいリソースは変わってくると思うのでご参考までに。 (実際に使用した設定から、会社アカウント固有の情報を省略しています)

デフォルトVPCも削除する設定になっていますので、必要に応じて変更してください。

accountsの部分は自分のAWSアカウントIDに置き換えてください。

nuke-config.yml

regions:
  - ap-northeast-1
  - global

account-blocklist:
  - "000000000000" # dummy

resource-types:
  excludes:
    # リソースが存在しないとERRORやWARNが出るサービスを除外(2022/12/23)
    # 実行結果のノイズになるため
    - FMSPolicy
    - FMSNotificationChannel
    - GlobalAccelerator
    - GlobalAcceleratorListener
    - GlobalAcceleratorEndpointGroup
    - WorkLinkFleet
    - MobileProject
    - SESReceiptRuleSet
    - SESReceiptFilter
    # 頻繁に作成するものではないので、除外
    - ACMCertificate
    - CodeStarConnection
    - EC2KeyPair
    - Budget
    - Route53HostedZone
    - Route53ResourceRecordSet
        - CloudTrailTrail
    - ConfigServiceDeliveryChannel
    - ConfigServiceConfigurationRecorder
    # スキャン時間が長くなるため除外
    - S3Object

accounts:
  "123456789":
    presets:
      - "cdk"
      - "terraform"
    filters:
      IAMRole:
        - type: glob
          value: "my-role"
      IAMRolePolicy:
        - type: glob
          value: "my-role"
      IAMRolePolicyAttachment:
        - type: glob
          value: "my-role"
        - type: glob
          value: "AWSServiceRole*"
      S3Bucket:
        - type: glob
          property: Name
          value: "rain-artifacts-*"
        - type: glob
          property: Name
          value: "cf-templates-*"
presets:
  cdk:
    filters:
      IAMRole:
        # cdk bootstrapで作成されるROLEのタグ名が、aws-cdk:bootstrap-role
        # ":"が含まれていて上手くglobで除外できていないから、role名で除外
        - type: glob
          value: "cdk-*-role-*"
      IAMRolePolicy:
        - type: glob
          value: "cdk-*-role-*"
      IAMRolePolicyAttachment:
        - type: glob
          value: "cdk-*-role-*"
      S3Bucket:
        - type: exact
          property: tag:aws:cloudformation:stack-name
          value: "CDKToolkit"
      ECRRepository:
        - type: glob
          value: "*cdk-*-container-assets-*"
      SSMParameter:
        - type: glob
          property: tag:aws:cloudformation:stack-name
          value: "CDKToolkit"
      CloudFormationStack:
        - type: exact
          property: Name
          value: "CDKToolkit"
  terraform:
    filters:
      DynamoDBTableItem:
        - type: exact
          property: Table
          value: "terraform_state_lock"
      DynamoDBTable:
        - type: glob
          value: "terraform_state_lock"
      S3Bucket:
        - type: glob
          property: Name
          value: "terraform-state-*"
      CloudFormationStack:
        - type: exact
          propety: Name
          value: "terraform-backend"
      IAMUser:
        - type: exact
          value: "terraform-cloud-admin"
      IAMUserAccessKey:
        - type: exact
          property: UserName
          value: "terraform-cloud-admin"
      IAMUserPolicyAttachment:
        - type: exact
          property: UserName
          value: "terraform-cloud-admin"

regions

aws-nukeの対象にするリージョンを指定します。

検証時はほぼ東京リージョン(ap-northeast-1)を使うため、global(IAMとかRoute53)とap-northeast-1のみを指定しています。

どこのリージョンにリソースが残っているかを確認する際は、AWS Resource Explorerを確認すると分かりやすいと思います。

resource-types

excludes: の部分で、除外するサービスを定義しています。

ACMやRoute53のホストゾーンなどは除外しています。

以下の基準で、除外するサービスを選びました。

  • 検証時に使いまわすことが多い
  • 課金が大きくない・または発生しない

またS3Objectに関しても除外しています。

理由としては、スキャン時間が伸びてしまうのとオブジェクトごとにDry-Runの結果に出力されるため、結果が見辛くなってしまうためです。

filterするにも大量のDry-Runの出力と向き合う必要があるため、aws-nukeでの一括削除の対象外としました。

オブジェクト削除したい場合は、マネジメントコンソールから「バケットを空にする」を実行する方が楽かもしれません。

accounts

filtersで除外するリソースを定義しています。

resource-typesexcludes:の部分と違って、サービス自体は削除に含めたいが一部リソースは対象外にしたいものを設定しています。

例) 検証用に適当に作ったS3バケットは削除したいが、terraformのstate管理用のバケットは残したいなど

accountsfilters配下に全て記載しても動作は変わらないですが、presetsを使用するとスッキリかけるのでおすすめです。

aws-nuke Dry-Run(必要に応じてconfigの修正)

ローカル環境に直接aws-nukeをインストールして使用しても問題ありませんが、今回はDocker上で実行する方法を紹介します。

configファイルと同じディレクトリに、以下のdocker-compose.ymlを用意します。

docker-compose.yml

version: "3"
services:
  aws-nuke-dry-run:
    image: rebuy/aws-nuke:latest
    entrypoint: /usr/local/bin/aws-nuke --config /home/aws-nuke/config.yml --force --quiet
    volumes:
      - ./nuke-config.yml:/home/aws-nuke/config.yml
      - ~/.aws:/home/aws-nuke/.aws
    environment:
      - AWS_ACCESS_KEY_ID
      - AWS_SECRET_ACCESS_KEY
      - AWS_SESSION_TOKEN
  aws-nuke-run:
    image: rebuy/aws-nuke:latest
    entrypoint: /usr/local/bin/aws-nuke --config /home/aws-nuke/config.yml --force --quiet --no-dry-run
    volumes:
      - ./nuke-config.yml:/home/aws-nuke/config.yml
      - ~/.aws:/home/aws-nuke/.aws
    environment:
      - AWS_ACCESS_KEY_ID
      - AWS_SECRET_ACCESS_KEY
      - AWS_SESSION_TOKEN

ファイルを用意できたら、以下のコマンドでdry-runを実行します。(この時点ではリソースの削除は実行されません)

$ docker compose run aws-nuke-dry-run
# 削除対象のリソース情報が表示される(省略)
Scan complete: 648 total, 308 nukeable, 340 filtered.

上記の出力では、308個のリソースが削除の対象がとなっていました。

参考までに、私の環境で実行した際に数が多かった削除対象のリソースです。

  • Cloudwatch Logs ロググループ: 60個
  • IAMポリシー: 36個

他には、VPCやセキュリティグループもそれなりにありました。

aws-nuke RUN

Configの修正とDry-Run結果の確認が終わったら実際にリソースを削除します。

実際にリソース削除が発生するため、この手順はDry-Run結果を確認の上、自己責任で行なってください。

$ docker compose run aws-nuke-run
Nuke complete: 0 failed, 189 skipped, 337 finished.

最終的には337個のリソースをaws-nukeで削除することができました。

AWS Resource Explorerでリソース削除を確認してみる

マネジメントコンソールから「AWS Resource Explorer」を選択して、状態を確認します。

私の場合は、PrefixListが削除から漏れていたことに気付いたので手動で削除しました。

おわりに

AWSアカウント内のリソースの大掃除でした。

1年ほど使っていたこともあり、検証の残骸が300程度と結構溜まっていました。

aws-nukeを使うことでスッキリ削除できました。 課金が大きいリソースはなかったため、コスト的には問題はありませんでしたが、不要なものを削除できたのでリソースの検索や参照が楽になりそうです。

AWS Resource Explorerはしっかり使ったことなかったのですが、今回の様なリソース棚卸しの際にはとても便利なサービスだと思いました。

aws-nukeの定期実行のやり方については、以下に書きましたので興味があったら読んでみてください。

以上、AWS事業本部の佐藤(@chari7311)でした。