Skip to content

Latest commit

 

History

History
846 lines (688 loc) · 24.8 KB

File metadata and controls

846 lines (688 loc) · 24.8 KB

Parameter Guide for AI Landing Zone Deployment

This guide focuses on configuration concepts for the AI Landing Zone.

Important: This repository deploys using Bicep parameter files, not infra/main.parameters.json.

  • Primary parameters file: infra/main.bicepparam
  • AI Landing Zone submodule parameters file (if you deploy it directly): submodules/ai-landing-zone/main.parameters.json

Fabric options in this repo are configured in infra/main.bicepparam via:

  • fabricCapacityPreset (create | byo | none) — driven by the fabricCapacityMode env variable
  • fabricWorkspacePreset (create | byo | none) — mirrors fabricCapacityPreset by default
  • BYO inputs: fabricCapacityResourceId (env), FABRIC_WORKSPACE_ID (env), FABRIC_WORKSPACE_NAME (env)

Deployment flow: This repo deploys the AI Landing Zone submodule from submodules/ai-landing-zone/main.bicep during the preprovision hook. The single source of truth for parameters is infra/main.bicepparam.

Fabric Configuration

Modes: create, byo, none

Mode Description
create Provisions a new Fabric capacity (Bicep) and workspace (postprovision script)
byo Reuses an existing Fabric capacity and workspace — no new resources created
none Disables all Fabric automation; OneLake indexing will be skipped

Both capacity and workspace modes are controlled by the same fabricCapacityMode environment variable (they are tied together in infra/main.bicepparam).

Setting Mode via azd env

The recommended way to configure Fabric mode is with azd env set — these values are read directly by infra/main.bicepparam at provision time:

# Choose one:
azd env set fabricCapacityMode create   # create new capacity + workspace (default if not set)
azd env set fabricCapacityMode byo      # reuse existing capacity + workspace
azd env set fabricCapacityMode none     # disable all Fabric automation

Reusing Existing Fabric Resources (BYO)

When fabricCapacityMode is byo, supply the identifiers of your existing resources:

# ARM resource ID of the existing Fabric capacity
azd env set fabricCapacityResourceId "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Fabric/capacities/<capacity-name>"

# GUID of the existing Fabric workspace (from the workspace URL)
azd env set FABRIC_WORKSPACE_ID "<workspace-guid>"

# Display name of the existing workspace (optional, used for naming/UX)
azd env set FABRIC_WORKSPACE_NAME "<workspace-display-name>"

How to find the workspace GUID: Open the workspace in app.fabric.microsoft.com. The URL segment after /groups/ is the GUID (e.g., https://app.fabric.microsoft.com/groups/e9c7ed61-0cdc-4356-a239-9d49cc755fe0/...).

How to find the capacity resource ID: Azure Portal → Fabric capacity resource → PropertiesResource ID.

You can also set these directly in infra/main.bicepparam if you prefer source-controlled values:

// infra/main.bicepparam
var fabricCapacityPreset = 'byo'
param fabricCapacityResourceId = '/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Fabric/capacities/<name>'
param fabricWorkspaceId = '<workspace-guid>'
param fabricWorkspaceName = '<workspace-display-name>'

Note: Values set via azd env set take precedence over hardcoded bicepparam values because readEnvironmentVariable(...) is evaluated at deploy time.

Creating New Fabric Resources

When fabricCapacityMode is create, you must provide at least one admin principal:

// infra/main.bicepparam
param fabricCapacityAdmins = ['user@contoso.com']
param fabricCapacitySku = 'F2'  // adjust SKU as needed

Permission requirement: The identity running azd must have the Fabric Administrator role (or Power BI tenant admin) to call the workspace admin APIs used during postprovision.


Observability — Bring Your Own Log Analytics Workspace

By default the wrapper sets deployLogAnalytics = false, so the AI Landing Zone does not create a new Log Analytics workspace and Application Insights is not provisioned. If you already have a centralized Log Analytics workspace (for example one shared across the platform), you can wire the deployed Foundry application and the wrapper-managed PostgreSQL Flexible Server to it.

How it works

When you set existingLogAnalyticsWorkspaceResourceId:

  1. An Application Insights component is created in the deployment resource group and linked to your existing workspace via WorkspaceResourceIdonly when deployAppInsights = true and deployLogAnalytics = false (the wrapper defaults). Its name follows the same appInsightsName convention (appi-<resourceToken>).
  2. PostgreSQL Flexible Server diagnostic settings (all logs + AllMetrics) are routed to your workspace (only when PostgreSQL is deployed by the wrapper).
  3. The connection string and instrumentation key are exposed as deployment outputs (when the Application Insights component is created) so post-provision automation (or your application configuration) can pick them up.

Note: This is wrapper-side wiring. The upstream AI Landing Zone submodule does not natively support a BYO Log Analytics workspace, so leave deployLogAnalytics = false and deployAppInsights = true (the defaults) when using BYO so the LAZ does not create its own workspace + Application Insights pair.

Setting it via azd env

azd env set EXISTING_LOG_ANALYTICS_WORKSPACE_RESOURCE_ID "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.OperationalInsights/workspaces/<workspace-name>"

Or set it directly in infra/main.bicepparam:

param existingLogAnalyticsWorkspaceResourceId = '/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.OperationalInsights/workspaces/<workspace-name>'

Outputs

Output Description
existingLogAnalyticsWorkspaceResourceIdOut Echo of the supplied workspace resource ID
byoApplicationInsightsResourceId Resource ID of the App Insights component created against the BYO workspace
byoApplicationInsightsName Name of the App Insights component
byoApplicationInsightsConnectionString Connection string for app instrumentation
byoApplicationInsightsInstrumentationKey Instrumentation key for legacy SDKs

Sensitive outputs: The connection string and instrumentation key are bootstrap credentials for sending telemetry to your Application Insights resource. They are emitted as deployment outputs so post-provision scripts and azd env can wire them into application configuration. Anyone with read access to the deployment history (subscription/RG Microsoft.Resources/deployments/read) can retrieve these values — keep that access scoped appropriately.

Permissions

The identity running the deployment needs permission to attach diagnostic settings to the workspace and to create the Application Insights component:

  • Microsoft.Insights/diagnosticSettings/write on the BYO Log Analytics workspace (or its resource group). The built-in Log Analytics Contributor role on the workspace (or its RG) covers this — there is no need to grant subscription-wide rights.
  • Microsoft.Insights/components/write on the deployment resource group (covered by Contributor on the deployment RG, which the deployment identity already needs to provision the rest of the stack).
  • The PostgreSQL Flexible Server that emits diagnostics is wrapper-managed in the deployment RG, so no additional cross-resource permissions are required.

Table of Contents

  1. Basic Parameters
  2. Deployment Toggles
  3. Network Configuration
  4. Microsoft Foundry Configuration
  5. Individual Service Configuration
  6. Common Customization Examples

Basic Parameters

location

Type: string
Default: ${AZURE_LOCATION=eastus2}
Description: Azure region where all resources will be deployed.

"location": {
  "value": "${AZURE_LOCATION=westus2}"
}

Set via azd:

azd env set AZURE_LOCATION westus2

Available regions (check AI service availability):

  • eastus, eastus2, westus, westus2, centralus
  • northeurope, westeurope
  • australiaeast, southeastasia

baseName

Type: string
Default: ${AZURE_ENV_NAME}
Description: Base name used to generate resource names.

"baseName": {
  "value": "${AZURE_ENV_NAME}"
}

Set via azd:

azd env new my-ai-app  # baseName becomes "my-ai-app"

Results in resource names like:

  • rg-my-ai-app
  • kv-my-ai-app-xyz
  • acr-my-ai-app-xyz

tags

Type: object
Default: Environment-specific tags
Description: Tags applied to all resources.

"tags": {
  "value": {
    "azd-env-name": "${AZURE_ENV_NAME}",
    "environment": "production",
    "project": "ai-application",
    "cost-center": "engineering",
    "owner": "ai-team"
  }
}

Deployment Toggles

Each toggle controls whether a service is created. Set to true to deploy, false to skip.

Core Infrastructure (Recommended: All True)

"deployToggles": {
  "value": {
    "logAnalytics": true,        // Log Analytics Workspace
    "appInsights": true,         // Application Insights
    "virtualNetwork": true       // Virtual Network
  }
}

Data Services

"cosmosDb": true,               // Azure Cosmos DB
"keyVault": true,               // Azure Key Vault
"searchService": true,          // Azure AI Search
"storageAccount": true          // Storage Account

When to disable:

  • Using existing Cosmos DB: set cosmosDb: false + provide resourceIds.cosmosDbResourceId
  • Using existing Key Vault: set keyVault: false + provide resourceIds.keyVaultResourceId

Container Platform

"containerEnv": true,           // Container Apps Environment
"containerRegistry": true,      // Azure Container Registry
"containerApps": false          // Individual Container Apps

Note: containerApps: false means no apps are deployed, but the environment is ready.

Optional Services (Usually False)

"appConfig": false,             // Azure App Configuration
"apiManagement": false,         // API Management
"applicationGateway": false,    // Application Gateway
"applicationGatewayPublicIp": false,
"firewall": false,              // Azure Firewall
"buildVm": false,               // Linux build VM
"jumpVm": false,                // Windows jump box
"bastionHost": false,           // Azure Bastion
"groundingWithBingSearch": false, // Bing Search Service
"wafPolicy": false              // Web Application Firewall

When to enable:

  • apiManagement: true - For API gateway and rate limiting
  • applicationGateway: true - For load balancing and SSL termination
  • firewall: true - For outbound traffic filtering
  • bastionHost: true - For secure VM access
  • buildVm: true - For CI/CD build agents
  • jumpVm: true - For Windows-based management

Log Analytics (Optional)

If you are using an existing Log Analytics workspace, set the resource ID in infra/main.bicepparam:

param logAnalyticsWorkspaceResourceId = '/subscriptions/<subId>/resourceGroups/<rg>/providers/Microsoft.OperationalInsights/workspaces/<name>'

Network Security Groups

"agentNsg": true,               // NSG for agent/workload subnet
"peNsg": true,                  // NSG for private endpoints subnet
"acaEnvironmentNsg": true,      // NSG for container apps subnet
"applicationGatewayNsg": false, // NSG for App Gateway subnet
"apiManagementNsg": false,      // NSG for APIM subnet
"jumpboxNsg": false,            // NSG for jumpbox subnet
"devopsBuildAgentsNsg": false,  // NSG for build agents subnet
"bastionNsg": false             // NSG for Bastion subnet

Rule: Enable NSG for any subnet you're using.


Network Configuration

vNetDefinition

Required when: deployToggles.virtualNetwork: true

"vNetDefinition": {
  "value": {
    "name": "vnet-ai-landing-zone",
    "addressPrefixes": [
      "10.0.0.0/16"
    ],
    "subnets": [
      {
        "name": "snet-agents",
        "addressPrefix": "10.0.1.0/24",
        "role": "agents"
      },
      {
        "name": "snet-private-endpoints",
        "addressPrefix": "10.0.2.0/24",
        "role": "private-endpoints"
      },
      {
        "name": "snet-container-apps",
        "addressPrefix": "10.0.3.0/23",
        "role": "container-apps-environment"
      }
    ]
  }
}

Subnet Roles

Role Required Purpose Minimum Size
agents ✅ Yes Workload VMs, compute /26 (64 IPs)
private-endpoints ✅ Yes Private endpoint NICs /26 (64 IPs)
container-apps-environment If containerEnv: true Container Apps /23 (512 IPs)
application-gateway If applicationGateway: true App Gateway /27 (32 IPs)
api-management If apiManagement: true APIM /27 (32 IPs)
jumpbox If jumpVm: true Jump VM /28 (16 IPs)
bastion If bastionHost: true Azure Bastion /26 (64 IPs)
devops-build-agents If buildVm: true Build VMs /28 (16 IPs)

Example: Minimal Network

"addressPrefixes": ["10.0.0.0/16"],
"subnets": [
  {
    "name": "snet-agents",
    "addressPrefix": "10.0.1.0/26",
    "role": "agents"
  },
  {
    "name": "snet-private-endpoints",
    "addressPrefix": "10.0.2.0/26",
    "role": "private-endpoints"
  }
]

Example: Full Network with All Services

"addressPrefixes": ["10.0.0.0/16"],
"subnets": [
  {
    "name": "snet-agents",
    "addressPrefix": "10.0.1.0/24",
    "role": "agents"
  },
  {
    "name": "snet-private-endpoints",
    "addressPrefix": "10.0.2.0/24",
    "role": "private-endpoints"
  },
  {
    "name": "snet-container-apps",
    "addressPrefix": "10.0.3.0/23",
    "role": "container-apps-environment"
  },
  {
    "name": "snet-app-gateway",
    "addressPrefix": "10.0.5.0/27",
    "role": "application-gateway"
  },
  {
    "name": "snet-apim",
    "addressPrefix": "10.0.6.0/27",
    "role": "api-management"
  },
  {
    "name": "snet-bastion",
    "addressPrefix": "10.0.7.0/26",
    "role": "bastion"
  },
  {
    "name": "snet-jumpbox",
    "addressPrefix": "10.0.8.0/28",
    "role": "jumpbox"
  },
  {
    "name": "snet-build-agents",
    "addressPrefix": "10.0.9.0/28",
    "role": "devops-build-agents"
  }
]

Microsoft Foundry Configuration

aiFoundryDefinition

Controls Microsoft Foundry account/project and model deployments.

"aiFoundryDefinition": {
  "value": {
    "includeAssociatedResources": true,
    "aiFoundryConfiguration": {
      "disableLocalAuth": false
    },
    "aiModelDeployments": [...]
  }
}

includeAssociatedResources

Type: boolean
Default: true
Description: Create dedicated AI Search, Cosmos DB, Key Vault, and Storage for Microsoft Foundry.

Set to false if you want to use shared resources.

disableLocalAuth

Type: boolean
Default: false
Description: Require Entra ID authentication (no API keys).

Set to true for maximum security in production.

AI Model Deployments

Array of OpenAI models to deploy.

GPT-4o Example

{
  "name": "gpt-4o",
  "model": {
    "format": "OpenAI",
    "name": "gpt-4o",
    "version": "2024-08-06"
  },
  "sku": {
    "name": "Standard",
    "capacity": 10
  }
}

All Available Models

Chat Models
// GPT-4o (latest)
{
  "name": "gpt-4o",
  "model": {"format": "OpenAI", "name": "gpt-4o", "version": "2024-08-06"},
  "sku": {"name": "Standard", "capacity": 10}
}

// GPT-4o mini (cost-effective)
{
  "name": "gpt-4o-mini",
  "model": {"format": "OpenAI", "name": "gpt-4o-mini", "version": "2024-07-18"},
  "sku": {"name": "Standard", "capacity": 10}
}

// GPT-4 Turbo
{
  "name": "gpt-4-turbo",
  "model": {"format": "OpenAI", "name": "gpt-4", "version": "turbo-2024-04-09"},
  "sku": {"name": "Standard", "capacity": 10}
}

// GPT-3.5 Turbo
{
  "name": "gpt-35-turbo",
  "model": {"format": "OpenAI", "name": "gpt-35-turbo", "version": "0125"},
  "sku": {"name": "Standard", "capacity": 10}
}
Embedding Models
// text-embedding-3-small (recommended)
{
  "name": "text-embedding-3-small",
  "model": {"format": "OpenAI", "name": "text-embedding-3-small", "version": "1"},
  "sku": {"name": "Standard", "capacity": 10}
}

// text-embedding-3-large (higher dimensions)
{
  "name": "text-embedding-3-large",
  "model": {"format": "OpenAI", "name": "text-embedding-3-large", "version": "1"},
  "sku": {"name": "Standard", "capacity": 10}
}

// text-embedding-ada-002
{
  "name": "text-embedding-ada-002",
  "model": {"format": "OpenAI", "name": "text-embedding-ada-002", "version": "2"},
  "sku": {"name": "Standard", "capacity": 10}
}
Image Generation
// DALL-E 3
{
  "name": "dall-e-3",
  "model": {"format": "OpenAI", "name": "dall-e-3", "version": "3.0"},
  "sku": {"name": "Standard", "capacity": 1}
}

Capacity (Tokens Per Minute)

Capacity TPM (K) Use Case
1 1,000 Development/testing
10 10,000 Small production
50 50,000 Medium production
100 100,000 Large production
240 240,000 Enterprise (max for Standard)

Check quota:

az cognitiveservices account list-usage \
  --name <account-name> \
  --resource-group <rg-name>

Individual Service Configuration

PostgreSQL Flexible Server (Repo Wrapper)

Use these in infra/main.bicepparam when deploying via this repo. postgreSqlNetworkIsolation defaults to networkIsolation.

param deployPostgreSql = true
param postgreSqlNetworkIsolation = networkIsolation
param postgreSqlAllowAzureServices = false
param postgreSqlMirrorConnectionMode = 'fabricUser'
param postgreSqlAuthConfig = {
  activeDirectoryAuth: 'Enabled'
  passwordAuth: 'Enabled'
}

When postgreSqlNetworkIsolation is false, PostgreSQL uses public access and does not create private endpoints or private DNS resources.

postgreSqlAllowAzureServices controls whether deployment also creates the PostgreSQL firewall rule that allows Azure services to connect (0.0.0.0 to 0.0.0.0). This is the declarative equivalent of the Azure portal Allow public access from any Azure service within Azure to this server setting.

Recommended combinations:

  • Public/manual Fabric path: postgreSqlNetworkIsolation = false and postgreSqlAllowAzureServices = true
  • Private/gateway path: postgreSqlNetworkIsolation = true and postgreSqlAllowAzureServices = false

postgreSqlAuthConfig should remain set to both authentication modes enabled if you plan to configure Fabric mirroring after deployment. This ensures the server is created with password authentication available for the fabric_user connection instead of relying on a later hook to change the auth mode.

postgreSqlMirrorConnectionMode controls which credential the manual Fabric PostgreSQL connection should use after deployment:

  • fabricUser uses the dedicated least-privilege mirroring user and postgres-fabric-user-password. This is the production-oriented default.
  • admin uses the PostgreSQL admin login and postgres-admin-password. This is intended for demo automation scenarios where you want to avoid creating a separate mirroring user.

Storage Account

"storageAccountDefinition": {
  "value": {
    "name": "stmyaiapp",
    "sku": "Standard_LRS",
    "allowBlobPublicAccess": false
  }
}

Key Vault

"keyVaultDefinition": {
  "value": {
    "name": "kv-myaiapp",
    "enableRbacAuthorization": true,
    "enablePurgeProtection": true,
    "softDeleteRetentionInDays": 90
  }
}

Cosmos DB

"cosmosDbDefinition": {
  "value": {
    "name": "cosmos-myaiapp",
    "sqlDatabases": [
      {
        "name": "chatdb",
        "containers": [
          {
            "name": "conversations",
            "partitionKeyPath": "/userId"
          }
        ]
      }
    ]
  }
}

AI Search

"aiSearchDefinition": {
  "value": {
    "name": "search-myaiapp",
    "sku": "standard",
    "semanticSearch": "free"
  }
}

Common Customization Examples

1. Development Environment (Minimal Cost)

{
  "location": {"value": "eastus2"},
  "baseName": {"value": "dev-ai"},
  "deployToggles": {
    "value": {
      "logAnalytics": true,
      "appInsights": true,
      "containerEnv": true,
      "containerRegistry": true,
      "cosmosDb": true,
      "keyVault": true,
      "storageAccount": true,
      "searchService": true,
      "virtualNetwork": true,
      "agentNsg": true,
      "peNsg": true,
      "acaEnvironmentNsg": true,
      // All others false
    }
  },
  "aiFoundryDefinition": {
    "value": {
      "includeAssociatedResources": true,
      "aiModelDeployments": [
        {
          "name": "gpt-4o-mini",
          "model": {
            "format": "OpenAI",
            "name": "gpt-4o-mini",
            "version": "2024-07-18"
          },
          "sku": {"name": "Standard", "capacity": 1}
        }
      ]
    }
  }
}

2. Production Environment (Full Security)

{
  "location": {"value": "eastus2"},
  "baseName": {"value": "prod-ai"},
  "deployToggles": {
    "value": {
      "logAnalytics": true,
      "appInsights": true,
      "containerEnv": true,
      "containerRegistry": true,
      "cosmosDb": true,
      "keyVault": true,
      "storageAccount": true,
      "searchService": true,
      "virtualNetwork": true,
      "apiManagement": true,
      "applicationGateway": true,
      "firewall": true,
      "bastionHost": true,
      "agentNsg": true,
      "peNsg": true,
      "acaEnvironmentNsg": true,
      "apiManagementNsg": true,
      "applicationGatewayNsg": true,
      "bastionNsg": true
    }
  },
  "aiFoundryDefinition": {
    "value": {
      "includeAssociatedResources": true,
      "aiFoundryConfiguration": {
        "disableLocalAuth": true
      },
      "aiModelDeployments": [
        {
          "name": "gpt-4o",
          "model": {
            "format": "OpenAI",
            "name": "gpt-4o",
            "version": "2024-08-06"
          },
          "sku": {"name": "Standard", "capacity": 100}
        },
        {
          "name": "text-embedding-3-large",
          "model": {
            "format": "OpenAI",
            "name": "text-embedding-3-large",
            "version": "1"
          },
          "sku": {"name": "Standard", "capacity": 50}
        }
      ]
    }
  }
}

3. Using Existing Resources

{
  "deployToggles": {
    "value": {
      "logAnalytics": false,    // Using existing
      "keyVault": false,        // Using existing
      "virtualNetwork": false,  // Using existing
      // ... other services true
    }
  },
  "resourceIds": {
    "value": {
      "logAnalyticsWorkspaceResourceId": "/subscriptions/.../Microsoft.OperationalInsights/workspaces/my-workspace",
      "keyVaultResourceId": "/subscriptions/.../Microsoft.KeyVault/vaults/my-keyvault",
      "virtualNetworkResourceId": "/subscriptions/.../Microsoft.Network/virtualNetworks/my-vnet"
    }
  }
}

4. Multi-Model AI Application

{
  "aiFoundryDefinition": {
    "value": {
      "includeAssociatedResources": true,
      "aiModelDeployments": [
        {
          "name": "gpt-4o",
          "model": {"format": "OpenAI", "name": "gpt-4o", "version": "2024-08-06"},
          "sku": {"name": "Standard", "capacity": 50}
        },
        {
          "name": "gpt-4o-mini",
          "model": {"format": "OpenAI", "name": "gpt-4o-mini", "version": "2024-07-18"},
          "sku": {"name": "Standard", "capacity": 10}
        },
        {
          "name": "text-embedding-3-small",
          "model": {"format": "OpenAI", "name": "text-embedding-3-small", "version": "1"},
          "sku": {"name": "Standard", "capacity": 20}
        },
        {
          "name": "dall-e-3",
          "model": {"format": "OpenAI", "name": "dall-e-3", "version": "3.0"},
          "sku": {"name": "Standard", "capacity": 1}
        }
      ]
    }
  }
}

Validation

Check Parameters Locally

# Validate JSON syntax
cat infra/main.parameters.json | jq .

# Validate Bicep compilation
cd infra
az bicep build --file main.bicep

Test Deployment (What-If)

azd provision --what-if

Dry Run

az deployment group what-if \
  --resource-group <rg-name> \
  --template-file infra/main.bicep \
  --parameters infra/main.parameters.json

Need Help?

  • Parameter errors: Check JSON syntax with jq
  • Deployment errors: Run with --debug flag
  • Quota errors: Check regional quotas with az vm list-usage
  • Network errors: Verify CIDR ranges don't overlap

📖 Deployment Guide: docs/deploymentguide.md