こんにちは、ゆたか(@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アカウントID
000000000000
の - 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つ未使用のリソースを削除していくことに比べたら、かなりの工数削減になりました。