AI Services Hub
Azure Landing Zone Infrastructure

Terraform Reference

🤖
Auto-Generated Documentation
This page is automatically generated from Terraform source files. Run ./docs/generate-tf-docs.sh to update.

Complete reference documentation for all Terraform modules, variables, and outputs extracted directly from the source code.

Initial Setup

Network foundation: VNet, Bastion, Jumpbox, self-hosted runners.

AI Services Hub

AI platform: APIM, AI Foundry, tenants, key rotation, WAF.

Initial Setup (initial-setup/infra/)

Network foundation layer — VNet, Bastion, Jumpbox, and self-hosted GitHub runners. Deployed once per environment via initial-setup/infra/deploy-terraform.sh.

Root Module

-------------

Location: initial-setup/infra/

Variables

NameTypeDefaultDescription
app_env string required Application environment (dev, test, prod)
app_name string required Name of the application
common_tags map(string) required Common tags to apply to all resources
location string Canada Azure region for resources
resource_group_name string required Name of the resource group
subscription_id string required Azure subscription ID
tenant_id string required Azure tenant ID
use_oidc bool true Use OIDC for authentication
vnet_address_space string required Address space for the virtual network, it is created by platform team
vnet_name string required Name of the existing virtual network
vnet_resource_group_name string required Resource group name where the virtual network exists
client_id string required Azure client ID for the service principal
github_runners_aca_enabled bool false Enable GitHub self-hosted runners on Azure Container Apps
github_organization string required GitHub organization name (e.g., 'bcgov')
github_repository string required GitHub repository name (e.g., 'ai-hub-tracking')
github_runner_pat string required GitHub Personal Access Token with Administration:write permission for runner registration
github_runners_container_cpu string 1 CPU cores for each runner container
github_runners_container_memory string 2Gi Memory for each runner container (e.g., '4Gi')
github_runners_max_count number 4 Maximum number of concurrent runners
github_runners_log_analytics_workspace_creation_enabled bool true Whether the GitHub runners module should create a Log Analytics workspace
github_runners_log_analytics_workspace_id string null Existing Log Analytics workspace ID to use when workspace creation is disabled
dev_address_spaces list(string) [] Address space for the dev environment of the vnet peering
prod_address_spaces list(string) [] Address space for the prod environment of the vnet peering
test_address_spaces list(string) [] Address space for the test environment of the vnet peering
azure_proxy_image string required The image for the Azure Proxy container
app_service_sku_name_azure_proxy string P0v4 The SKU name for the azure proxy App Service plan.
enable_azure_proxy bool false Enable deployment of the Azure Proxy App Service
enable_bastion bool false Enable deployment of the Azure Bastion host
enable_jumpbox bool false Enable deployment of the Azure Jumpbox VM
log_analytics_retention_days number 30 Number of days to retain data in Log Analytics Workspace
log_analytics_sku string PerGB2018 SKU for Log Analytics Workspace

Outputs

NameDescription
jumpbox_vm_id ID of the jumpbox virtual machine
jumpbox_vm_name Name of the jumpbox virtual machine
jumpbox_admin_username Admin username for SSH access to jumpbox
jumpbox_auto_shutdown_time Auto-shutdown time (PST)
jumpbox_auto_start_schedule Auto-start schedule (PST)
bastion_resource_id Resource ID of Azure Bastion
bastion_fqdn FQDN of the Bastion service
github_runners_environment_name Name of the Container App Environment for GitHub runners
github_runners_job_name Name of the Container App Job running the GitHub runner
github_runners_label The label to use in workflow runs-on to target these runners
github_runners_acr_name Name of the Azure Container Registry for runner images
proxy_url URL of the Azure Proxy service
proxy_auth Authentication info for the Azure Proxy service

Resources Created

azure-proxy

Location: initial-setup/infra/modules/azure-proxy/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
app_env string required The deployment environment (e.g., dev, test, prod).
app_name string required The base name of the application. Used for naming Azure resources.
app_service_subnet_id string required The subnet ID for the App Service.
appinsights_connection_string string required The Application Insights connection string for monitoring.
appinsights_instrumentation_key string required The Application Insights instrumentation key.
common_tags map(string) {} A map of tags to apply to resources.
container_registry_url string https://ghcr.io The URL of the container registry to pull images from.
location string required The Azure region where resources will be created.
log_analytics_workspace_id string required The resource ID of the Log Analytics workspace for diagnostics.
repo_name string required The repository name, used for resource naming.
resource_group_name string required The name of the resource group in which to create resources.
azure_proxy_image string required The image for the Azure DB Proxy container
app_service_sku_name_azure_proxy string required The SKU name for the azure db proxy App Service plan.

Outputs

NameDescription
proxy_url The URL of the Azure Proxy App Service
proxy_auth The authentication string for the Azure Proxy

Resources Created

bastion

-----------------------------------------------------------------------------

Location: initial-setup/infra/modules/bastion/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
app_name string required Name of the application, used for resource naming
resource_group_name string required Name of the resource group
location string required Azure region for resources
bastion_subnet_id string required Subnet ID for Azure Bastion (must be named AzureBastionSubnet)
common_tags map(string) required Common tags to apply to all resources
bastion_sku string Basic SKU for Azure Bastion (Basic or Standard)

Outputs

NameDescription
bastion_resource_id Resource ID of the Azure Bastion host
bastion_fqdn FQDN of the Bastion host
public_ip_address Public IP address of the Bastion host

Resources Created

github-runners-aca

-----------------------------------------------------------------------------

Location: initial-setup/infra/modules/github-runners-aca/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
enabled bool true Enable or disable the GitHub runners module
postfix string required A postfix used to build default names for resources (e.g., 'ai-hub')
location string required Azure region where resources will be deployed
resource_group_name string required Name of the existing resource group
common_tags map(string) {} Common tags to apply to all resources
github_organization string required GitHub organization name (e.g., 'bcgov')
github_repository string required GitHub repository name (e.g., 'ai-hub-tracking')
github_runner_pat string required GitHub Personal Access Token with Administration:write permission for runner registration
vnet_id string required ID of the existing virtual network
container_app_subnet_id string required ID of the subnet for Container Apps (must be delegated to Microsoft.App/environments)
private_endpoint_subnet_id string required ID of the subnet for private endpoints (used for ACR)
container_cpu string 1 CPU cores for each runner container (e.g., 1, 2, 4)
container_memory string 2Gi Memory for each runner container (e.g., '4Gi')
max_runners number 4 Maximum number of concurrent runners
log_analytics_workspace_creation_enabled bool true Whether the AVM runner module should create a Log Analytics workspace
log_analytics_workspace_id string null Existing Log Analytics workspace ID to use when creation is disabled

Outputs

NameDescription
container_app_environment_name Name of the Container App Environment
container_app_environment_id Resource ID of the Container App Environment
container_app_job_name Name of the Container App Job running the GitHub runner
container_app_job_id Resource ID of the Container App Job
container_registry_name Name of the Azure Container Registry
container_registry_login_server Login server URL of the Azure Container Registry
runner_label The label to use in workflow runs-on to target these runners (use just 'self-hosted' for AVM-based runners)

jumpbox

-----------------------------------------------------------------------------

Location: initial-setup/infra/modules/jumpbox/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
app_name string required Name of the application, used for resource naming
resource_group_name string required Name of the resource group
location string required Azure region for resources
subnet_id string required Subnet ID for the jumpbox VM
common_tags map(string) required Common tags to apply to all resources
vm_size string Standard_B2als_v2 Size of the virtual machine (B2als_v2: 2 vCPU, 4 GB RAM - cost-effective for jumpbox)
os_disk_type string Standard_LRS Storage account type for the OS disk
os_disk_size_gb number 64 Size of the OS disk in GB

Outputs

NameDescription
vm_id ID of the jumpbox virtual machine
vm_name Name of the jumpbox virtual machine
private_ip_address Private IP address of the jumpbox VM
admin_username Admin username for SSH access
principal_id Principal ID of the VM's managed identity
ssh_public_key_id Resource ID of the SSH public key in Azure
ssh_private_key_path Local path to the SSH private key file
automation_account_id ID of the Azure Automation Account for VM scheduling
auto_shutdown_time Auto-shutdown time (PST)
auto_start_schedule Auto-start schedule

Resources Created

monitoring

Log Analytics Workspace

Location: initial-setup/infra/modules/monitoring/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
app_name string required Name of the application
common_tags map(string) required Common tags to apply to all resources
location string Canada Azure region for resources
log_analytics_retention_days number 30 Number of days to retain data in Log Analytics Workspace
log_analytics_sku string PerGB2018 SKU for Log Analytics Workspace

Outputs

NameDescription
appinsights_connection_string The Application Insights connection string.
appinsights_instrumentation_key The Application Insights instrumentation key.
log_analytics_workspace_id The resource ID of the Log Analytics workspace.
log_analytics_workspace_key The primary shared key for the Log Analytics workspace.
log_analytics_workspace_workspaceId The name of the Log Analytics workspace.

Resources Created

network

Location: initial-setup/infra/modules/network/

Files (5)
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
apps_service_subnet_name string app-service-subnet Name of the subnet for App Services
common_tags map(string) required Common tags to apply to all resources
container_instance_subnet_name string container-instance-subnet Name of the subnet for container instances
container_apps_subnet_name string container-apps-subnet Name of the subnet for Container Apps
location string Canada Azure region for resources
private_endpoint_subnet_name string privateendpoints-subnet Name of the subnet for private endpoints
resource_group_name string required Name of the resource group
vnet_address_space string required Address space for the virtual network, it is created by platform team
vnet_name string required Name of the existing virtual network
vnet_resource_group_name string required Resource group name where the virtual network exists
web_subnet_name string web-subnet Name of the web subnet for APIM deployment
apim_subnet_name string apim-subnet Name of the subnet for API Management
jumpbox_subnet_name string jumpbox-subnet Name of the subnet for Jumpbox VM
bastion_subnet_name string AzureBastionSubnet Name of the subnet for Azure Bastion (must be AzureBastionSubnet)
dev_address_spaces list(string) [] Address space for the dev environment of the vnet peering
prod_address_spaces list(string) [] Address space for the prod environment of the vnet peering
test_address_spaces list(string) [] Address space for the test environment of the vnet peering

Outputs

NameDescription
container_instance_subnet_id The subnet ID for the container instance.
app_service_subnet_id The subnet ID for the App Service.
private_endpoint_subnet_id The subnet ID for private endpoints.
container_apps_subnet_id The subnet ID for Container Apps Environment.
apim_subnet_id The subnet ID for API Management.
jumpbox_subnet_id The subnet ID for the Jumpbox VM.
bastion_subnet_id The subnet ID for Azure Bastion.
dns_servers The DNS servers for the virtual network.
vnet_id ID of the virtual network
vnet_name Name of the virtual network

Resources Created

AI Services Hub (infra-ai-hub/)

Multi-tenant AI platform deployed via 5 isolated Terraform stacks with parallel execution. See ADR-013 for architecture rationale.

Stacks

Each stack has its own state file and backend configuration. Deployed in dependency order: shared → tenant (parallel) → foundry + apim + tenant-user-mgmt (parallel).

shared

Location: infra-ai-hub/stacks/shared/

Files (7)
  • backend.tf
  • locals.tf
  • main.tf
  • monitoring.tf
  • outputs.tf
  • providers.tf
  • variables.tf

Variables

NameTypeDefaultDescription
app_env string required Application environment
app_name string required Application name prefix
location string required Azure region
resource_group_name string required Shared resource group name
common_tags map(string) {} Common tags
subscription_id string required Azure subscription ID
tenant_id string required Azure tenant ID
client_id string required Azure client ID
use_oidc bool true Use OIDC
vnet_name string required Landing zone VNet name
vnet_resource_group_name string required Landing zone VNet resource group
source_vnet_address_space string required Source VNet address space
subnet_allocation map(map(string)) required Explicit subnet allocation map. Outer key = address space CIDR, inner key = subnet name, inner value = full subnet CIDR.
external_peered_projects map(object({ {} Map of external project names to their peered VNet config for direct APIM access (bypasses App Gateway). Key = project name, value = { cidrs = [...], priority = 4xx }.
shared_config any required Shared environment config
defender_enabled bool false Enable Defender for Cloud plans
defender_resource_types map(object({ {} Defender for Cloud resource types and subplans
backend_resource_group string required Backend resource group (unused by shared stack logic, accepted for command consistency)
backend_storage_account string required Backend storage account (unused by shared stack logic, accepted for command consistency)
backend_container_name string tfstate Backend container name (unused by shared stack logic, accepted for command consistency)
monitoring_webhook_url string required Teams Power Automate webhook URL for hub alert notifications. Optional — provide this and/or alert_emails in shared_config.monitoring. Store in sensitive tfvars, never in source-controlled params.

Outputs

NameDescription
resource_group_name No description
resource_group_id No description
private_endpoint_subnet_id No description
private_endpoint_subnet_cidr No description
private_endpoint_subnet_cidrs Sorted list of all PE subnet CIDRs in the pool (covers primary + overflow PE subnets)
private_endpoint_subnet_ids_by_key Map of PE pool key to subnet resource ID
private_endpoint_subnet_cidrs_by_key Map of PE pool key to CIDR string
private_endpoint_nsg_id No description
apim_subnet_id No description
appgw_subnet_id No description
aca_subnet_id ACA subnet ID for Container App Environment
container_app_environment_id Container App Environment resource ID (null if not enabled)
container_app_environment_name Container App Environment name (null if not enabled)
ai_foundry_hub_id No description
ai_foundry_hub_name No description
ai_foundry_hub_endpoint No description
ai_foundry_hub_principal_id No description
log_analytics_workspace_id No description
application_insights_id No description
application_insights_connection_string No description
application_insights_instrumentation_key No description
language_service_id No description
language_service_endpoint No description
hub_key_vault_id No description
hub_key_vault_name No description
hub_key_vault_uri No description
dns_zone_public_ip_id No description
dns_zone_public_ip_address No description
waf_policy_id No description
app_gateway_id No description
app_gateway_name No description
appgw_url App Gateway frontend URL (https://). Null when App Gateway is not deployed.
hub_alerts_action_group_id Resource ID of the hub monitoring action group. Referenced by the APIM stack to attach APIM resource health alerts.

Resources Created

tenant

Location: infra-ai-hub/stacks/tenant/

Files (6)
  • backend.tf
  • locals.tf
  • main.tf
  • outputs.tf
  • providers.tf
  • variables.tf

Variables

NameTypeDefaultDescription
app_env string required No description
location string required No description
common_tags map(string) {} No description
subscription_id string required No description
tenant_id string required No description
client_id string required No description
use_oidc bool true No description
shared_config any required No description
tenants map(any) {} No description
tenant_tags map(map(string)) {} Per-tenant tags (up to 20 key/value pairs each). Kept separate from var.tenants to avoid HCL structural type unification errors when different tenants have different tag keys.
backend_resource_group string required No description
backend_storage_account string required No description
backend_container_name string tfstate No description

Outputs

NameDescription
tenant_resource_groups No description
tenant_key_vaults No description
tenant_storage_accounts No description
tenant_ai_search No description
tenant_cosmos_db No description
tenant_document_intelligence No description
tenant_speech_services No description
tenant_log_analytics No description
tenant_enabled_resources No description

foundry

Location: infra-ai-hub/stacks/foundry/

Files (6)
  • backend.tf
  • locals.tf
  • main.tf
  • outputs.tf
  • providers.tf
  • variables.tf

Variables

NameTypeDefaultDescription
app_env string required No description
location string required No description
common_tags map(string) {} No description
subscription_id string required No description
tenant_id string required No description
client_id string required No description
use_oidc bool true No description
shared_config any required No description
tenants map(any) {} No description
tenant_tags map(map(string)) {} Per-tenant tags (up to 20 key/value pairs each). Kept separate from var.tenants to avoid HCL structural type unification errors when different tenants have different tag keys.
backend_resource_group string required No description
backend_storage_account string required No description
backend_container_name string tfstate No description

Outputs

NameDescription
tenant_projects No description
tenant_ai_model_deployments No description

apim

Location: infra-ai-hub/stacks/apim/

Files (7)
  • backend.tf
  • locals.tf
  • main.tf
  • monitoring.tf
  • outputs.tf
  • providers.tf
  • variables.tf

Variables

NameTypeDefaultDescription
app_env string required No description
app_name string required No description
location string required No description
common_tags map(string) {} No description
subscription_id string required No description
tenant_id string required No description
client_id string required No description
use_oidc bool true No description
shared_config any required No description
tenants map(any) {} No description
defender_enabled bool false No description
apim_pe_subnet_key string null Optional PE subnet pool key for APIM private endpoint. When set, uses the mapped PE subnet instead of primary. APIM is pinned (not auto-balanced).
defender_resource_types map(object({ {} No description
backend_resource_group string required No description
backend_storage_account string required No description
backend_container_name string tfstate No description

Outputs

NameDescription
apim_gateway_url No description
apim_id APIM resource ID (consumed by key-rotation stack for RBAC)
apim_name No description
apim_principal_id Principal ID of the APIM system-assigned managed identity
apim_key_rotation_summary No description
rotation_enabled_tenants Comma-separated list of tenant names with key rotation enabled (per-tenant opt-in)
apim_tenant_subscriptions No description

Resources Created

tenant-user-mgmt

Location: infra-ai-hub/stacks/tenant-user-mgmt/

Files (6)
  • backend.tf
  • locals.tf
  • main.tf
  • outputs.tf
  • providers.tf
  • variables.tf

Variables

NameTypeDefaultDescription
app_env string required Application environment (dev, test, prod)
subscription_id string required Azure subscription ID
tenant_id string required Azure tenant ID
client_id string required Azure client ID for the service principal (OIDC)
use_oidc bool true Use OIDC for authentication
tenants any {} Tenant configurations (reuses the same tfvars as the main config)
backend_resource_group string required Backend resource group (accepted for shared deploy command contract)
backend_storage_account string required Backend storage account (accepted for shared deploy command contract)
backend_container_name string tfstate Backend container name (accepted for shared deploy command contract)

Outputs

NameDescription
tenant_user_management Map of tenant names to their Entra group IDs and custom role definition IDs

Modules

Reusable modules consumed by the stacks above. Each module wraps Azure Verified Modules (AVM) or native azurerm/azapi resources.

ai-foundry-hub

AI Foundry Hub Module

Location: infra-ai-hub/modules/ai-foundry-hub/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the AI Foundry account
resource_group_name string required Name of the resource group
resource_group_id string required Resource ID of the resource group
location string required Azure region for supporting resources (Log Analytics, App Insights, Private Endpoints)
ai_location string null Azure region for AI Foundry Hub. Can differ from location for model availability (e.g., canadaeast for GPT-4.1). Defaults to location.
sku string S0 SKU for the AI Foundry account
public_network_access_enabled bool false Whether public network access is enabled
local_auth_enabled bool false Whether local authentication (API keys) is enabled
private_endpoint_subnet_id string required Subnet ID for private endpoints
log_analytics object({ { Log Analytics workspace configuration
application_insights optional(string, { Application Insights configuration for AI Foundry monitoring
ai_agent object({ { AI Agent service configuration with network injection support
bing_grounding object({ { Bing Web Search resource for grounding AI models
private_endpoint_dns_wait object({ {} Configuration for waiting on policy-managed DNS zone groups
subscription_id string required Azure subscription ID.
scripts_dir string required Path to the scripts directory containing wait-for-dns-zone.sh
purge_on_destroy bool false Whether to permanently purge the AI Foundry account on destroy (bypasses soft delete)
purge_wait object({ {} Wait configuration for AI Foundry soft-delete before purge
tags map(string) {} Tags to apply to resources

Outputs

NameDescription
id Resource ID of the AI Foundry account
name Name of the AI Foundry account
ai_location Azure region where the AI Foundry Hub is deployed (may differ from PE location)
endpoint Primary endpoint of the AI Foundry account
principal_id Principal ID of the system-assigned managed identity
tenant_id Tenant ID of the system-assigned managed identity
private_endpoint_id Resource ID of the private endpoint
private_endpoint_ip Private IP address of the private endpoint
log_analytics_workspace_id Resource ID of the Log Analytics workspace (if created or provided)
application_insights_id Resource ID of Application Insights (if enabled)
application_insights_connection_string Connection string for Application Insights (if enabled)
application_insights_instrumentation_key Instrumentation key for Application Insights (if enabled, deprecated - use connection_string)
ai_agent_id Resource ID of the AI Agent service (if enabled)
ai_agent_principal_id Principal ID of the AI Agent's managed identity
bing_grounding_id Resource ID of the Bing Grounding resource (if enabled)
bing_grounding_endpoint Endpoint of the Bing Grounding resource (if enabled)

Resources Created

apim

API Management Module (stv2)

Location: infra-ai-hub/modules/apim/

Files (5)
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the API Management instance
resource_group_name string required Name of the resource group
location string required Azure region for resources
sku_name string StandardV2_1 SKU name for APIM (stv2). StandardV2_1-10 for cost-effective, PremiumV2_1-30 for VNet injection and advanced features.
publisher_name string required Publisher name for APIM
publisher_email string required Publisher email for APIM
public_network_access_enabled bool true Whether public network access is enabled for APIM. Set to false to restrict access to private endpoints only.
enable_private_endpoint bool false Whether to create a private endpoint for APIM inbound access. Must be set explicitly to avoid plan-time evaluation issues.
private_endpoint_subnet_id string null Subnet ID for APIM private endpoint (stv2). Required when enable_private_endpoint is true.
private_dns_zone_ids list(string) [] List of private DNS zone IDs to link for APIM private endpoint
enable_vnet_integration bool false Whether to enable VNet integration for outbound connectivity. Required when backend services have public network access disabled.
vnet_integration_subnet_id string null Subnet ID for APIM VNet integration (outbound). Required when enable_vnet_integration is true. Subnet must have delegation to Microsoft.Web/hostingEnvironments.
enable_diagnostics bool false Whether to enable diagnostic settings. Must be set explicitly to avoid plan-time evaluation issues.
log_analytics_workspace_id string null Log Analytics Workspace ID for diagnostics. Required when enable_diagnostics is true.
tenant_products map(object({ {} Map of tenant names to their product configurations
tags map(string) {} Tags to apply to resources
enable_telemetry bool false Enable AVM telemetry
apis optional(string, {} Map of APIs to create in APIM
subscriptions string {} Map of subscriptions to create
named_values map(object({ {} Map of named values (properties) for APIM
policy_fragments map(object({ {} Map of reusable policy fragments
global_policy_xml string null XML content for the global API Management policy
scripts_dir string required Path to the scripts directory containing wait-for-dns-zone.sh
private_endpoint_dns_wait object({ {} Configuration for waiting on policy-managed DNS zone groups

Outputs

NameDescription
id Resource ID of the API Management instance
name Name of the API Management instance
gateway_url Gateway URL of the API Management instance
management_url Management URL of the API Management instance
developer_portal_url Developer portal URL
private_ip_addresses Private IP addresses of APIM (when VNet integrated)
public_ip_addresses Public IP addresses of APIM
product_ids Map of product names to their resource IDs
principal_id Principal ID of the APIM managed identity
private_endpoint_ip Private IP address of the APIM private endpoint

Resources Created

app-configuration

App Configuration Module

Location: infra-ai-hub/modules/app-configuration/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the App Configuration store
resource_group_name string required Name of the resource group
location string required Azure region for resources
sku string standard SKU for App Configuration (free or standard)
public_network_access_enabled bool false Enable public network access
local_auth_enabled bool false Enable local authentication (access keys)
purge_protection_enabled bool true Enable purge protection
soft_delete_retention_days number 7 Soft delete retention in days (1-7)
private_endpoint_subnet_id string null Subnet ID for private endpoint
encryption object({ { Customer-managed key encryption configuration
replicas list(object({ [] Geo-replication configuration (Standard SKU only)
feature_flags map(object({ {} Feature flags to create
configuration_keys optional(string) {} Configuration key-value pairs
log_analytics_workspace_id string null Log Analytics Workspace ID for diagnostics
scripts_dir string required Path to shared scripts directory for DNS wait operations
private_endpoint_dns_wait object({ {} Configuration for waiting on policy-managed DNS zone groups
tags map(string) {} Tags to apply to resources

Outputs

NameDescription
resource_id Resource ID of the App Configuration store
name Name of the App Configuration store
endpoint Endpoint of the App Configuration store
primary_read_key Primary read key connection string
principal_id Principal ID of the system-assigned managed identity
private_endpoint_id Resource ID of the private endpoint

Resources Created

app-gateway

Application Gateway Module

Location: infra-ai-hub/modules/app-gateway/

Files (5)
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the Application Gateway
resource_group_name string required Name of the resource group
location string required Azure region for resources
subnet_id string required Subnet ID for the Application Gateway
sku object({ { SKU configuration for App Gateway
autoscale object({ null Autoscale configuration (if set, overrides sku.capacity)
waf_enabled bool true Enable Web Application Firewall
waf_mode string Prevention WAF mode: Detection or Prevention
ssl_certificates map(object({ {} SSL certificates — from Key Vault (key_vault_secret_id) or direct PFX upload (data+password). Certificates can also be uploaded via Azure Portal; Terraform will ignore changes to ssl_certificate blocks.
ssl_certificate_name string null Name of an SSL certificate already on the App Gateway (uploaded via CLI/portal). When set, enables HTTPS listener and HTTP→HTTPS redirect. Only set after the cert has been uploaded to the App Gateway.
backend_apim object({ required APIM backend configuration. The FQDN resolves to the PE private IP via private DNS zone linked to the App GW VNet.
frontend_hostname string required Frontend hostname for the listener
enable_diagnostics bool false Whether to enable diagnostic settings (use static bool to avoid count unknown at plan time)
log_analytics_workspace_id string null Log Analytics Workspace ID for diagnostics
key_vault_id string null Key Vault ID for SSL certificate access
public_ip_resource_id string null Resource ID of a pre-created static Public IP for the App Gateway. When set, App GW uses this existing PIP. When null, this module does not create or associate any Public IP, and you must ensure a suitable frontend configuration (for example, a private frontend or an externally managed PIP). Typically provided by the dns-zone module.
tags map(string) {} Tags to apply to resources
zones set(string) [1, Availability zones for App Gateway
url_path_map_configurations map(object({ null URL path maps for path-based routing
rewrite_rule_set map(object({ null Rewrite rule sets for header and URL manipulation
waf_policy_id string null Resource ID of WAF policy to associate with App Gateway

Outputs

NameDescription
id Resource ID of the Application Gateway
name Name of the Application Gateway
public_ip_address Public IP address of the Application Gateway. Returns null - get this from the dns_zone module output instead (dns_zone_public_ip) to avoid data source lookup failures during first deployment.
public_ip_id Public IP resource ID
backend_address_pools Backend address pools
principal_id Principal ID of the App Gateway managed identity (user-assigned)

Resources Created

container-app-environment

Container App Environment Module

Location: infra-ai-hub/modules/container-app-environment/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the Container App Environment
resource_group_name string required Name of the resource group
location string required Azure region for resources
infrastructure_subnet_id string required Subnet ID for the Container App Environment infrastructure
internal_load_balancer_enabled bool true Use internal load balancer (private only access)
zone_redundancy_enabled bool false Enable zone redundancy. Requires /23+ subnet. Set to false for /27 consumption-only.
mtls_enabled bool true Enable mTLS peer authentication between apps
workload_profiles string [] Workload profiles for dedicated compute (Consumption-only if empty)
log_analytics_workspace_id string null Log Analytics Workspace ID for diagnostics
enable_diagnostics bool false Enable diagnostic settings. Use this instead of null-checking log_analytics_workspace_id to avoid count depending on resource attributes during destroy.
tags map(string) {} Tags to apply to resources
private_endpoint_subnet_id string required Subnet ID for Container App Environment private endpoint. Required when enable_private_endpoint is true.
scripts_dir string required Path to shared scripts directory for DNS wait operations
private_endpoint_dns_wait object({ {} Configuration for waiting on policy-managed DNS zone groups

Outputs

NameDescription
resource_id Resource ID of the Container App Environment
name Name of the Container App Environment
default_domain Default domain of the Container App Environment
static_ip_address Static IP address of the Container App Environment

Resources Created

container-registry

Container Registry Module

Location: infra-ai-hub/modules/container-registry/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the Container Registry
resource_group_name string required Name of the resource group
location string required Azure region for resources
sku string Premium SKU for Container Registry. Premium required for private endpoints and geo-replication.
public_network_access_enabled bool true Enable public network access. Set to true for public ACR, false for private-only.
private_endpoint_subnet_id string null Subnet ID for private endpoints. Required if public_network_access_enabled is false.
admin_enabled bool false Enable admin user for the registry
quarantine_policy_enabled bool false Enable quarantine policy for images
data_endpoint_enabled bool false Enable dedicated data endpoints for each region
export_policy_enabled bool true Enable export policy (allows images to be exported)
zone_redundancy_enabled bool true Enable zone redundancy (Premium only)
enable_trust_policy bool false Enable content trust / image signing (Premium only)
retention_policy_days number 7 Days to retain untagged manifests (0 = disabled)
georeplications map(object({ {} Geo-replication configuration for Premium SKU
log_analytics_workspace_id string null Log Analytics Workspace ID for diagnostics
scripts_dir string required Path to shared scripts directory for DNS wait operations
private_endpoint_dns_wait object({ {} Configuration for waiting on policy-managed DNS zone groups
resource_group_name_for_dns_wait string null Resource group name to use for DNS wait operations (where PE is created)
tags map(string) {} Tags to apply to resources
enable_telemetry bool false Enable AVM telemetry

Outputs

NameDescription
resource_id Resource ID of the Container Registry
name Name of the Container Registry
login_server Login server URL of the Container Registry
principal_id Principal ID of the system-assigned managed identity
private_endpoint_id Resource ID of the private endpoint

Resources Created

defender

Microsoft Defender for Cloud Subscription Pricing

Location: infra-ai-hub/modules/defender/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
resource_types map(object({ {} Map of Defender for Cloud resource types to enable with their configuration. Keys are resource type names (e.g., 'Api', 'StorageAccounts'), values are objects with subplan.

Outputs

NameDescription
enabled_resource_types List of Defender for Cloud resource types that are enabled
pricing_ids Map of resource type to pricing resource ID

Resources Created

dns-zone

=============================================================================

Location: infra-ai-hub/modules/dns-zone/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name_prefix string required Prefix for resource names (e.g., ai-hub-test)
location string required Azure region for resources
dns_zone_name string required DNS zone name (e.g., test.aihub.gov.bc.ca)
resource_group_name string required Name of the DNS resource group
a_record_ttl number 3600 TTL for the A record in seconds
tags map(string) {} Tags to apply to resources
ddos_protection_enabled bool false Enable DDoS IP Protection on the App Gateway public IP. Provides per-IP adaptive L3/L4 DDoS mitigation, telemetry, and alerting. Cost: ~$199 USD/month per IP.
log_analytics_workspace_id string required Log Analytics workspace ID for diagnostic settings on the public IP and DNS zone

Outputs

NameDescription
dns_zone_id Resource ID of the DNS zone
dns_zone_name Name of the DNS zone
name_servers Name servers for the DNS zone (provide these to your DNS registrar for delegation)
public_ip_id Resource ID of the static public IP (pass to App Gateway module)
public_ip_address IP address of the static public IP
resource_group_name Name of the DNS resource group
resource_group_id Resource ID of the DNS resource group

Resources Created

foundry-project

=============================================================================

Location: infra-ai-hub/modules/foundry-project/

Files (5)
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
tenant_name string required Name of the tenant (used for resource naming)
location string required Azure region for the project
ai_location string required Azure region for AI resources (can differ from project location for model availability)
ai_foundry_hub_id string required Resource ID of the parent AI Foundry hub
tags map(string) {} Tags to apply to resources
key_vault object({ { Key Vault configuration from tenant module
storage_account object({ { Storage account configuration from tenant module
ai_search object({ { AI Search configuration from tenant module
cosmos_db object({ { Cosmos DB configuration from tenant module
document_intelligence object({ { Document Intelligence configuration from tenant module
ai_model_deployments string {} AI model deployments to create on the shared AI Foundry Hub (prefixed with tenant name)
project_connections object({ {} Toggle which project connections to create

Outputs

NameDescription
project_id Resource ID of the AI Foundry project
project_name Name of the AI Foundry project
project_principal_id Principal ID of the AI Foundry project's managed identity
ai_model_deployment_ids Map of original model names to their resource IDs (deployment names are tenant-prefixed)
ai_model_deployment_names List of deployed AI model names (tenant-prefixed, e.g., 'wlrs-gpt-4.1-mini')
ai_model_deployment_mapping Map of client-facing model names to tenant-prefixed deployment names
has_model_deployments Whether this tenant has any AI model deployments
complete Marker indicating all project resources are complete (for serialization)

Resources Created

key-rotation-function

=============================================================================

Location: infra-ai-hub/modules/key-rotation-function/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name_prefix string required Naming prefix (e.g., ai-services-hub-dev)
resource_group_name string required Resource group for all resources
resource_group_id string required Resource group ID (for RBAC scoping)
location string required Azure region
tags map(string) {} Resource tags
container_app_environment_id string required Container App Environment resource ID
container_registry_url string ghcr.io Container registry URL (e.g., ghcr.io)
container_image_name string required Container image name (e.g., bcgov/ai-hub-tracking/apim-key-rotation)
container_image_tag string latest Container image tag
cpu number 0.5 CPU cores allocated to the container (e.g., 0.5)
memory string 1Gi Memory allocated to the container (e.g., 1Gi)
cron_expression string 0 Cron expression for the job schedule (e.g., 0 9 * * * for daily 09:00 UTC)
replica_timeout_seconds number 1800 Maximum seconds a replica can run before being terminated
key_propagation_wait_seconds number 10 Seconds to pause after APIM key regeneration for propagation (per tenant)
replica_retry_limit number 1 Maximum number of retries for a failed replica
apim_id string required APIM resource ID (for RBAC)
apim_name string required APIM instance name (passed to job as env var)
hub_keyvault_id string required Hub Key Vault resource ID (for RBAC)
hub_keyvault_name string required Hub Key Vault name (passed to job as env var)
environment string required Target environment (dev, test, prod)
app_name string required Application name prefix
subscription_id string required Azure subscription ID
rotation_enabled bool true Master rotation toggle
rotation_interval_days number 7 Days between rotations (must be < 90)
dry_run bool false When true, logs what would happen without making changes
included_tenants string required Comma-separated list of tenant names to include in rotation (empty = no tenants — safe default)
secret_expiry_days number 90 Key Vault secret expiry in days (Landing Zone max: 90)

Outputs

NameDescription
job_id Resource ID of the key rotation Container App Job
job_name Name of the key rotation Container App Job
principal_id System-assigned Managed Identity principal ID

Resources Created

network

Network Module - Main Configuration

Location: infra-ai-hub/modules/network/

Files (6)
  • data.tf
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name_prefix string required Prefix used for naming resources (e.g., ai-hub-dev)
location string required Azure region for resources
common_tags map(string) {} Common tags to apply to all resources
vnet_name string required Name of the existing virtual network (target environment)
vnet_resource_group_name string required Resource group name where the virtual network exists (target environment)
source_vnet_address_space string required Address space of the source environment VNet (single CIDR string), used for NSG allow rules (e.g., tools VNet CIDR).
subnet_allocation map(map(string)) required No description
external_peered_projects map(object({ {} No description

Outputs

NameDescription
private_endpoint_subnet_id Resource ID of the primary private endpoint subnet (first in pool)
private_endpoint_subnet_cidr CIDR of the primary private endpoint subnet
private_endpoint_nsg_id Resource ID of the private endpoint NSG
private_endpoint_subnet_pool Map of all PE subnets available for tenant allocation (name => cidr)
private_endpoint_subnet_ids_by_key Map of PE subnet pool key to resource ID.
private_endpoint_subnet_cidrs_by_key Map of PE subnet pool key to CIDR string.
private_endpoint_subnet_keys_ordered Ordered list of PE subnet pool keys for deterministic iteration.
apim_subnet_id Resource ID of the APIM subnet (null if not enabled)
apim_subnet_cidr CIDR of the APIM subnet (null if not enabled)
apim_nsg_id Resource ID of the APIM NSG (null if not enabled)
appgw_subnet_id Resource ID of the App Gateway subnet (null if not enabled)
appgw_subnet_cidr CIDR of the App Gateway subnet (null if not enabled)
appgw_nsg_id Resource ID of the App Gateway NSG (null if not enabled)
aca_subnet_id Resource ID of the ACA subnet (null if not enabled)
aca_subnet_cidr CIDR of the ACA subnet (null if not enabled)
aca_nsg_id Resource ID of the ACA NSG (null if not enabled)
vnet_id Resource ID of the target VNet
vnet_name Name of the target VNet

Resources Created

pii-redaction-service

=============================================================================

Location: infra-ai-hub/modules/pii-redaction-service/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name_prefix string required Prefix for all resource names (e.g. 'aihub-dev').
resource_group_name string required Name of the resource group where the Container App is deployed.
container_app_environment_id string required Resource ID of the shared Container App Environment.
container_registry_url string ghcr.io Container registry URL (without trailing slash).
container_image_name string required Full image name within the registry (e.g. 'bcgov/ai-hub-tracking/jobs/pii-redaction-service').
container_image_tag string latest Container image tag. Use 'latest' for rolling deployments or a semver tag for pinned releases.
cpu number 0.25 vCPU allocation per replica.
memory string 512Mi Memory allocation per replica (e.g. '1Gi').
min_replicas number 1 Minimum number of Container App replicas.
max_replicas number 5 Maximum number of Container App replicas.
language_endpoint string required Azure Language Service endpoint URL (PII_LANGUAGE_ENDPOINT).
language_service_id string required Resource ID of the Language Service — used for the Cognitive Services User RBAC assignment.
language_api_version string required Language API version string (PII_LANGUAGE_API_VERSION).
per_batch_timeout_seconds number 10 Timeout in seconds for each Language API batch call (PII_PER_BATCH_TIMEOUT_SECONDS).
total_processing_timeout_seconds number 85 Overall deadline in seconds for processing all batches (PII_TOTAL_PROCESSING_TIMEOUT_SECONDS).
transient_retry_attempts number 4 Maximum retries for transient 429 and 5xx Language API responses after the initial request.
retry_backoff_base_seconds number 1 Base exponential backoff delay in seconds when Retry-After is absent.
retry_backoff_max_seconds number 10 Maximum exponential backoff delay in seconds when Retry-After is absent.
max_concurrent_batches number 15 Maximum Language API batches per request. Requests requiring more batches are rejected with HTTP 413.
max_batch_concurrency number 3 Number of Language API batches allowed in flight simultaneously (semaphore bound).
max_doc_chars number 5000 Maximum characters per Language API document before word-boundary chunking (PII_MAX_DOC_CHARS).
max_docs_per_call number 5 Maximum documents per Language API call (PII_MAX_DOCS_PER_CALL).
log_level string INFO Application log level (PII_LOG_LEVEL). One of: DEBUG, INFO, WARNING, ERROR.
tags map(string) {} Resource tags.

Outputs

NameDescription
container_app_id Resource ID of the PII Redaction Container App.
container_app_fqdn Internal FQDN of the PII Redaction Container App (accessible within the VNet via the Container App Environment).
principal_id Object ID of the Container App's system-assigned managed identity.

Resources Created

tenant-user-management

=============================================================================

Location: infra-ai-hub/modules/tenant-user-management/

Files (6)
  • data.tf
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
tenant_name string required Unique identifier for the tenant (used in group/role names)
display_name string required Human-readable display name for the tenant
app_env string required Application environment (dev, test, prod) — included in group/role names to prevent cross-environment conflicts
resource_group_id string required Resource group ID for tenant scope role assignments
user_management object({ {} Tenant user management configuration (Entra groups + custom roles)

Outputs

NameDescription
group_object_ids Object IDs for tenant role groups (empty when create_groups = false)
role_definition_ids Role definition IDs for tenant custom roles
mode Assignment mode: 'group' when create_groups=true, 'direct_user' otherwise
direct_user_assignments Map of direct user role assignments (empty when create_groups = true)

Resources Created

tenant

Tenant Module - Main Configuration

Location: infra-ai-hub/modules/tenant/

Files (6)
  • data.tf
  • locals.tf
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
tenant_name string required Unique identifier for the tenant (used in resource names)
display_name string required Human-readable display name for the tenant
location string required Azure region for resources
ai_location string null Azure region for AI services (OpenAI, Document Intelligence). Can differ from location for model availability.
resource_group_name_override string null Optional custom name for the tenant resource group. If not provided, defaults to '{tenant_name}-rg'
private_endpoint_subnet_id string required Subnet ID for private endpoints
log_analytics_workspace_id string null Resource ID of Log Analytics workspace for diagnostics (legacy/shared)
log_analytics object({ { Per-tenant Log Analytics workspace configuration
private_endpoint_dns_wait object({ {} Configuration for waiting on policy-managed DNS zone groups
scripts_dir string required Path to shared scripts directory for DNS wait operations
key_vault object({ { Key Vault configuration for the tenant
storage_account optional(string, { Storage Account configuration for the tenant
ai_search object({ { Azure AI Search configuration for the tenant
cosmos_db optional(string, { Cosmos DB configuration for the tenant
document_intelligence object({ { Document Intelligence configuration for the tenant
speech_services object({ { Azure Speech Services configuration for the tenant
ai_foundry_hub_id string null Resource ID of the shared AI Foundry Hub (for reference in outputs)
tags map(string) {} Tags to apply to tenant resources

Outputs

NameDescription
resource_group_name Name of the tenant's resource group
resource_group_id ID of the tenant's resource group
key_vault_id Resource ID of the Key Vault
key_vault_name Name of the Key Vault
key_vault_uri URI of the Key Vault
storage_account_id Resource ID of the Storage Account
storage_account_name Name of the Storage Account
storage_account_primary_blob_endpoint Primary blob endpoint of the Storage Account
storage_account_primary_access_key Primary access key of the Storage Account
storage_account_primary_connection_string Primary connection string of the Storage Account
ai_search_id Resource ID of the AI Search service
ai_search_name Name of the AI Search service
ai_search_endpoint Endpoint URL of the AI Search service
cosmos_db_id Resource ID of the Cosmos DB account
cosmos_db_name Name of the Cosmos DB account
cosmos_db_account_name Account name of the Cosmos DB (alias for cosmos_db_name, used for role assignments)
cosmos_db_resource_group_name Resource group name containing the Cosmos DB account
cosmos_db_endpoint Endpoint of the Cosmos DB account
cosmos_db_database_name Name of the pre-created Cosmos DB SQL database
document_intelligence_id Resource ID of the Document Intelligence account
document_intelligence_name Name of the Document Intelligence account
document_intelligence_endpoint Endpoint of the Document Intelligence account
speech_services_id Resource ID of the Speech Services account
speech_services_name Name of the Speech Services account
speech_services_endpoint Endpoint of the Speech Services account
speech_services_primary_key Primary access key for the Speech Services account
openai_endpoint Endpoint for OpenAI-compatible API calls (shared AI Foundry Hub)
openai_id Resource ID for AI models (points to AI Foundry Hub)
log_analytics_workspace_id Resource ID of the tenant's Log Analytics workspace (if enabled)
has_log_analytics Whether the tenant has a Log Analytics workspace (own or shared)
log_analytics_enabled Whether the tenant has its own dedicated Log Analytics workspace
application_insights_id Resource ID of the tenant's Application Insights (if tenant LAW enabled)
application_insights_instrumentation_key Instrumentation key for the tenant's Application Insights
application_insights_connection_string Connection string for the tenant's Application Insights
enabled_resources Summary of which resources are enabled for this tenant

Resources Created

waf-policy

WAF Policy Module

Location: infra-ai-hub/modules/waf-policy/

Files (4)
  • main.tf
  • outputs.tf
  • variables.tf
  • versions.tf

Variables

NameTypeDefaultDescription
name string required Name of the WAF policy
resource_group_name string required Name of the resource group
location string required Azure region for resources
enabled bool true Enable the WAF policy
mode string Prevention WAF mode: Detection or Prevention
request_body_check bool true Enable request body inspection
request_body_enforcement bool true Enforce max request body size limit. When false, WAF inspects up to inspect_limit but does not reject oversized requests. Requires OWASP CRS 3.2+
request_body_inspect_limit_in_kb number 128 How deep into a request body the WAF inspects and applies rules (KB). Only used with CRS 3.2+
max_request_body_size_kb number 128 Maximum request body size in KB (8-2000)
file_upload_limit_mb number 100 Maximum file upload size in MB
managed_rule_sets "Microsoft_BotManagerRuleSet" [ Managed rule sets to apply
exclusions list(object({ [] Rule exclusions for false positive handling
custom_rules "RateLimitRule") [] Custom WAF rules (MatchRule or RateLimitRule)
tags map(string) {} Tags to apply to resources

Outputs

NameDescription
resource_id Resource ID of the WAF policy
name Name of the WAF policy
http_listener_ids Associated HTTP listener IDs
path_based_rule_ids Associated path-based rule IDs

Resources Created

Adding New Modules

When creating new Terraform modules, follow these conventions to ensure automatic documentation:

  1. Add a description comment at the top of main.tf:
    # Description: This module creates Azure storage accounts with encryption
  2. Always include description for variables:
    variable "storage_name" {
      type        = string
      description = "Name of the storage account (must be globally unique)"
    }
  3. Always include description for outputs:
    output "storage_id" {
      value       = azurerm_storage_account.main.id
      description = "The resource ID of the storage account"
    }
  4. Run the documentation generator:
    ./docs/generate-tf-docs.sh
💡
Tip: The documentation generator runs automatically during the GitHub Pages build. Push to main and docs are rebuilt.