Repository navigation
fix(iac/azure): move reservation role definition to bootstrap; runtime keeps only the assignment - #1095
Conversation
…e keeps only the assignment (closes #1092) The runtime container-apps module instantiated the cudly-reservation-role module, which creates an azurerm_role_definition. Creating a role definition needs Microsoft.Authorization/roleDefinitions/write, a bootstrap-class permission the CI deploy service principal intentionally lacks (it has only roleDefinitions/read plus roleAssignments/{read,write,delete}). Every Azure deploy therefore 403'd at the role-definition write, exactly as the bootstrap-vs-runtime IAM split intends. Fix, honoring the split (no roleDefinitions/write granted to the deploy SP): - Bootstrap: create the host-side reservation role definition in the human-applied ci-cd-permissions module (new reservation_role.tf) and output its resource ID and display name. - Runtime: stop creating the definition in container-apps; resolve it via data.azurerm_role_definition by name + subscription scope and keep only the azurerm_role_assignment. A missing definition fails loud ("not found"), signalling the operator to re-run the bootstrap rather than widening the SP. - Shared module: factor the role display name into a local (single source of truth) and expose it via a role_definition_name output so the runtime lookup stays in lockstep. - Drop the tenant-root "/providers/Microsoft.Capacity" assignable scope (a subscription-scoped principal cannot register a scope above its subscription, a latent 403). It is now gated behind include_capacity_provider_scope (default false); the role is only ever assigned at subscription scope. REQUIRED MANUAL STEP: a privileged human must re-apply the ci-cd-permissions bootstrap once to create the role definition before the next runtime deploy. Verified offline: terraform fmt -check, terraform validate, and tflint are clean on the shared module, the bootstrap env, and the container-apps module (apply not run; staging-first).
|
Warning Review limit reached
More reviews will be available in 10 minutes and 39 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
Summary
Fixes the deterministic 403 that blocks every Azure Container Apps deploy
(#1092). The runtime container-apps module instantiated the
cudly-reservation-rolemodule, which creates anazurerm_role_definition.Creating a role definition requires
Microsoft.Authorization/roleDefinitions/write, a bootstrap-class permissionthe CI deploy service principal intentionally lacks (it holds only
roleDefinitions/readplusroleAssignments/{read,write,delete}). So theruntime apply 403'd at the role-definition write every run, exactly as the
bootstrap-vs-runtime IAM split intends. The bug was a bootstrap-class resource
sitting in the runtime apply path.
Root cause and diagnosis:
docs/code-review/21-azure-deploy-failures.md(Finding A).
Fix (honors the split; does NOT grant
roleDefinitions/writeto the deploy SP)definition in
terraform/environments/azure/ci-cd-permissions/(new
reservation_role.tf), and output its resource ID + display name.modules/compute/azure/container-apps): stop creating thedefinition; resolve it via
data.azurerm_role_definitionby name +subscription scope and keep only the
azurerm_role_assignment(the deploy SPhas
roleAssignments/write). A missing definition fails loud with a"not found" error, signalling the operator to re-run the bootstrap rather than
widening the SP.
modules/iam/azure/cudly-reservation-role): factor therole display name into a
local(single source of truth) and expose it via arole_definition_nameoutput so the runtime lookup stays in lockstep./providers/Microsoft.Capacityfromassignable_scopes(a subscription-scopedprincipal cannot register a scope above its subscription, a latent 403). It is
now gated behind a new
include_capacity_provider_scopevariable(default
false); the role is only ever assigned at subscription scope. Thisapplies to both the host-side and customer-side
(
iac/federation/azure-target) consumers of the shared module.REQUIRED MANUAL STEP (privileged human, before the next runtime deploy)
A privileged human must re-apply the
terraform/environments/azure/ci-cd-permissions/bootstrap module once so the host-side reservation role definition exists:
Until that bootstrap apply lands, the runtime
data.azurerm_role_definitionlookup will fail loudly with "Role Definition ... was not found" - the intended
signal to run the bootstrap, NOT to widen the deploy SP's permissions. After the
bootstrap apply, the next Azure deploy resolves the role and creates only the
assignment, which the deploy SP is allowed to do.
Verification
Terraform apply / deploy was NOT run (staging-first; the bootstrap module is
applied manually by a privileged human). Static checks, run offline against
cached providers because the public Terraform registry was unreachable during
this work:
terraform fmt -recursive -check: clean on all touched paths.terraform validate: clean on the shared module, theci-cd-permissionsbootstrap env, and the
container-appsruntime module.tflint: clean (no findings) on all three.Notes / follow-ups
See
docs/code-review/open-questions/fix-azure-deploy-1092.md(not committed).One deliberate deferral: the shared module's provider constraint was left at
>= 3.0(consumers pin~> 3.0). Aligning it forces a regeneration of themodule's tracked
.terraform.lock.hcl, which needs registry access that wasunavailable here; the deploy path is unaffected because the parent roots already
govern the provider version. A follow-up can align the constraint and relock
online.
Closes #1092