Using Terraform
April 30, 2026 · View on GitHub
PSRule for Azure supports analyzing Azure resources defined in Terraform configurations by expanding Terraform plan JSON files.
This enables pre-flight validation of Terraform-managed Azure resources against Azure Well-Architected Framework (WAF) rules.
!!! Experimental "Experimental - Learn more" Terraform plan expansion is a work in progress, and not ready for production use. We are actively working on improving this experience, and would love to hear your feedback.
As always if you find bugs/ errors or if something just doesn't work as your expect it to, please let us know.
You can log a bug on GitHub or [provide feedback here][2].
Overview
Terraform plan expansion parses the output of terraform show -json and converts Azure resources from the AzAPI provider into ARM-format representations.
These are then evaluated by the same PSRule rules used for ARM templates and Bicep files.
Supported providers
Currently, the following Terraform providers are supported:
| Provider | Support |
|---|---|
AzAPI (azure/azapi) | azapi_resource and azapi_update_resource are converted to ARM format. |
AzureRM (hashicorp/azurerm) | Not yet supported. Planned for a future release. |
The AzAPI provider is a thin wrapper over the Azure ARM REST API, meaning its body property is already in ARM-compatible format.
This makes it the highest-fidelity provider for PSRule analysis.
Getting started
Step 1: Generate a Terraform plan
In your CI pipeline, generate a plan and export it as JSON:
terraform init
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
Step 2: Enable Terraform plan expansion
Add the following to your ps-rule.yaml configuration:
configuration:
AZURE_TERRAFORM_PLAN_EXPANSION: true
Step 3: Run PSRule
Analyze the plan JSON file with PSRule:
Assert-PSRule -InputPath './tfplan.json' -Format File -Module PSRule.Rules.Azure
Or using the CLI:
ps-rule run --input-path './tfplan.json' --module PSRule.Rules.Azure
How it works
When AZURE_TERRAFORM_PLAN_EXPANSION is enabled and a JSON file matching the Terraform plan schema is detected, PSRule:
- Parses the
planned_valuessection of the plan JSON. - Walks the module tree (including nested
child_modules). - For each
azapi_resourceorazapi_update_resourcewithmode: "managed", converts it to ARM format. - Imports the converted resources into PSRule for rule evaluation.
Resource conversion
The converter performs the following mappings from AzAPI to ARM format:
| AzAPI property | ARM property | Notes |
|---|---|---|
type (e.g., Microsoft.Storage/storageAccounts@2023-01-01) | type + apiVersion | Split at @ |
name | name | Direct |
location | location | Direct; omitted if null |
parent_id + type + name | id | Constructed resource ID |
body.* | Merged to resource root | properties, sku, etc. |
tags | tags | Top-level takes precedence over body.tags |
identity.type | identity.type | Direct |
identity.identity_ids | identity.userAssignedIdentities | Array converted to object |
Excluded resource types
The following are excluded from conversion:
- Data sources (
mode: "data") — Read-only lookups, not deployable resources. azapi_resource_action— Invokes POST actions, not a resource definition.azapi_data_plane_resource— Data plane operations don't map to ARM resources.- Non-Azure providers — Resources from
hashicorp/random,hashicorp/null, etc. are skipped.
Limitations
The following limitations apply to Terraform plan expansion:
- Only
azapi_resourceandazapi_update_resourcetypes are supported. Theazurermprovider is not yet supported. - Raw
.tffiles cannot be analyzed directly. You must first generate a plan JSON file. - Unknown-at-plan-time values — Properties that Terraform cannot resolve until after
apply(e.g., resource IDs, FQDNs) will be absent from analysis.- As a result, using the
hashicorp/randomto generate resource names dynamically is currently not supported.
- As a result, using the
- Ephemeral values — Terraform 1.10+ ephemeral values are redacted from plan JSON and will not be available.
- Sensitive values — Values marked as sensitive in Terraform are redacted in the plan JSON.
- No runtime property projection — Unlike Bicep expansion, runtime-only properties (e.g.,
principalId) are not projected. azapi_update_resourceonly contains the properties being updated, not the full resource definition.
Configuration
| Option | Type | Default | Description |
|---|---|---|---|
AZURE_TERRAFORM_PLAN_EXPANSION | bool | false | Enable expansion from Terraform plan JSON files. |