Skip to content

Reservation-purchaser role assignment is destroyed and recreated on every apply, briefly revoking a money-path grant #1802

Description

@cristim

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions