スタックが削除される時でなければDeletionPolicyのRetainは効かない?
こんにちは、のんピ(@non____97)です。
皆さんはスタックが削除される時でなければDeletionPolicyのRetainは効かないのか気になったことはありますか? 私はあります。
AWS公式ドキュメントにはDeletionPolicyは「スタックが削除された際に」という条件しか記載ありません。
DeletionPolicy 属性を使用すると、スタックが削除された際にリソースをRetainし、場合によってはバックアップすることもできます。制御する各リソースに対して DeletionPolicy 属性を指定します。DeletionPolicy 属性が設定されていない場合、AWS CloudFormation ではデフォルトでリソースが削除されます。
リソースの論理IDを変更して更新した場合など、スタックの削除ではなく、スタックの更新によってリソースが削除される場合はDeletionPolicyが効かないのでしょうか。
効くとは思いますが、あまり意識せずに普段触っており、確信が持てなかったので検証してみます。
いきなりまとめ
- CloudFormationのDeletion Policyはスタックが削除されるタイミングに限らず、リソースが削除されるタイミングでも動作する
- スタック更新中にロールバックした場合もDeletionPolicyは効く
やってみた
DeletionPolicyをRetainにしたリソースの作成
では、やってみます。
まず、DeletionPolicyをRetainにしたリソースの作成をします。
使用するテンプレートは以下の通りです。
service-linked-role.yml
AWSTemplateFormatVersion: "2010-09-09"
Conditions:
IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1]
Resources:
AWSServiceRoleForGlobalAccelerator:
Condition: IsControlPlaneRegion
DeletionPolicy: Retain
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: globalaccelerator.amazonaws.com
AWS CLIでStackを作成します。
$ aws cloudformation deploy \
--stack-name service-linked-role-globalaccelerator \
--template-file service-linked-role.yml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1
Waiting for changeset to be created..
Waiting for stack create/update to complete
Successfully created/updated stack - service-linked-role-globalaccelerator
作成後、Stackのイベントを確認します。特にエラーなく完了していますね。
リソースも問題なく作成完了しています。
DeletionPolicyをRetainにしたリソースの削除
それでは、DeletionPolicyをRetainにしたリソースの削除をしようとしてみます。
テンプレートを以下のように変更しました。
- 論理IDを
AWSServiceRoleForGlobalAccelerator
からAWSServiceRoleForGlobalAccelerator2
に変更 CustomSuffix
を付与- 既存のAWSServiceRoleForGlobalAcceleratorとロール名が重複したことによるエラーを防ぐ
service-linked-role.yml
AWSTemplateFormatVersion: "2010-09-09"
Conditions:
IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1]
Resources:
AWSServiceRoleForGlobalAccelerator2:
Condition: IsControlPlaneRegion
DeletionPolicy: Retain
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: globalaccelerator.amazonaws.com
CustomSuffix: TestSuffix
それでは変更セットを作成します。
$ aws cloudformation deploy \
--stack-name service-linked-role-globalaccelerator \
--template-file service-linked-role.yml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1 \
--no-execute-changeset
Waiting for changeset to be created..
Changeset created successfully. Run the following command to review changes:
aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067
作成した変更セットを確認します。
aws cloudformation describe-change-set \
--change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067
{
"Changes": [
{
"Type": "Resource",
"ResourceChange": {
"Action": "Add",
"LogicalResourceId": "AWSServiceRoleForGlobalAccelerator2",
"ResourceType": "AWS::IAM::ServiceLinkedRole",
"Scope": [],
"Details": []
}
},
{
"Type": "Resource",
"ResourceChange": {
"Action": "Remove",
"LogicalResourceId": "AWSServiceRoleForGlobalAccelerator",
"PhysicalResourceId": "AWSServiceRoleForGlobalAccelerator",
"ResourceType": "AWS::IAM::ServiceLinkedRole",
"Scope": [],
"Details": []
}
}
],
"ChangeSetName": "awscli-cloudformation-package-deploy-1690698779",
"ChangeSetId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067",
"StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/service-linked-role-globalaccelerator/e95ecaa0-2ea1-11ee-88eb-12a6b76090b7",
"StackName": "service-linked-role-globalaccelerator",
"Description": "Created by AWS CLI at 2023-07-30T06:32:59.614445 UTC",
"Parameters": null,
"CreationTime": "2023-07-30T06:33:00.949000+00:00",
"ExecutionStatus": "AVAILABLE",
"Status": "CREATE_COMPLETE",
"StatusReason": null,
"NotificationARNs": [],
"RollbackConfiguration": {},
"Capabilities": [
"CAPABILITY_NAMED_IAM"
],
"Tags": null,
"ParentChangeSetId": null,
"IncludeNestedStacks": false,
"RootChangeSetId": null
}
論理IDAWSServiceRoleForGlobalAccelerator2
が追加されて、論理IDAWSServiceRoleForGlobalAccelerator
が削除されそうですね。
それでは、こちらの変更セットを実行します。
$ aws cloudformation execute-change-set \
--change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690698779/bcd7c57d-a329-4c76-ac29-9ab724ae6067
実行後、Stackのイベントを確認するとResource handler returned message: "Custom suffix is not allowed for globalaccelerator.amazonaws.com
とエラーになっていました。
どうやらAWSServiceRoleForGlobalAccelerator
はカスタムサフィックスを指定できないようです。
しょうがないので、テンプレートを以下のようにAWSServiceRoleForCloudHSM
を作成するようなものに変更します。
service-linked-role.yml
AWSTemplateFormatVersion: "2010-09-09"
Conditions:
IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1]
Resources:
AWSServiceRoleForCloudHSM:
Condition: IsControlPlaneRegion
DeletionPolicy: Retain
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: cloudhsm.amazonaws.com
それでは変更セットを作成して、作成された変更セットを確認します。
$ aws cloudformation deploy \
--stack-name service-linked-role-globalaccelerator \
--template-file service-linked-role.yml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1 \
--no-execute-changeset
Waiting for changeset to be created..
Changeset created successfully. Run the following command to review changes:
aws cloudformation describe-change-set --change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287
$ aws cloudformation describe-change-set \
--change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287
{
"Changes": [
{
"Type": "Resource",
"ResourceChange": {
"Action": "Add",
"LogicalResourceId": "AWSServiceRoleForCloudHSM",
"ResourceType": "AWS::IAM::ServiceLinkedRole",
"Scope": [],
"Details": []
}
},
{
"Type": "Resource",
"ResourceChange": {
"Action": "Remove",
"LogicalResourceId": "AWSServiceRoleForGlobalAccelerator",
"PhysicalResourceId": "AWSServiceRoleForGlobalAccelerator",
"ResourceType": "AWS::IAM::ServiceLinkedRole",
"Scope": [],
"Details": []
}
}
],
"ChangeSetName": "awscli-cloudformation-package-deploy-1690699228",
"ChangeSetId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287",
"StackId": "arn:aws:cloudformation:us-east-1:<AWSアカウントID>:stack/service-linked-role-globalaccelerator/e95ecaa0-2ea1-11ee-88eb-12a6b76090b7",
"StackName": "service-linked-role-globalaccelerator",
"Description": "Created by AWS CLI at 2023-07-30T06:40:28.682688 UTC",
"Parameters": null,
"CreationTime": "2023-07-30T06:40:30.020000+00:00",
"ExecutionStatus": "AVAILABLE",
"Status": "CREATE_COMPLETE",
"StatusReason": null,
"NotificationARNs": [],
"RollbackConfiguration": {},
"Capabilities": [
"CAPABILITY_NAMED_IAM"
],
"Tags": null,
"ParentChangeSetId": null,
"IncludeNestedStacks": false,
"RootChangeSetId": null
}
論理IDAWSServiceRoleForCloudHSM
が追加されて、論理IDAWSServiceRoleForGlobalAccelerator
が削除されそうですね。
こちらの変更セットを実行します。
$ aws cloudformation execute-change-set \
--change-set-name arn:aws:cloudformation:us-east-1:<AWSアカウントID>:changeSet/awscli-cloudformation-package-deploy-1690699228/abda1f6d-dbb2-4b45-82e0-91d429fb9287
実行後のイベントは以下のようになっていました。
問題なく更新できていますね。論理IDAWSServiceRoleForGlobalAccelerator
はDELETE_SKIPPED
となっていることが分かります。
リソースタブからも論理IDAWSServiceRoleForGlobalAccelerator
は無くなっています。
IAMのコンソールからAWSServiceRoleForGlobalAcceleratorが残っているか確認すると、確かに削除されずに存在していました。
スタック更新中にロールバックした場合もDeletionPolicy Retainは効くのか
スタック更新中にロールバックした場合もDeletionPolicy Retainは効くのか気になったので検証してみます。
以下のようにDeletionPolicyがRetainなリソースAWSServiceRoleForGlobalAccelerator
作成後に、必ず作成に失敗するAWSServiceRoleForGlobalAccelerator2
を定義してみました。
service-linked-role.yml
AWSTemplateFormatVersion: "2010-09-09"
Conditions:
IsControlPlaneRegion: !Equals [!Ref AWS::Region, us-east-1]
Resources:
AWSServiceRoleForGlobalAccelerator:
Condition: IsControlPlaneRegion
DeletionPolicy: Retain
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: globalaccelerator.amazonaws.com
AWSServiceRoleForGlobalAccelerator2:
Condition: IsControlPlaneRegion
DeletionPolicy: Retain
DependsOn: AWSServiceRoleForGlobalAccelerator
Type: "AWS::IAM::ServiceLinkedRole"
Properties:
AWSServiceName: globalaccelerator.amazonaws.com
CustomSuffix: TestSuffix
IAMのコンソールから先の検証で作成したAWSServiceRoleForGlobalAcceleratorを削除しておきます。
この状態でStackを更新します。
$ aws cloudformation deploy \
--stack-name service-linked-role-globalaccelerator \
--template-file service-linked-role.yml \
--capabilities CAPABILITY_NAMED_IAM \
--region us-east-1
Waiting for changeset to be created..
Waiting for stack create/update to complete
Failed to create/update the stack. Run the following command
to fetch the list of events leading up to the failure
aws cloudformation describe-stack-events --stack-name service-linked-role-globalaccelerator
Stackの更新に失敗していますね。
イベントを確認すると、論理IDAWSServiceRoleForGlobalAccelerator
はDELETE_SKIPPED
となっていることが分かります。また、作成に失敗した論理IDAWSServiceRoleForGlobalAccelerator2
もDELETE_SKIPPED
となっていました。
リソースタブから論理IDAWSServiceRoleForGlobalAccelerator
とAWSServiceRoleForGlobalAccelerator2
のリソースが存在しないことを確認します。
IAMのコンソールからAWSServiceRoleForGlobalAcceleratorが残っているか確認すると、確かに削除されずに存在していました。
そのため、CloudFormationでDeletion PolicyをRetainにしているリソースが含まれている場合に、Stackの作成に失敗するとそのリソースが残ることになります。
もし、そのリソースの物理IDを固定している場合はStackの再作成をする際に「同じ名前のリソースが存在する」とエラーになるでしょう。
Deletion Policyでどのリソースが残るのか意識しよう
CloudFormationのDeletion Policyはスタックが削除されるタイミングに限らず、リソースが削除されるタイミングでも動作することを確認しました。
間違ってリソースが削除されることを防ぐ意味でDeletion Policyは便利ですが、意識しなければ不要なリソースが残り続けたり、Stackの再作成をしようとした時に思わぬところでエラーになりそうです。
この記事が誰かの助けになれば幸いです。
以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!