Skip to content

feat(infra) grant Cosmos data-plane RBAC to developer principal in Bicep#60

Merged
jkeeley2073 merged 1 commit into
mainfrom
Dev-CosmosDataPlaneRbac
May 3, 2026
Merged

feat(infra) grant Cosmos data-plane RBAC to developer principal in Bicep#60
jkeeley2073 merged 1 commit into
mainfrom
Dev-CosmosDataPlaneRbac

Conversation

@jkeeley2073
Copy link
Copy Markdown
Contributor

Summary

Closes the Cosmos data-plane RBAC gap that the original Bicep author explicitly deferred:

//   Cosmos DB Built-in Data Contrib — 00000000-... (data-plane;
//   assigned via az SQL role-assignment, not RBAC role-assignment —
//   out of scope here)

Caught it on the first --ensure-cosmos-containers smoke-test post-deploy:

Forbidden (403); Substatus: 5301; Reason: Request blocked by Auth pinwiz-cosmos-dev-hlpz4
principal [fb4fdb3e-...] does not have required RBAC permissions to perform action
[Microsoft.DocumentDB/databaseAccounts/readMetadata] on resource [/].

ARM-level RBAC (the other 5 role assignments in the developer-RBAC block) doesn't cover Cosmos NoSQL data-plane operations. Cosmos uses a separate Bicep type — Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments — under the database account itself. Built-in role 00000000-0000-0000-0000-000000000002 (Cosmos DB Built-in Data Contributor) covers the read/write needed by CosmosBootstrapper.EnsureCreatedAsync and the production MachineRepository / IngestionSourceRepository paths.

Gates on !empty(developerObjectId) only — NOT on deployPhase2. Cosmos itself is Phase 1 and read/write is needed to validate the deploy.

The developer-RBAC comment block is updated: removed the "out of scope here" note for the Cosmos role; added a paragraph explaining the Bicep-namespace difference so the next reader doesn't try to consolidate this with the standard Microsoft.Authorization/roleAssignments block.

Test Plan

  • az bicep build -> exit 0 (Bicep compiles clean)
  • dotnet build / dotnet test -> 503 / 503 unchanged (pure IaC change)
  • Live re-validation post-merge: user re-runs pwsh ./infra/scripts/Deploy-SharedResources.ps1 -Environment dev against the existing Phase 1 deploy. ARM is idempotent for everything that already exists; only the new cosmosDataContributor resource is added. Then dotnet run --project src/PinballWizard.Cli -- --ensure-cosmos-containers should print:
    Container 'machines' ready (partition key /manufacturer, default TTL none).
    Container 'ingestion_sources' ready (partition key /partitionKey, default TTL none).
    Cosmos database + containers ensured.
    

Out of Scope

  • Splitting the developer-RBAC block into Phase-1 and Phase-2 sub-blocks. The new Cosmos role is the only Phase-1-RBAC entry today, plus 5 Phase-2 entries; the gating is per-resource via if (deployPhase2 && ...). Splitting into separate blocks adds noise without clarity.
  • Granting data-plane roles to a future API service principal. Phase 2 ACA Apps will need Cosmos DB Built-in Data Contributor on their managed identities; a follow-up PR adds those role assignments at the same time the ACA env is provisioned.

Checklist

  • CI is green (Bicep lint + dotnet build/test/codeql/sanitization)
  • PR title follows the Conventional Commits format
  • No TODO / FIXME / commented-out code committed

Pre-push self-audit

Step 0 — /local-review (qualitative)

  • Skipped with justification — single Bicep resource addition using Azure's well-known built-in role GUID; doc-comment update on the surrounding RBAC block. No architectural decisions to surface.

Step 1 — Mechanical checklist

  • Every new *Options property has at least one real getter call in src/ — N/A (no code change)
  • Sibling-diffed against the closest existing implementation — the new sqlRoleAssignments resource sits alongside the 5 existing Microsoft.Authorization/roleAssignments resources; gating differs (Cosmos is Phase 1) and that's documented in the comment block
  • No bare catch { } — N/A
  • New ISourceScraper? — N/A
  • Tests assert behavior, not just structure — N/A (Bicep change; live-deploy re-validation covers it)
  • Build is zero-warning — confirmed (dotnet build unaffected; az bicep build clean)
  • git log -1 --format='%an <%ae>' shows personal noreply, not work email

Caught on the first --ensure-cosmos-containers smoke-test after the
Phase 1 deploy: Cosmos NoSQL containers need a SEPARATE data-plane
role assignment (sqlRoleAssignments) on top of the ARM-level RBAC.
Without it, every read/write fails with:

  Forbidden (403); Substatus: 5301; Reason: Request blocked by Auth ...
  principal does not have required RBAC permissions to perform action
  [Microsoft.DocumentDB/databaseAccounts/readMetadata] on resource [/]

The original Bicep author flagged this gap explicitly in the
developer-RBAC comment block as 'data-plane; assigned via az SQL
role-assignment, not RBAC role-assignment - out of scope here'. Time
to close it.

Adds:
  resource cosmosDataContributor
    'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2024-08-15'

Granting role 00000000-0000-0000-0000-000000000002 (Cosmos DB Built-in
Data Contributor) scoped to the Cosmos account root. Gates on
!empty(developerObjectId) only, NOT on deployPhase2 — Cosmos itself
is Phase 1, and read/write is needed to validate the deploy via
--ensure-cosmos-containers.

The developer-RBAC comment block is updated: the 'out of scope here'
note for the Cosmos role is removed, replaced with a description of
how Cosmos data-plane uses a SEPARATE Bicep namespace from the
standard Microsoft.Authorization/roleAssignments used by the other
RBAC entries.

Idempotent re-deploy against the existing Phase 1 account: only the
new role assignment is added; everything else is no-op. After this
PR lands, future Phase 1 deploys will not need the manual
'az cosmosdb sql role assignment create' workaround.

Pre-push self-audit: 7-item mechanical (all pass). /local-review
skipped — single Bicep resource addition with a doc-comment update;
the role definition GUID is Azure's well-known built-in.
@jkeeley2073 jkeeley2073 added the claude-code Generated with Claude Code label May 3, 2026
@jkeeley2073 jkeeley2073 merged commit 81eadab into main May 3, 2026
6 checks passed
@jkeeley2073 jkeeley2073 deleted the Dev-CosmosDataPlaneRbac branch May 3, 2026 22:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-code Generated with Claude Code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant