Serialize Claude model deployments after Foundry role assignments to absorb RBAC propagation lag - #39
Merged
Conversation
When ASSIGN_RBAC=true, each model deployment now dependsOn both Foundry User and Foundry Project Manager role assignments on the Foundry account. The role-assignment PUT returns in ~5s but Foundry data-plane RBAC takes a few minutes to propagate; the slow model-deployment LRO (30s-20min) absorbs that wait, so the first claude -p / Python SDK call after azd up succeeds without retries. Bicep and Terraform variants updated for parity. When ASSIGN_RBAC is false the role-assignment resources are if(false)/count=0 and the dependency edges are dropped, so there is no extra wait.
Arun Sekhar (achandmsft)
added a commit
that referenced
this pull request
Jun 11, 2026
…C=true Replaces the two-role assignment (Foundry User + Foundry Project Manager) with a single Cognitive Services User assignment on the Foundry account. This is the smallest built-in role whose data actions cover Microsoft.CognitiveServices/accounts/MaaS/* (the Claude inference path). Preserves the issue #38 / #39 serialization: all three Claude deployments still dependsOn the role-assignment resource, so the model-deployment LRO absorbs RBAC propagation lag. Verified end-to-end with ASSIGN_RBAC=true: azd up succeeded, verifier 10/10 PASS including live claude -p round trip, python src/hello_claude.py succeeded on first call with no retries. Closes #40.
Arun Sekhar (achandmsft)
added a commit
that referenced
this pull request
Jun 11, 2026
…C=true (#41) Replaces the two-role assignment (Foundry User + Foundry Project Manager) with a single Cognitive Services User assignment on the Foundry account. This is the smallest built-in role whose data actions cover Microsoft.CognitiveServices/accounts/MaaS/* (the Claude inference path). Preserves the issue #38 / #39 serialization: all three Claude deployments still dependsOn the role-assignment resource, so the model-deployment LRO absorbs RBAC propagation lag. Verified end-to-end with ASSIGN_RBAC=true: azd up succeeded, verifier 10/10 PASS including live claude -p round trip, python src/hello_claude.py succeeded on first call with no retries. Closes #40. Co-authored-by: Arun Sekhar <achand@microsoft.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #38.
Summary
When
ASSIGN_RBAC=true, both IaC variants now order each Claude model deployment after theFoundry User+Foundry Project Managerrole assignments on the Foundry account. The role-assignment PUTs return fast (~5 s) but Foundry data-plane RBAC takes a few minutes to propagate; the slow model-deployment LRO (30 s–20 min) absorbs that propagation wait, so the firstclaude -p/ Python SDK call afterazd upsucceeds without retries.Changes
infra-bicep/infra/foundry.bicep— movedfoundryUserAssignment/foundryProjectManagerAssignmentdeclarations above the deployments and added both to each deployment'sdependsOn. Comment explains the intent.infra-terraform/infra/main.tf— added the twoazurerm_role_assignmentresources to eachazapi_resource.claude_*depends_on. Comment explains the intent.README.md401 PermissionDenied: updated to reflect the new behavior; the manual-grant path still needs the usual wait.Why this works in all four cases
dependsOnedges toif(false)/count=0resources are dropped — no wait.if(false)/count=0; no work at all.rbacEnabled = false, the role-assignment resources areif(false)and Bicep drops dependency edges to skipped resources.depends_onon a resource address withcount = 0resolves to an empty collection, so the dependency is satisfied immediately.Validation
az bicep build --file infra-bicep/infra/main.bicep— exit 0 (three pre-existing BCP037 warnings onmodelProviderDataonly; runtime-valid property the Bicep type schema doesn't yet know about).terraform fmt -check,terraform init -backend=false,terraform validatefrominfra-terraform/infra— all exit 0, "Success! The configuration is valid."No new resources, no new variables, no new env-var contract.