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:

ProviderSupport
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:

  1. Parses the planned_values section of the plan JSON.
  2. Walks the module tree (including nested child_modules).
  3. For each azapi_resource or azapi_update_resource with mode: "managed", converts it to ARM format.
  4. Imports the converted resources into PSRule for rule evaluation.

Resource conversion

The converter performs the following mappings from AzAPI to ARM format:

AzAPI propertyARM propertyNotes
type (e.g., Microsoft.Storage/storageAccounts@2023-01-01)type + apiVersionSplit at @
namenameDirect
locationlocationDirect; omitted if null
parent_id + type + nameidConstructed resource ID
body.*Merged to resource rootproperties, sku, etc.
tagstagsTop-level takes precedence over body.tags
identity.typeidentity.typeDirect
identity.identity_idsidentity.userAssignedIdentitiesArray 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_resource and azapi_update_resource types are supported. The azurerm provider is not yet supported.
  • Raw .tf files 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/random to generate resource names dynamically is currently not supported.
  • 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_resource only contains the properties being updated, not the full resource definition.

Configuration

OptionTypeDefaultDescription
AZURE_TERRAFORM_PLAN_EXPANSIONboolfalseEnable expansion from Terraform plan JSON files.