Skip to content

feat(autoscaling): add deletionProtection property to AutoScalingGroup#36924

Merged
mergify[bot] merged 19 commits intoaws:mainfrom
matoom-nomu:feat/add-deletionProtection-to-asg
Feb 25, 2026
Merged

feat(autoscaling): add deletionProtection property to AutoScalingGroup#36924
mergify[bot] merged 19 commits intoaws:mainfrom
matoom-nomu:feat/add-deletionProtection-to-asg

Conversation

@matoom-nomu
Copy link
Contributor

Issue # (if applicable)

None

Reason for this change

ASG supports deletionProtection as documented in the CloudFormation reference.

Description of changes

  • Added deletionProtection property to AutoScalingGroupProps
  • Update README with usage example-

Describe any new or updated permissions being added

None

Description of how you validated changes

Added unit/integ tests.

Checklist


By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@github-actions github-actions bot added p2 valued-contributor [Pilot] contributed between 6-12 PRs to the CDK labels Feb 9, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results48 ran48 passed
TestResult
No test annotations available

@github-actions
Copy link
Contributor

github-actions bot commented Feb 9, 2026

⚠️ Experimental Feature: This security report is currently in experimental phase. Results may include false positives and the rules are being actively refined.
Please try merge from main to avoid findings unrelated to the PR.


TestsPassed ✅SkippedFailed
Security Guardian Results with resolved templates48 ran48 passed
TestResult
No test annotations available

@aws-cdk-automation aws-cdk-automation added the pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. label Feb 9, 2026
Copy link
Contributor

@lpizzinidev lpizzinidev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, ty!

@aws-cdk-automation aws-cdk-automation added pr/needs-maintainer-review This PR needs a review from a Core Team Member and removed pr/needs-community-review This PR needs a review from a Trusted Community Member or Core Team Member. labels Feb 10, 2026
@matboros matboros self-assigned this Feb 12, 2026
@matboros
Copy link
Contributor

Hey, thanks a lot for the pr. It looks solid. Just one question: is there any particular reason for the extensive integ testing? Normally I believe we dont need integ tests for just exposing an L1 property on an L2, the unit tests would be enough for me. If you want to test that the property is transferred, I think a test for a single value would be enough, maybe the none, since that wont prevent test cleanup. Also, you could just rename one of the other tests for a more generic name (e.g. integ.asg-capacity-rebalance.ts to integ.asg-capacity-properties.ts), and add this property there too.
The correct value mapping is already tested with the unit tests.
What do you think?

@aws-cdk-automation aws-cdk-automation removed the pr/needs-maintainer-review This PR needs a review from a Core Team Member label Feb 12, 2026
@mergify mergify bot dismissed matboros’s stale review February 12, 2026 13:33

Pull request has been modified.

@matoom-nomu
Copy link
Contributor Author

matoom-nomu commented Feb 12, 2026

@matboros

Hey, thanks a lot for the pr. It looks solid. Just one question: is there any particular reason for the extensive integ testing? Normally I believe we dont need integ tests for just exposing an L1 property on an L2, the unit tests would be enough for me. If you want to test that the property is transferred, I think a test for a single value would be enough, maybe the none, since that wont prevent test cleanup. Also, you could just rename one of the other tests for a more generic name (e.g. integ.asg-capacity-rebalance.ts to integ.asg-capacity-properties.ts), and add this property there too. The correct value mapping is already tested with the unit tests. What do you think?

Thanks for the comment.

is there any particular reason for the extensive integ testing?

For me, comprehensive testing just makes me feel more confident to send PR.
In this case,I wanted to verify that PREVENT_ALL_DELETION actually blocks stack deletion in practice, not just that the property is passed through correctly. During testing, I confirmed the stack deletion fails as expected when this protection is enabled, which gave me confidence the feature works end-to-end.
I thought comprehensive testing would be safer, but is this a bit too much?

you could just rename one of the other tests for a more generic name

That makes sense.
I wasn't sure if renaming existing integ test files was acceptable practice, so I created a separate test instead.
Now I understand we should consolidate related tests into existing files rather than creating new ones unnecessarily.

@aws-cdk-automation aws-cdk-automation added the pr/needs-maintainer-review This PR needs a review from a Core Team Member label Feb 12, 2026
@matoom-nomu matoom-nomu requested a review from matboros February 13, 2026 01:15
@matboros
Copy link
Contributor

I understand where you are coming from, and it makes totally sense. My main concern is, that this package now has tons of integ tests, which take ages to run, and because of that, they are never run, which renders them useless, since with time they stop working, and noone notices. We are spending effort to make the suit runnable again, and we need to balance out test coverage, with reasonable amount of tests.
I am totally with you on trying out if the feature actually works. Thanks for maintaining high standards around this. It is always a fine line with how much underlying functionality we should be testing in cdk (the property is a CF feature, the actual deletion protection comes from the service).

But if you already spent the effort, lets make the test explicit. I dont think we need all 3 integ test cases (that is a lot of resources and time - we need the 3 cases in unit tests only).
Lets make then the actual integ functionality properly tested. Why not deploy the a stack with PREVENT_ALL_DELETION, assert CF cannot delete it, and then update the stack to no protection (so that the integ test runner can clean this up?)

There are examples for trying to delete the stack (/packages/@aws-cdk-testing/framework-integ/test/aws-cloudformation/test/integ.core-cross-region-references.ts).

@matoom-nomu
Copy link
Contributor Author

@matboros

Thanks for advise !
I'm working on changing the integ-test as you stated.
But It may be difficult to assert that CloudFormation cannot delete a stack containing an ASG with PREVENT_ALL_DELETION, because the stack’s exports are consumed by the assertion stack.
When we attempt to delete the stack, CloudFormation blocks the deletion with:
“Delete canceled. Cannot delete export <integ stack name> as it is in use by <assertion stack name>
So the deletion is blocked due to the export dependency rather than the deletion protection itself.
Given this constraint, how would you prefer we proceed?
One option would be to avoid asserting stack deletion directly and instead assert the ASG configuration via DescribeAutoScalingGroups (verifying that deletion protection is enabled)

@matoom-nomu
Copy link
Contributor Author

matoom-nomu commented Feb 16, 2026

@matboros

Thanks for advise ! I'm working on changing the integ-test as you stated. But It may be difficult to assert that CloudFormation cannot delete a stack containing an ASG with PREVENT_ALL_DELETION, because the stack’s exports are consumed by the assertion stack. When we attempt to delete the stack, CloudFormation blocks the deletion with: “Delete canceled. Cannot delete export <integ stack name> as it is in use by <assertion stack name> So the deletion is blocked due to the export dependency rather than the deletion protection itself. Given this constraint, how would you prefer we proceed? One option would be to avoid asserting stack deletion directly and instead assert the ASG configuration via DescribeAutoScalingGroups (verifying that deletion protection is enabled)

By passing fixed values on the Assertion side, I was able to avoid the import/export issue between stacks.
However, we still need to change the SDK version to implement this test case.

// To the stack including `PREVENT_ALL_DELETION` ASG

test.assertions.awsApiCall('CloudFormation', 'deleteStack', {
  StackName: 'aws-cdk-autoscaling-deletion-protection',
}).next(
  test.assertions.awsApiCall('CloudFormation', 'describeStacks', {
    StackName: 'aws-cdk-autoscaling-deletion-protection',
  }).expect(integ.ExpectedResult.objectLike({
    Stacks: integ.Match.arrayWith([
      integ.Match.objectLike({
        StackName: 'aws-cdk-autoscaling-deletion-protection',
        StackStatus: 'DELETE_FAILED',
      }),
    ]),
  })).waitForAssertions(),
).next(
  test.assertions.awsApiCall('AutoScaling', 'updateAutoScalingGroup', {
    AutoScalingGroupName: 'test-asg-deletion-protection',
    DeletionProtection: 'none',
  })
).next(
  test.assertions.awsApiCall('CloudFormation', 'deleteStack', {
    StackName: 'aws-cdk-autoscaling-deletion-protection',
  })
);

It appears that the Assertion Lambda is using aws-sdk-js/3.895.0, and this version doesn't have the DeletionProtection parameter definition in the UpdateAutoScalingGroup API.
As a result, it ends up calling updateAutoScalingGroup without the DeletionProtection parameter.

Assertion Lambda Log
image

Cloudtrail Log(lack deletionProtection in requset parameter)
スクリーンショット 2026-02-16 15 14 47

How should we proceed with this issue?
Should we update the SDK version and test it as you suggested, or should we modify the test to use just describeAutoScalingGroups to verify the attribute instead (though it would fail at cleanup)?

@matoom-nomu
Copy link
Contributor Author

matoom-nomu commented Feb 16, 2026

@matboros
I modified the integTest with a preDestroy hook and confirmed that deletion is now possible.
Could you please review it again?

@matboros
Copy link
Contributor

matboros commented Feb 18, 2026

Hi @matoom-nomu,

im really sorry for the slow response.

I really like your approach, and I especially liked the tries you did. You said:

By passing fixed values on the Assertion side, I was able to avoid the import/export issue between stacks.

I cannot find that code, how hacky is that?
I like the idea of deploy -> assert cannot delete (with ensuring this is because of the undeletable asg) -> update stack -> let the runtime clean up.

For the update stack, you said that updating through the cli is problematic, becuase it is missing parameters. I'd think, why dont we update the property in the stack, and regenerate the cfn template, and do a cfn deployment of the same stack? sounds more resilient, should work with old cli, tests that value can be updated through cdk/cfn. I like the update being in the predestroy hook, that communicates intent perfectly.

What do you think about this? since you already had all the pieces, it should be simple to test, no?

@matoom-nomu
Copy link
Contributor Author

matoom-nomu commented Feb 19, 2026

Hi @matboros

I like the idea of deploy -> assert cannot delete (with ensuring this is because of the undeletable asg) -> update stack -> let the runtime clean up.

Same opinion too.
I tried several approaches to realize this flow, but each had its own issues.


① Update Cfn via addPropertyOverride

const asg = new autoscaling.AutoScalingGroup(asgStack, 'FleetPreventAll' ・・・

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

* Assertion Codes here

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

const cfnAsg = asg.node.defaultChild as cdk.CfnResource;
cfnAsg.addPropertyOverride('DeletionProtection', autoscaling.DeletionProtection.NONE);

This results in the stack being updated before the assertion runs:

-> initial stack deploy
-> update stack (change DeletionProtection to None)
-> assert cannot delete (with ensuring this is because of the undeletable asg)
-> let the runtime clean up.

So far, I haven’t found a way to perform the stack update after the assertion.


② Update the actual ASG via updateAutoScalingGroup

test.assertions.awsApiCall('AutoScaling', 'updateAutoScalingGroup', {
    AutoScalingGroupName: 'test-asg-deletion-protection',
    DeletionProtection: 'none',
  })

As I mentioned at comment at here
this ends up with calling updateAutoScalingGroup without DeletionProtection: 'none' because the Assertion Lambda runtime uses an older SDK version. As a result, the integ test cleanup fails.


Thus, updating deletionProtection after assertion appears to be difficult at the moment.
So I eventually switched to using a preDestroy hook with the update-autoscaling CLI.

I cannot find that code, how hacky is that?

It’s turned out to be just a matter of stack dependencies.

test.assertions.awsApiCall('CloudFormation', 'deleteStack', {
  // ❌ Cannot delete: the assertion stack created by integ tests imports/references this stack, which prevents deletion.  
  StackName: asg.autoScalingGroupName, 
  // ↓ ⭕ Can delete: there is no relationship between the assertion stack and this test stack.
  StackName: 'aws-cdk-autoscaling-deletion-protection', //OK
})

@matboros
Copy link
Contributor

Hi @matoom-nomu,
thanks for the response.

This results in the stack being updated before the assertion runs:

-> initial stack deploy
-> update stack (change DeletionProtection to None)
-> assert cannot delete (with ensuring this is because of the undeletable asg)
-> let the runtime clean up.

are you sure about step 2? i would assume, based on the code you wrote, that you are modifying the initial stack, so the initial stack will deploy DeletionProtection none, no? the actual runtime execution all happens afterwards. My tip would be (without having tried):

const stackName = "aws-cdk-autoscaling-deletion-protection";
const asgStack = new cdk.Stack(app, stackName);
const asg = new autoscaling.AutoScalingGroup(asgStack, 'FleetPreventAll' ・・・


// assertion logic

test.assertions.awsApiCall('CloudFormation', 'deleteStack', {
  StackName: stackName,
})

// get the template you will use for update
const cfnAsg = asg.node.defaultChild as cdk.CfnResource;
const originalValue = <get the original valeu>;
cfnAsg.addPropertyOverride('DeletionProtection', autoscaling.DeletionProtection.NONE);
// generate the cfn template used for updates
const templateString = JSON.stringify(Template.fromStack(asgStack).toJSON(), null, 2);
// now set the property back
cfnAsg.addPropertyOverride('DeletionProtection', originalValue);


// now use cfn updatestack in your predestoy

did you try this? i would expect it to work.

and one more thing: why do you set stackUpdateWorkflow: false, ? do you need that?

@matoom-nomu
Copy link
Contributor Author

Hi @matboros,

Thanks again for your guidance, I really appreciate it.
I updated the integ-test using the approach you suggested, and it works as intended now.

and one more thing: why do you set stackUpdateWorkflow: false, ? do you need that?

I had added stackUpdateWorkflow: false as a workaround, but I've removed it now.

@matboros matboros added the pr/needs-integration-tests-deployment Requires the PR to deploy the integration test snapshots. label Feb 25, 2026
@matboros matboros temporarily deployed to deployment-integ-test February 25, 2026 08:03 — with GitHub Actions Inactive
Copy link
Contributor

@matboros matboros left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A pity you removed the predestroy hook, i liked it since it communicated intent better, but this works as well. thanks a lot for the contribution!

@mergify
Copy link
Contributor

mergify bot commented Feb 25, 2026

Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@mergify mergify bot had a problem deploying to deployment-integ-test February 25, 2026 08:36 Error
@mergify
Copy link
Contributor

mergify bot commented Feb 25, 2026

Merge Queue Status

Rule: default-squash


  • Entered queue2026-02-25 08:36 UTC
  • Checks passed · in-place
  • Merged2026-02-25 23:35 UTC · at aadda4e802ac9e4f36a16763f56761bc0dd50454

This pull request spent 14 hours 58 minutes 22 seconds in the queue, including 9 hours 15 seconds running CI.

Required conditions to merge

@aws-cdk-automation aws-cdk-automation removed the pr/needs-maintainer-review This PR needs a review from a Core Team Member label Feb 25, 2026
@mergify mergify bot had a problem deploying to deployment-integ-test February 25, 2026 11:35 Error
@mergify mergify bot temporarily deployed to deployment-integ-test February 25, 2026 14:34 Inactive
@mergify mergify bot merged commit 467f2b4 into aws:main Feb 25, 2026
24 of 25 checks passed
@github-actions
Copy link
Contributor

Comments on closed issues and PRs are hard for our team to see.
If you need help, please open a new issue that references this one.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Feb 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

p2 pr/needs-integration-tests-deployment Requires the PR to deploy the integration test snapshots. valued-contributor [Pilot] contributed between 6-12 PRs to the CDK

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants