Skip to main content

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 .env or .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:

  1. Client Secret (Local Development)

    useClientSecret: true
    clientId: from .env
    clientSecret: from .env
    tenantId: from .env
  2. Managed Identity Only (Azure IMDS)

    useManagedIdentity: true
    // Gets token from: http://169.254.169.254/metadata/identity/oauth2/token
  3. 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 endpoint
  • IDENTITY_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:

  1. User selects environment in UI
  2. Frontend sends targetEnvironment name
  3. Backend looks up URL in data/environments.json
  4. Backend creates client with that specific URL
  5. 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.