Azure Multi-Environment Deployment Guide
Overview
This document explains how the multi-environment feature works in Azure App Service and what's needed for successful deployment.
Architecture
Local Development
- Authentication: Client Secret (stored in
.envor.env.local) - Environment Config:
data/environments.json(loaded at runtime) - Environment Selection: User selects from dropdown in UI
Azure App Service
- Authentication: User-Assigned Managed Identity + Federated Credentials
- Environment Config:
data/environments.json(included in deployment package) - Environment Selection: User selects from dropdown in UI
- No Secrets Required: Managed identity handles authentication automatically
What Gets Deployed
The deploy-secretless.ps1 script packages these files:
deploy.zip
├── server.js # Entry point (sets AUTH_MODE=managed_identity)
├── package.json # Dependencies
├── backend/ # Backend code
│ ├── server.js
│ ├── dataverse-client.js # Handles 3 auth modes
│ ├── environment-manager.js # Reads data/environments.json
│ └── ... (all backend files)
├── data/ # ✅ NOW INCLUDED
│ └── environments.json # Multi-environment configuration
├── shared/ # Shared utilities
└── public/ # Frontend build (from src/frontend/dist)
Authentication Flow
DataverseClient Authentication Modes
The dataverse-client.js supports 3 authentication modes:
-
Client Secret (Local Development)
useClientSecret: true
clientId: from .env
clientSecret: from .env
tenantId: from .env -
Managed Identity Only (Azure IMDS)
useManagedIdentity: true
// Gets token from: http://169.254.169.254/metadata/identity/oauth2/token -
Managed Identity + Federated Credentials (Azure App Service - THIS IS WHAT WE USE)
useManagedIdentity: true
useFederatedCredential: true
// Two-step process:
// 1. Get Azure token from App Service managed identity endpoint
// 2. Exchange for Dataverse token using federated credentials
How Environment Selection Works
When user selects an environment from dropdown:
User selects "test-princess" in UI
↓
Frontend sends: { targetEnvironment: "test-princess", ... }
↓
Backend deployment-service.js:
- Reads data/environments.json
- Finds environment by name
- Creates dataverseConfig with URL override:
{
dataverseUrl: "https://org32dda8c3.crm4.dynamics.com",
useManagedIdentity: true,
useFederatedCredential: true
}
↓
DataverseClient:
- Uses provided dataverseUrl (test-princess)
- Authenticates via managed identity + FIC
- Gets token for THAT specific environment
↓
Deployment proceeds to selected environment
Prerequisites for Azure Deployment
1. Managed Identity Setup
The managed identity (service principal) must have application users in ALL environments:
# Run this for each environment
.\scripts\setup-dataverse-user.ps1 `
-DataverseUrl "https://orgXXXXXXXX.crm4.dynamics.com" `
-ServicePrincipalId "c834e8fa-acbd-4fa4-8a0d-d6c832d0f4ab" `
-SecurityRole "System Administrator"
Required Settings:
accessmode: 4 (Non-interactive)- Security Role: System Administrator (or appropriate role)
- User status: Enabled
2. Federated Identity Credentials
The app registration must have federated credentials configured for the App Service:
# This is set up by setup-secretless.ps1
az ad app federated-credential create `
--id <APP_OBJECT_ID> `
--parameters '{
"name": "app-mermaid-princess-fic",
"issuer": "https://login.microsoftonline.com/<TENANT_ID>/v2.0",
"subject": "api://AzureADTokenExchange",
"audiences": ["api://AzureADTokenExchange"]
}'
3. Azure App Service Configuration
Managed Identity:
identity: {
type: 'UserAssigned'
userAssignedIdentities: {
'${managedIdentity.id}': {}
}
}
Application Settings:
appSettings: [
{
name: 'NODE_ENV'
value: 'production'
}
// No DATAVERSE_URL needed! Comes from environments.json + user selection
]
Environment Variables (Auto-Set by App Service):
IDENTITY_ENDPOINT: Managed identity endpointIDENTITY_HEADER: Authentication header for managed identity
Key Concepts
Why No DATAVERSE_URL in App Settings?
Unlike single-environment deployments, multi-environment support means the target URL is dynamic based on user selection:
- User selects environment in UI
- Frontend sends
targetEnvironmentname - Backend looks up URL in
data/environments.json - Backend creates client with that specific URL
- Managed identity authenticates to THAT environment
Why Managed Identity Works for Multiple Environments?
The managed identity (service principal) is organization-wide, not environment-specific. As long as it has application users in each environment, it can authenticate to all of them.
Why Include environments.json in Deployment?
The file contains:
- Environment names
- Environment URLs
- Environment metadata (colors, owners, purposes)
- Deployment settings (resource naming patterns)
This allows the app to dynamically connect to any configured environment without code changes.