LAB 09 – AzAPI: the whole Azure API, today¶
Story: GreenGrid's security architect wants application security groups and asks for storage properties the azurerm provider does not show. Azure has them – in the Resource Manager REST API. AzAPI gives you that API in Terraform.
| Duration | ~35 min |
| You create | azapi.tf; you edit versions.tf, providers.tf, outputs.tf, the tests |
| Solution | solutions/LAB09/ (or ./bin/catchup 9) |
| azurerm | AzAPI | |
|---|---|---|
| Resources | curated, typed arguments | every ARM resource type and API version |
| New Azure features | when the provider adds them | the day the API ships |
| Validation | provider schema | embedded ARM schema (schema_validation_enabled) |
| Body | HCL arguments | the ARM JSON as an HCL object |
Step 1 – Add the provider¶
versions.tf – add to required_providers:
providers.tf:
Step 2 – A resource straight from its ARM schema¶
azapi.tf:
resource "azapi_resource" "asg_app" {
type = "Microsoft.Network/applicationSecurityGroups@2024-05-01"
name = "asg-app-${local.name_suffix}"
parent_id = azurerm_resource_group.main.id
location = azurerm_resource_group.main.location
tags = local.common_tags
body = {
properties = {}
}
response_export_values = ["properties.provisioningState"]
}
type= resource type @ API version – look them up in the Azure REST API reference.parent_idfollows the ARM hierarchy: resource group → resource → child resource.bodyis plain HCL in AzAPI 2.x – nojsonencode();outputis plain HCL too – nojsondecode().
Step 3 – Read anything¶
data "azapi_resource" "storage" {
type = "Microsoft.Storage/storageAccounts@2024-01-01"
resource_id = module.storage.id
response_export_values = {
tls = "properties.minimumTlsVersion"
access_tier = "properties.accessTier"
created_time = "properties.creationTime"
}
}
Outputs:
output "asg_provisioning_state" {
description = "Read from the ARM response - no jsondecode() needed in AzAPI 2.x"
value = azapi_resource.asg_app.output.properties.provisioningState
}
output "storage_arm_properties" {
description = "Storage properties read with AzAPI"
value = data.azapi_resource.storage.output
}
✅ Checkpoint: asg_provisioning_state = "Succeeded"; the storage output shows TLS1_2, Hot and the creation time – creationTime is not an azurerm attribute.
Step 4 – Keep the tests green¶
The tests from LAB08 now need a mock for azapi, otherwise terraform test asks for credentials:
mkdir -p tests/mocks/azapi
cp ../../solutions/LAB09/tests/mocks/azapi/azapi.tfmock.hcl tests/mocks/azapi/
Add to tests/greengrid.tftest.hcl:
Step 5 – azapi_update_resource (discussion)¶
azapi_update_resource PATCHes properties on a resource managed elsewhere – the classic way to set a property azurerm does not support yet:
resource "azapi_update_resource" "example" {
type = "Microsoft.Storage/storageAccounts@2024-01-01"
resource_id = module.storage.id
body = { properties = { someNewProperty = "value" } }
}
⚠️ If azurerm also manages that property, the two providers fight on every apply. Use it only for properties azurerm does not know – and replace it with the azurerm argument once the provider catches up.
Bonus¶
- Convert the ASG to azurerm (
azurerm_application_security_group) with amovedblock – is that possible across providers? (No: useremoved+import.) azapi_resource_actioncalls ARM actions, e.g.listKeys– why is that dangerous for the state?- Export an existing resource as AzAPI code:
aztfexport resource --provider-name=azapi <resource id>.
Troubleshooting¶
| Symptom | Likely cause |
|---|---|
embedded schema validation failed |
property name or API version wrong – check the REST reference |
NoRegisteredProviderFound for the API version |
that version does not exist for this resource type |
output is null |
the path is not in response_export_values |
| tests ask for Azure credentials | mock_provider "azapi" missing |
Files for this lab: Think-Cube/terraform-azure-labs/labs/LAB09-azapi