Skip to main content

Azure Infrastructure Requirements

Everything an Azure platform/governance team needs to review and prepare before a NimBus deployment runs — what gets provisioned, which resource providers must be registered, and exactly which RBAC the deploying identity, the provisioned apps, and operators need. The how-to lives in the Deployment Guide; this page is the reference.

Resources provisioned​

One resource group holds everything for a {solutionId} + {environment} pair. Bicep sources: deploy/bicep/deploy.core.bicep and deploy/bicep/deploy.webapp.bicep.

ResourceName conventionDefault SKU / configurationPurpose
Service Bus namespacesb-{solutionId}-{environment} (override: --service-bus-namespace-name)Standard (topics are required; the Basic tier has no topics). Premium (1 messaging unit by default) with --network-mode privateMessaging backbone — one topic per endpoint plus the Resolver topic
Application Insightsai-{solutionId}-{environment}-global-tracelogkind: web componentTelemetry; the WebApp queries traces with its managed identity (Reader on the component)
Cosmos DB account (default storage provider)cosmos-{solutionId}-{environment}Standard offer (provisioned throughput), Session consistency, single region; database MessageDatabase with containers messages (partition /eventId, TTL 90 days) and audits (TTL 1 year). Per-endpoint containers are created at runtime by the apps (see ADR-008)Message store + audit trail
Azure SQL server + database (only --storage-provider sqlserver --sql-mode provision)sql-{solutionId}-{environment} / MessageDatabaseS0 (allowed: Basic/S0/S1/S2), TLS ≥ 1.2, public network access enabled with the AllowAllWindowsAzureIps (0.0.0.0) firewall ruleMessage store alternative. The open Azure-services rule admits every Azure tenant; --network-mode private replaces it with a private endpoint (Private networking)
Storage accountst{solutionId}{environment}funcStorageV2, Standard_LRS, HTTPS-only; blob container app-package-resolver added on Flex ConsumptionFunctions host storage + Flex deployment package
App Service Plan (core)asp-{solutionId}-{environment}-coreFC1 Flex Consumption (Linux) by default, or EP1 Elastic Premium (Windows) via --resolver-planHosts the resolver Function App
App Service Plan (management)asp-{solutionId}-{environment}-managementB1 for dev/development, S1 otherwise (override via --management-plan-sku)Hosts the management WebApp
Function Appfunc-{solutionId}-{environment}-resolver.NET 10 isolated worker, FTPS-only, system-assigned managed identityThe NimBus Resolver
Web Appwebapp-{solutionId}-{environment}-managementHTTPS-only, FTPS-only, run-from-package, Always On (Basic+), system-assigned managed identityManagement UI
Role assignments(deterministic GUIDs)See Role assignments created by the deploymentManaged-identity data-plane access
Private endpoints (only --network-mode private)pe-{resource}-{groupId}5–8 endpoints in your subnet: Service Bus, store (none for an external SQL server), storage (blob, queue, table, plus file on Elastic Premium), Resolver and WebApp sites. Tagged nimbus-deployment={solutionId}-{environment}Private access to every NimBus endpoint
Private DNS zones (only --private-dns create)privatelink.*One per service type, linked to your VNet with fallback to internetResolve the private endpoints

With --network-mode private the Cosmos DB account, SQL server, storage account, Service Bus namespace and both apps are created with public network access disabled, and both apps are VNet-integrated. Subnets, DNS, egress and runners: Private networking.

Legacy names: --resource-name-postfix appends -{postfix} to the Service Bus, Cosmos DB, SQL server, Function App and Web App names only, and --func-storage-account-name points the Resolver at an existing storage account (details).

Naming constraint: the storage account name st{solutionId}{environment}func must be ≤ 24 lowercase alphanumeric characters — keep solutionId + environment within 17 characters combined.

Resource provider registrations​

The deployment uses these resource providers:

ProviderUsed forWhen
Microsoft.ServiceBusNamespaceAlways
Microsoft.WebPlans, Function App, Web AppAlways
Microsoft.StorageFunctions storageAlways
Microsoft.InsightsApplication InsightsAlways
Microsoft.DocumentDBCosmos DB--storage-provider cosmos (default)
Microsoft.SqlAzure SQL--storage-provider sqlserver --sql-mode provision
Microsoft.EventGridOptional storage-hook webhooksOnly if you use Event Grid storage hooks — nothing in the Bicep deploys Event Grid resources
Microsoft.NetworkPrivate endpoints, private DNS zones--network-mode private
Microsoft.AppFlex Consumption subnet delegation--network-mode private with the Flex Consumption Resolver

ARM registers a provider automatically on first use only when the deploying identity holds the subscription-scoped .../register/action permission (included in Contributor/Owner at subscription scope). A resource-group-scoped pipeline identity cannot register providers, so on a fresh subscription have an administrator pre-register once:

for ns in Microsoft.ServiceBus Microsoft.Web Microsoft.Storage Microsoft.Insights Microsoft.DocumentDB Microsoft.EventGrid; do
az provider register --namespace $ns
done

nb infra apply attempts to register Microsoft.EventGrid itself; when the identity lacks permission it prints a warning and continues (it never blocks the deployment).

Role assignments created by the deployment​

For governance review — the Bicep grants the two system-assigned managed identities these roles:

RoleRole IDScopeGranted toWhen
Azure Service Bus Data Owner090c5cfd-751d-490a-894a-3ce6f1109419Service Bus namespaceResolver + WebApp identitiesAlways
Cosmos DB Built-in Data Contributor (Cosmos data-plane sqlRoleAssignments)00000000-0000-0000-0000-000000000002Cosmos accountResolver + WebApp identitiesCosmos provider
Cosmos DB Operator (Azure control plane; account keys remain inaccessible)230815da-be43-4aae-9cb4-875f7bd000aaMessageDatabaseWebApp identityCosmos provider; required by Topology → Storage container cleanup
Storage Blob Data Ownerb7e6dc6d-f1e8-4753-8033-0f276bb0955bFunctions storage accountResolver identityFlex Consumption plan (identity-based host storage + deployment package)
Readeracdd72a7-3385-48ef-bd42-f606fba81ae7Application Insights componentWebApp identityWhen appInsightsAppId is set (always through nb); the event logs endpoint queries Application Insights with Microsoft Entra (details)

No secrets are distributed to the apps on the Cosmos path — everything is managed identity. The provisioned-SQL path passes a SQL connection string as app settings instead.

RBAC for the deploying identity (pipeline or user)​

The identity running nb infra apply / the pipelines needs, on the target resource group:

  • Owner — simplest, or
  • least privilege: Contributor + Role Based Access Control Administrator (f58310d9-a9f6-439a-9e8d-f62e7b41a168).

Why Contributor alone is not enough: the table above is written as Microsoft.Authorization/roleAssignments, and Contributor's NotActions explicitly exclude Microsoft.Authorization/*/Write. The Cosmos entries are the exception — they are Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments resources and are covered by Contributor.

Hardening the RBAC Administrator grant with an ABAC condition restricting assignable roles to the four IDs the deployment needs. A condition written before the WebApp's Reader grant lists only the first three; add Reader, or the WebApp deployment fails when it assigns Reader:

az role assignment create \
--role "Role Based Access Control Administrator" \
--assignee-object-id <SP_OBJECT_ID> --assignee-principal-type ServicePrincipal \
--scope /subscriptions/<SUB_ID>/resourceGroups/<RG> \
--condition-version 2.0 \
--condition "((!(ActionMatches{'Microsoft.Authorization/roleAssignments/write'})) OR (@Request[Microsoft.Authorization/roleAssignments:RoleDefinitionId] ForAnyOfAnyValues:GuidEquals {090c5cfd-751d-490a-894a-3ce6f1109419, b7e6dc6d-f1e8-4753-8033-0f276bb0955b, 230815da-be43-4aae-9cb4-875f7bd000aa, acdd72a7-3385-48ef-bd42-f606fba81ae7}))"

Everything else the CLI does is covered by resource-group Contributor:

  • az deployment group create for both Bicep templates
  • nb topology apply reads the Service Bus root connection string (listKeys) to create topics/subscriptions/rules
  • nb deploy apps zip-deploys the Function App and Web App

Subscription-scope permissions are not required, provided the resource providers are pre-registered (previous section).

Private mode additionally needs rights outside the resource group: joining your subnets (Microsoft.Network/virtualNetworks/subnets/join/action, for example Network Contributor on the VNet) and, with --private-dns existing, Private DNS Zone Contributor on the hub DNS resource group. See Private networking › Permissions.

Operator and developer access (after deployment)​

WhoNeedsWhy
Operators using nb ops commands (endpoint, container) or local WebApp with Entra authAzure Service Bus Data Owner on the namespace + Cosmos DB Built-in Data Contributor on the accountData-plane access via DefaultAzureCredential — same heuristic the apps use (see docs/cli.md)
CI identity re-running deploymentsSame as deploying identityRe-runs are idempotent; existing plans/regions are pinned

Tooling and platform constraints​

RequirementDetail
Azure CLI ≥ 2.60.0Hard minimum for Flex Consumption zip deploys (Microsoft-documented); nb deploy apps refuses to deploy to a Flex plan with an older CLI. ≥ 2.70 recommended; .bicepparam files need ≥ 2.53
Bicep CLI ≥ 0.35.1Required on every deployment path because the templates use @secure() outputs. Check with az bicep version and update with az bicep upgrade (Microsoft documentation)
.NET 10 SDK + Node.js 22Wherever nb deploy apps builds the apps (the WebApp SPA builds during dotnet publish); pipeline agents need outbound access to nuget.org and the npm registry
Flex Consumption region availabilityNot available in every region — check with az functionapp list-flexconsumption-locations
Region consistencyApps must live in the same region as their plans; the CLI pins existing resources to their current region automatically
Plan-type immutabilityElasticPremium (Windows) ↔ FlexConsumption (Linux) cannot be converted in place — delete the resolver Function App and the core plan to switch
Azure SQL DNS cooldownA deleted SQL server's name is held globally for 24–72 h; use --sql-server-name to redeploy sooner
Service Bus tierStandard minimum (topics). Premium for private networking (private endpoints are Premium-only) or predictable throughput — the topology is tier-agnostic. Azure cannot convert Standard to Premium in place; nb keeps an existing Premium namespace Premium