module.compute_container_apps[0].azurerm_role_assignment.reservations_purchaser is destroyed and recreated on every single apply, so the host identity's reservation-purchase grant is briefly revoked on every deploy.
Found while verifying the #1794 fix in deploy run 31545175691, where it appears as one of exactly three destroys.
Why
Both role_definition_id and scope derive from a data source that is deferred to apply time (data.azurerm_role_definition.cudly_reservation_purchaser, which Terraform reports as will be read during apply). Both attributes are therefore always (known after apply), and both force replacement on azurerm_role_assignment. So the resource can never be seen as unchanged, regardless of whether anything actually changed.
Why it matters
This is a money-path grant. It is what lets the host identity call calculatePrice and reservationOrders/write. There is a window on every deploy where the assignment does not exist, and a purchase attempting to run in that window would 403.
The window is short, but the deploy is not coordinated with purchase activity in any way, so nothing rules the overlap out. It also produces misleading churn in every plan, which trains reviewers to skim past a destroy line on a permissions resource, and that is its own hazard.
Fix direction
Stop making the assignment depend on apply-time-unknown values. Options worth weighing:
- Resolve the role definition by a stable, statically-known ID rather than a name lookup, so
role_definition_id is known at plan time. The bootstrap stack already outputs role_definition_resource_id; consuming that through a documented channel (remote state or an explicit variable) removes the data source entirely.
- Failing that, pin
scope to a statically-derivable subscription ID rather than routing it through the deferred data source.
Note the deliberate bootstrap-vs-runtime split documented in terraform/modules/compute/azure/container-apps/main.tf: the role definition is created by the human-applied bootstrap stack, and the runtime stack only looks it up. Any fix has to respect that split rather than move definition ownership into the runtime stack.
Verification
Apply twice with no intervening changes and confirm the second plan reports no changes for this resource. That is the whole test, and today it fails.
Then confirm the grant is continuously present across a deploy rather than merely present afterwards, since an assignment that is destroyed and recreated still ends in the correct final state while having been absent in between.
Related
module.compute_container_apps[0].azurerm_role_assignment.reservations_purchaseris destroyed and recreated on every single apply, so the host identity's reservation-purchase grant is briefly revoked on every deploy.Found while verifying the #1794 fix in deploy run 31545175691, where it appears as one of exactly three destroys.
Why
Both
role_definition_idandscopederive from a data source that is deferred to apply time (data.azurerm_role_definition.cudly_reservation_purchaser, which Terraform reports aswill be read during apply). Both attributes are therefore always(known after apply), and both force replacement onazurerm_role_assignment. So the resource can never be seen as unchanged, regardless of whether anything actually changed.Why it matters
This is a money-path grant. It is what lets the host identity call
calculatePriceandreservationOrders/write. There is a window on every deploy where the assignment does not exist, and a purchase attempting to run in that window would 403.The window is short, but the deploy is not coordinated with purchase activity in any way, so nothing rules the overlap out. It also produces misleading churn in every plan, which trains reviewers to skim past a destroy line on a permissions resource, and that is its own hazard.
Fix direction
Stop making the assignment depend on apply-time-unknown values. Options worth weighing:
role_definition_idis known at plan time. The bootstrap stack already outputsrole_definition_resource_id; consuming that through a documented channel (remote state or an explicit variable) removes the data source entirely.scopeto a statically-derivable subscription ID rather than routing it through the deferred data source.Note the deliberate bootstrap-vs-runtime split documented in
terraform/modules/compute/azure/container-apps/main.tf: the role definition is created by the human-applied bootstrap stack, and the runtime stack only looks it up. Any fix has to respect that split rather than move definition ownership into the runtime stack.Verification
Apply twice with no intervening changes and confirm the second plan reports no changes for this resource. That is the whole test, and today it fails.
Then confirm the grant is continuously present across a deploy rather than merely present afterwards, since an assignment that is destroyed and recreated still ends in the correct final state while having been absent in between.
Related