Summary
Add Terraform as a supported infrastructure-as-code option for Foundry agents, so teams standardized on Terraform can provision and manage agent infrastructure with real .tf files and their own state/backend workflow.
azd ai agent init --infra would emit a Terraform template (instead of Bicep) that provisions the same resources and produces the same outputs, and the agent deploy/RBAC flow continues to work unchanged.
Goals
azd ai agent init --infra can emit a Terraform template instead of Bicep.
- Ejected .tf provisions the same resources and emits the same output contract as the Bicep template.
- Agent deploy + RBAC continue to work unchanged on the Terraform path.
Non-goals
- No bicepless/in-memory option for Terraform — .tf files are always on disk.
Proposed approach
-
Author a Terraform module (azurerm + azapi mix) replicating internal/synthesis/templates/{main,modules/resources,modules/acr}.bicep:
- azurerm_resource_group, azurerm_cognitive_deployment, azurerm_container_registry, azurerm_role_assignment ×2 (Cognitive Services User on project, AcrPull on ACR).
- azapi for the AIServices account (allow_project_management), the Foundry projects sub-resource, and the ContainerRegistry connections sub-resource.
-
Eject command: azd ai agent init --infra=terraform
| Invocation |
Result |
azd ai agent init --infra |
eject Bicep (unchanged) |
azd ai agent init --infra=terraform |
eject Terraform (new) |
azd ai agent init --infra=bicep |
eject Bicep (explicit) |
| (flag absent) |
bicepless default — no files, microsoft.foundry (unchanged) |
-
Set infra.provider: terraform in azure.yaml so azd-core's built-in Terraform provider handles provisioning (the microsoft.foundry provider is not used on this path).
Why delegate to azd-core's Terraform provider (instead of building a custom one)
Bicep is handled by a custom in-extension provider (microsoft.foundry) that
generates and deploys infra itself. For Terraform we could either build a similar
custom provider, or delegate to azd-core's built-in Terraform provider. We chose to
delegate, for two reasons:
-
Cost & consistency. The custom microsoft.foundry provider's rich behavior
is cheap for Bicep only because Bicep compiles to ARM JSON and reuses the ARM
deployment engine the provider already has. Terraform has no such intermediate,
so, a custom Terraform provider means building a second provisioning engine plus
maintaining a parallel Terraform copy.
-
Auth gap. A custom Terraform provider would have to authenticate the
terraform Azure provider itself, but the extension only holds azd's
credential and sets none of the ARM_* environment variables Terraform expects.
azd-core's Terraform provider already handles that, so delegating avoids the
problem entirely.
End-to-end journey:
| Step |
Command |
Who handles it |
| Scaffold |
azd ai agent init |
extension (agent prompts, unchanged) |
| Choose IaC |
--infra=terraform |
extension eject → writes .tf + stamps infra.provider: terraform |
| Provision |
azd provision |
azd-core Terraform provider (terraform init/plan/apply) |
| Deploy |
azd deploy |
extension azure.ai.agent service target (unchanged) |
| Tear down |
azd down |
azd-core terraform destroy |
Summary
Add Terraform as a supported infrastructure-as-code option for Foundry agents, so teams standardized on Terraform can provision and manage agent infrastructure with real .tf files and their own state/backend workflow.
azd ai agent init --infrawould emit a Terraform template (instead of Bicep) that provisions the same resources and produces the same outputs, and the agent deploy/RBAC flow continues to work unchanged.Goals
azd ai agent init --infracan emit a Terraform template instead of Bicep.Non-goals
Proposed approach
Author a Terraform module (azurerm + azapi mix) replicating
internal/synthesis/templates/{main,modules/resources,modules/acr}.bicep:Eject command:
azd ai agent init --infra=terraformazd ai agent init --infraazd ai agent init --infra=terraformazd ai agent init --infra=bicepmicrosoft.foundry(unchanged)Set
infra.provider: terraforminazure.yamlso azd-core's built-in Terraform provider handles provisioning (the microsoft.foundry provider is not used on this path).Why delegate to azd-core's Terraform provider (instead of building a custom one)
Bicep is handled by a custom in-extension provider (
microsoft.foundry) thatgenerates and deploys infra itself. For Terraform we could either build a similar
custom provider, or delegate to azd-core's built-in Terraform provider. We chose to
delegate, for two reasons:
Cost & consistency. The custom
microsoft.foundryprovider's rich behavioris cheap for Bicep only because Bicep compiles to ARM JSON and reuses the ARM
deployment engine the provider already has. Terraform has no such intermediate,
so, a custom Terraform provider means building a second provisioning engine plus
maintaining a parallel Terraform copy.
Auth gap. A custom Terraform provider would have to authenticate the
terraformAzure provider itself, but the extension only holds azd'scredential and sets none of the
ARM_*environment variables Terraform expects.azd-core's Terraform provider already handles that, so delegating avoids the
problem entirely.
End-to-end journey:
azd ai agent init--infra=terraform.tf+ stampsinfra.provider: terraformazd provisionterraform init/plan/apply)azd deployazure.ai.agentservice target (unchanged)azd downterraform destroy