CloudFormation のベストプラクティスから逸脱してみた
AWS CloudFormation のベストプラクティス - AWS CloudFormation
スタックのリソースを CloudFormation 以外の方法で変更しないでください。変更するとスタックのテンプレートとスタックリソースの現在の状態の間で不一致が起こり、スタックの更新または削除でエラーが発生する場合があります。
上述の通り、CloudFormation で作成したリソースを CloudFormation 以外の方法で変更することは非推奨ですが、今回はあえて上記から逸脱してどのようなことが起きるのか確認してみました。
CloudFormation で作成したリソースについて
CloudFormation で作成したリソースという範囲には以下のような方法で作成されたリソースも含まれます。
- AWS CDK で作成したリソース
- AWS SAM で作成したリソース
- コンソール操作の裏側で CloudFormation によって作成されたリソース
- Elastic Beanstalk 環境
- ECS クラスターや ECS サービス
- Amplify CLI から作成されたリソース
- Cloud9 環境
上記以外にも該当するリソースはあると思われます。
どのリソースが CloudFormation から作成されたのかについては、リソースタグで判別できます。
以下のタグが付与されているリソースは CloudFormation から作成されています。
- aws:cloudformation:logical-id
- aws:cloudformation:stack-id
- aws:cloudformation:stack-name
ユーザーが定義する任意のタグに加えて、CloudFormation はプレフィックス aws: が付いた次のようなスタックレベルのタグを自動的に作成します。
CloudFormation 以外の方法について
CloudFormation 以外の方法での変更としては以下のような操作があります。
- コンソールからの操作
- AWS CLI からの操作
- AWS SDK を使用したプログラムからの操作
今回はコンソールからの操作で検証してみました。
検証手順
- CloudFormation で VPC を作成
- VPC をコンソールからの操作で削除
- CloudFormation から VPC の設定を更新
1. CloudFormation で VPC を作成
【CloudFormation入門】5分と6行で始めるAWS CloudFormationテンプレートによるインフラ構築 | DevelopersIO
まずは以下の CloudFormation テンプレートで VPC を作成します。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
SampleVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
CloudFormation コンソールからテンプレートファイルをアップロードして VPC を作成しました。
作成された VPC のタグには上述の CloudFormation に関するタグが自動的に付与されています。
上記のドキュメントにも記載されている通り、CloudFormation によって付与されたタグを更新、削除することはできません。
また、リソースタグとしてもカウントされないため、コンソール上でもタグの編集画面には表示されません。
2. VPC をコンソールからの操作で削除
ここで CloudFormation のベストプラクティスから逸脱した操作として、コンソールから VPC を削除します。
CloudFormation スタックでドリフトを検出すると、「DELETED」のステータスになっています。
CloudFormation テンプレートと実際のリソースに差異が発生しているためドリフトが発生している状態です。
この状態で CloudFormation スタックの更新や削除を実施するとエラーが発生する可能性があるという内容が冒頭のドキュメントの内容です。
3. CloudFormation から VPC の設定を更新
ドリフトが発生した状態で以下の CloudFormation テンプレートを使用してスタックを更新してみます。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
SampleVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
Tags:
- Key: Name
Value: Sample-vpc
タグを追加するだけの更新です。
スタックを更新したところ、以下のエラーが発生して更新できませんでした。
Resource handler returned message: "The vpc ID 'vpc-0b4638bd2d747e6e0' does not exist (Service: Ec2, Status Code: 400, Request ID: ed7332b0-3921-4871-91c8-0c659d6a1dc2)" (RequestToken: a3c8d0df-ff38-5241-bd49-d23bdf43d0e3, HandlerErrorCode: NotFound)
エラーメッセージに記載されている通り、更新対象の VPC が存在しないため更新ができない状況です。
CloudTrail 側には CreateTags でエラーが記録されていました。
"errorCode": "Client.InvalidVpcID.NotFound",
"errorMessage": "The vpc ID 'vpc-0b4638bd2d747e6e0' does not exist",
これがドリフト状態で CloudFormation スタックの更新や削除を実施するとエラーが発生するという状況です。
解決策 1
UPDATE_ROLLBACK_FAILED ステータスで停止している CloudFormation スタックを回復する | AWS re:Post
スタックのステータスにもよりますが、ステータスが UPDATE_ROLLBACK_FAILED の場合には上記ナレッジセンターに記載されている手順をお試しください。
- スタックの削除
- スタックのロールバック
今回はスタックのステータスが UPDATE_ROLLBACK_COMPLETE なので、スタックの削除での対応が可能です。
解決策 2
CloudFormationでロールバックしてしまったときに注意してほしいこと #AWS - Qiita
設定値を成功するように適当に変更
上記ブログで紹介されている通り、いったん関連のないリソースをテンプレートで定義して更新する方法もあります。
この方法を使用することで、スタックを削除せずに VPC の設定を CloudFormation から削除できます。
まず、以下のようなダミーでの更新用テンプレートを作成します。
この時、既存のリソース定義は変更せず、ダミー用のリソースのみ追記します。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
SampleVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/16
# ダミー用のリソース追記
DummyVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/18
上記テンプレートでスタックを更新します。
削除された VPC に対する更新操作がないためダミー用の VPC の作成操作のみが行われ、スタックの更新が完了しました。
ただし、この状況ではまだ CloudFormation 側は削除された VPC がスタックに含まれていると認識しています。
そのため、次は以下のように削除した VPC の定義をテンプレートからも削除します。
AWSTemplateFormatVersion: "2010-09-09"
Resources:
DummyVpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: 10.0.0.0/18
この時、ダミー用リソースも不要であればテンプレートから削除し、本来必要なリソースを追記しても OK です。
今回はダミー用 VPC の定義だけ残して再度スタックを更新します。
テンプレートから SampleVpc の定義を削除して更新したことでスタックからも SampleVpc が削除されました。
これでダミー用 VPC のみがスタックに残り、CloudFormation 側と実際のリソースの状態が一致しました。
再度ドリフトを検出しても IN_SYNC となったため、ドリフトも発生していません。
解決策 1 のスタックを削除の方が手順は少ないですが、スタックを削除せずに対応したい場合にはダミーリソースでの更新もご検討ください。
まとめ
CloudFormation のベストプラクティスから逸脱してみた結果を紹介しました。
どなたかの参考になれば幸いです。
Discussion