aws-nuke と CodeBuild を使ってAWSリソースを定期的に自動削除してみる

こんにちは、ゆたか(@yutaka0m)です。

弊社では、エンジニアが自由にAWSを使って新しいリソースを検証できるように「サンドボックス用のAWSアカウント」を作っています。

「リソースを作ったら、あとでちゃんと消す」というルールで運用しているのですが、どうしても消し忘れることがあります。消し忘れたリソースを放置すると、無駄に料金がかかるだけなので、何か対策を考える必要があります。

利用者に「作ったリソースはつまびらかにメモしておいて絶対に全部消すように」と依頼するのも現実的ではないので、定期的自動ですべてのリソースを削除する仕組みを構築することとしました。

aws-nuke

リソースの削除にはaws-nukeを使います。これは、AWSアカウントからすべてのリソースを削除するCLIです。

aws-nukeの基本的な使い方

自動化の前に、aws-nukeの基本的な使い方を説明します。

ダウンロード

まず、最新リリースのAssetsから、自分のOSにあったソースをダウンロードします。

私の環境はDarwin(macOS)なので「aws-nuke-v2.14.0-darwin-amd64」が執筆時時点の最新です。

ダウンロードして、実行権限を付与しておきます。

# 最新のバージョンを入力
$ AWS_NUKE_VERSION=v2.14.0

$ curl -L https://github.com/rebuy-de/aws-nuke/releases/download/${AWS_NUKE_VERSION}/aws-nuke-${AWS_NUKE_VERSION}-darwin-amd64 -o aws-nuke

$ chmod u+x aws-nuke

aws-nuke 設定の記述

次に、aws-nukeの設定ファイルを記述します。

nuke-config.yaml

regions:
- ap-northeast-1

account-blacklist:
- 999999999999

resource-types:
  excludes:
    - EC2Instance

accounts:
  000000000000: # <- 上書きしてください
    filters:
      SNSTopic:
        - "TopicARN: arn:aws:sns:ap-northeast-1:000000000000:xx-topic"
  • regions : 削除対象のAWSリージョンを指定します
  • account-blacklist : 間違って削除したくないAWSアカウントを指定します 必須パラメータなので、とくにない場合も適当な値を入れておきます
  • excludes : 削除したくないリソースを記述します
  • accounts : 削除する対象のAWSアカウントIDを入力します
  • filters : 削除したくない特定のリソースを記述します

上記の例だと、

  • AWSアカウントID000000000000
  • ap-northeast-1に存在する
  • EC2Instance以外と
  • xx-topicというIDのSNSTopic以外の
  • すべてのAWSリソースを削除する

という設定になっています。

他にも色々な設定ができますので、aws-nuke(GitHub)をご参照ください。

AWSアカウントの設定

aws-nukeを実行するには事前にアカウントエイリアス を設定しておく必要があります。

また、aws configure等を使ってAWSの認証情報を設定しておく必要があります。

aws-nukeのドライ実行

設定が完了したので、aws-nukeを実行してみます。

まずは削除されるリソースの確認をおこないます。まだ削除は実行されないのでご安心ください。

$ ./aws-nuke -c nuke-config.yaml

実行すると次のようなメッセージが表示されるので、アカウントエイリアスを入力し、Enterを押します。

Do you really want to nuke the account with the ID 000000000000 and the alias 'xxxxxxxx'?
Do you want to continue? Enter account alias to continue.
> 

続けて削除対象のリソースが表示されます。 削除したくないリソースが削除対象になっている場合は、nuke-config.yamlを修正します。

(たとえば、ログイン用のIAMユーザを削除してしまうと、ログインできなくなるので注意が必要です)

aws-nukeの実行

次に、実際にリソースの削除をおこないます。

先ほどのコマンドに、--no-dry-runを追記するだけです。

$ ./aws-nuke -c nuke-config.yaml --no-dry-run

実行すると、ドライ実行と同じように「アカウントエイリアス」の入力が求められるので入力します。

Do you really want to nuke these resources on the account with the ID 000000000000 and the alias 'xxxxxxxx'?
Do you want to continue? Enter account alias to continue.
> 

削除対象のリソースのスキャンが終わったら、もう一度「アカウントエイリアス」を入力します。

リソースの削除が開始され、

Nuke complete: 1 failed, 1 skipped, 10 finished.

Nuke completeと表示されたら正常終了です。 リソースが削除されたかどうか確認してみましょう。

aws-nukeの自動実行

さて、ここからが本題です。 定期的にaws-nukeを実行する環境を構築します。

環境はリソース削除対象と同じAWSアカウント上に作成します。

aws-nukeの実行は「AWS CodeBuild」で行い、「Amazon CloudWatch Events」でスケジューリングします。また、設定ファイルは「Amazon S3」に保存します。

S3バケットの作成

CodeBuildの設定ファイル(buidspec.yaml)と、aws-nukeの設定ファイル(nuke-config.yaml)を保存するためのS3バケットを作成します。

バケット名はaws-nuke-sample-aws-nuke-configとしました。

buidspec.yamlの記述

次に、CodeBuildの設定ファイル(buidspec.yaml)を次のように記述します。こちらをZIPにして、buidspec.zipという名前でS3バケットにアップロードしておきます。

version: 0.2

phases:
  build:
    commands:
      # AWSクレデンシャルの取得
      - curl -qL -o aws_credentials.json 169.254.170.2${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}
      - AWS_ACCESS_KEY_ID=`jq -r '.AccessKeyId' aws_credentials.json`
      - AWS_SECRET_ACCESS_KEY=`jq -r '.SecretAccessKey' aws_credentials.json`
      - AWS_SESSION_TOKEN=`jq -r '.Token' aws_credentials.json`
      # aws-nukeのダウンロード
      - wget -q https://github.com/rebuy-de/aws-nuke/releases/download/${AWS_NUKE_VERSION}/aws-nuke-${AWS_NUKE_VERSION}-linux-amd64.tar.gz
      # バイナリはdistというディレクトリの下にあるので`--strip-components 1`をつけて親ディレクトリを捨てる
      - tar -zxf aws-nuke-${AWS_NUKE_VERSION}-linux-amd64.tar.gz --strip-components 1
      - mv aws-nuke-${AWS_NUKE_VERSION}-linux-amd64 aws-nuke
      - chmod u+x aws-nuke
      # aws-nuke設定ファイル取得
      - aws s3 cp s3://${NUKE_CONFIG_BUCKET_ID}/nuke-config.yaml .
      # aws-nukeの実行
      - ./aws-nuke -c nuke-config.yaml --no-dry-run --quiet --force --force-sleep 3 --access-key-id $AWS_ACCESS_KEY_ID --secret-access-key $AWS_SECRET_ACCESS_KEY --session-token $AWS_SESSION_TOKEN

169.254.170.2(メタデータエンドポイント)にアクセスすると、CodeBuildに付与されたIAMロールの認証情報を取得できるので、そこから「アクセスキーID」「シークレットアクセスキー」「セッショントークン」を抜き出します。

あとは、その認証情報を使ってaws-nukeを実行しているだけです。

CodeBuildの作成

次に、CodeBuildを構築します。プロジェクト名はaws-nuke-no-dry-runとしました。

ソースプロバイダはAmazon S3を選択し、先ほど作成したバケット名と、S3オブジェクトキーにはbuildspec.zipを指定します。

環境は、Linuxの最新のイメージを指定しておけば問題ありません。執筆時時点では、aws/codebuild/amazonlinux2-x86_64-standard:3.0が最新です。 また、特権付与にチェックを入れておきます。

ロールはAdministratorAccessのポリシーをアタッチしたロールを作成し、そのARNを指定します。

追加設定を開き、環境変数に次の項目を設定します。 - AWS_NUKE_VERSION : 最新のaws-nukeバージョン(たとえばv2.14.0) - NUKE_CONFIG_BUCKET_ID : nuke-config.yamlを保存しているバケット名(たとえばaws-nuke-sample-aws-nuke-config)

Buildspecは「buildspecファイルを使用する」をチェックします。

ログは、aws-nuke用のCloudWatch Logs グループを作成しておき、そちらを指定します。

設定は以上なので、これでビルドプロジェクトを作成します。

CloudWatch Eventsの作成

まず、次のポリシーをアタッチしたCloudWatch Events用のロールを作成します。"Resource"には、先ほど作成したCodeBuildのARNを指定します。ロール名はaws-nuke-cloudwatch-roleとします。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Action": "codebuild:StartBuild",
            "Resource": "arn:aws:codebuild:ap-northeast-1:xxxxxxxxxxxx:project/aws-nuke-no-dry-run"
        }
    ]
}

次に、CodeBuildを定期的に実行するようCloudWatch Eventを作成します。

AWSコンソールにログインしたら、CloudWatch Events ルールにアクセスし、ルールを作成します。

スケジュールは任意に設定します。

また、ターゲットはCodeBuildを選択し、先ほど作成したCodeBuildのARNを指定します。 ロールは、既存のロールを使用するにチェックし、先ほど作成したCloudWatch Events用のロールを指定します。

aws-nuke 設定の記述

次に、aws-nukeの設定ファイルを記述します。

regions:
  - ap-northeast-1
  - global

account-blacklist:
  - 999999999999 # 必須パラメータなのでダミーを登録しておく

resource-types:
  excludes:
    # IAMの設定はaws-nukeでは削除しない
    - IAMGroup
    - IAMGroupPolicyAttachment
    - IAMLoginProfile
    - IAMPolicy
    - IAMRole
    - IAMRolePolicy
    - IAMRolePolicyAttachment
    - IAMUser
    - IAMUserAccessKey
    - IAMUserGroupAttachment
    - IAMVirtualMFADevice

accounts:
  000000000000: # 該当のAWSアカウントIDを指定する
    filters:
      CloudWatchEventsRule:
        - "Rule: aws-nuke-no-dry-run"
      CloudWatchEventsTarget:
        - type: glob
          value: "Rule: aws-nuke-no-dry-run*"
      CloudWatchLogsLogGroup:
        - "/aws/codebuild/aws-nuke"
      CodeBuildProject:
        - type: glob
          value: "aws-nuke-no-dry-run*"
      S3Bucket:
        - "s3://aws-nuke-sample-aws-nuke-config"
      S3Object:
        - property: Bucket
          type: glob
          value: "aws-nuke-sample-aws-nuke-config*"

aws-nukeの実行で、今まで作成してきたCodeBuildやS3、CloudWatch Eventsが削除されないようにfiltersを設定しておく必要があります。

また、間違って必須なIAMを削除するのを防ぐため、IAMユーザ/ロール/ポリシーなどはaws-nukeから削除しない設定にしました。 他にも、用途に合わせて適宜設置を変更してください。

ちゃんと設定されているか、いったんローカルでドライ実行をして確かめてみるとよいです。 問題がなければ、先ほど作成したS3バケットにnuke-config.yamlという名前でアップロードしておきます。

設定は以上です。

結果の確認

あとは、イベントが実行されるのを待つだけです。結果はCloudWatch Logsから確認できます。

ローカルで実行した時と同じように、Nuke completeと表示されていたらOKです。

CloudWatch Eventsで指定したスケジュールにて、定期的自動ですべてのリソースを削除してくれます。

aws-nukeをTerraformで構築

上記をTerraformで構築できるようにしています。あわせてご参照ください。

https://github.com/yutaka0m/terraform-aws-nuke

おわりに

aws-nukeを使ったサンドボックス用AWSアカウントの運用を始めて3ヶ月が経ちました。今のところ問題なく、定期的にリソースを削除してくれています。 AWSコンソールから1つ1つ未使用のリソースを削除していくことに比べたら、かなりの工数削減になりました。

ASKUL Engineering BLOG

2020 © ASKUL Corporation. All rights reserved.