Skip to content

AI Platform: Platform Modules

This page is for the platform team. It describes the five Terraform modules of the solution, their main inputs and how they are meant to be combined. The platform team is XMMS or your own team, see Operating models.

Modules only

The source delivers modules. The deployment code that calls them per environment ("deploy roots") is planned for a later phase. Deployment order when it exists: shared platform first, then projects, then workloads.

Requirements

Item Value
Terraform >= 1.12, < 2.0
AzureRM provider >= 4.0.0, < 5.0
AzAPI provider >= 2.6.1, < 3.0
Azure AD provider ~> 2.47, < 3.0
Naming module Azure/naming/azurerm ~> 0.4
Backend azurerm with use_azuread_auth = true; storage account, container and key are passed at terraform init, nothing is committed
Authentication Azure CLI session with sufficient permissions

The azurerm version constraint (< 5.0) matters when you plan a provider upgrade, see Known issues. Lock files are committed to the repository.

Overview

Module Type Creates
foundry_account Resources Foundry account, its identity, optional private endpoint
foundry_project Resources Project, identity, storage, Application Insights, connections, capability host, role assignments
workload_identity Resources User-assigned identity and role assignments
platform_data Data only Lookup of shared platform resources
project_data Data only Lookup of one project and its identity
flowchart LR
    pd["platform_data"] --> pdata["project_data"]
    pd --> fp["foundry_project"]
    fa["foundry_account"] --> fp
    fp --> wi["workload_identity"]
    pdata --> wl["workload"]
    wi --> wl

foundry_account

Creates the shared account. Inputs:

Input Required Description
name Yes Account name. Also used as custom subdomain. The identity is named <name>-identity, the private endpoint <name>-pe.
resource_group_id Yes Parent resource group ID
location Yes Azure region
integration_subnet_id Yes Subnet for agent network injection
endpoint_subnet_id No Subnet for the private endpoint. Without it, no private endpoint is created.
tags No Tags

Outputs: id, name, endpoint, openai_endpoint, identity_client_id, identity_principal_id.

foundry_project

Creates one project. Two modes:

Mode When Result
Decoupled account_id is set Only the project and its resources, in the existing account. Use this with the shared platform account.
Standalone account_id is null (default) Also creates an account, its identity, a private endpoint and diagnostic settings. Kept for backward compatibility.
Input Required Description
project_name Yes (default null in code) Name of the project. Also the suffix for resource names.
location Yes Azure region
integration_subnet_id Yes Agent integration subnet
endpoint_subnet_id Yes Subnet for private endpoints
log_analytics_workspace_id Yes Workspace for Application Insights (and diagnostics in standalone mode)
cosmosdb_account_id Yes Cosmos DB account for agent threads
ai_search_id Yes AI Search service as vector store
account_id No Existing account
owner_group_id, contributor_group_id, reader_group_id Effectively yes Entra ID groups, see Access and RBAC
tags No Tags

Outputs: foundry (account ID, name, identity; identity values are null in decoupled mode), foundry_project (ID, name, identity) and used_resources (storage account, Cosmos DB, AI Search).

Sequence inside the module, which explains the waits you see in a plan:

  1. Resource group, identities, Application Insights, storage account and its private endpoint.
  2. The project, then a 10 second wait for the project identity to be available in Entra ID.
  3. Connections (storage, Cosmos DB, AI Search, Application Insights) and the role assignments on the data stores.
  4. A 60 second wait for role assignments to take effect.
  5. The capability host caphostproject-<project>.
  6. The Cosmos DB SQL role assignments on the collections the capability host created.

platform_data and project_data

Data-only modules, no resources.

platform_data has no inputs. It looks up the platform resource group, the Foundry account, container registry, Container Apps environment, Cosmos DB, AI Search, two storage accounts (platform and data), Key Vault, Log Analytics workspace, the spoke VNet, the private endpoint subnet and the Foundry integration subnet, and exposes IDs, names and endpoints. It also outputs the owner, contributor and reader group IDs.

Resource names are hard-coded

The names in platform_data are written as local values in main.tf for one platform deployment (one region, production). Another deployment, region or environment needs a change of those values, or the module has to be changed to take inputs. See Known issues.

project_data takes project_name and uses platform_data to find the account. It outputs project_id, project_name, project_endpoint, identity_client_id and identity_principal_id. It finds the project identity by the naming convention id-<project>-foundry-project in the project resource group, so a project created outside foundry_project must follow that convention.

workload_identity

Input Required Description
name Yes Identity name
location Yes Region
resource_group_name Yes Resource group of the identity
role_assignments No List of objects with scope and role_definition_name
tags No Tags

Outputs: id, client_id, principal_id. Each assignment is keyed on scope plus role name.

Create a project: checklist

Use this as a guide when a request for a new project arrives. Adapt it to your deployment code.

Step Check
1 The name is short (maximum 8 characters) and unique on the platform
2 Region and environment are allowed on your platform
3 The three groups exist and have the right owners (Access, groups and PIM)
4 The shared Cosmos DB, AI Search, Log Analytics workspace and the two subnets exist
5 Required private DNS zones resolve (see Architecture)
6 The needed models are deployed in the account and quota is available
7 Plan shows the expected project resources only, then apply through your normal pipeline and review: Change workflow