Fix plan noise for Application Gateway plans
How AzAPI list-aware properties fix the plan noise that makes shared Application Gateways painful to manage.
Have you ever used Terraform to manage Application Gateway as a shared service?
If you have, you probably already know the pain of noisy plans. HashiCorp call it out in their documentation:

In summary, the error says - yes, the plan is noisy, but as long as nothing has changed, the provider will work it out.
That’s great, but it doesn’t inspire confidence when reviewing changes.
In this article, I’m going to show you a new way to fix this problem, using capabilities just released in the Terraform AzAPI provider.
Why does the problem exist?
Everything in an App Gateway is a list. Listeners, backend pools, routing rules, probes, SSL certificates, frontend ports. There is one set of lists for all the applications in the gateway.
AzureRM treats lists as a set, stored with a hash, which means any item changed in the list leads to multiple instances of adds and removes, and the noisy plans.
What if you could treat it as a map instead (or a dictionary, if you prefer that lingo), every item in the list is given a key? Then it doesn’t matter if you add or remove items, because maps are not sensitive to ordering changes.
You might think - ok - I can just define my resources as maps in Terraform, pass them to the App Gateway, wouldn’t that work? Well no - because the issue is how the Azure API returns the results.
We need a way to instruct the response from the API to add a key to each list, so we can fix the ordering sensitivity.
The fix
Matt White raised issue #995 on the AzAPI provider, which drove the design. I contributed the fix, and this has just landed in AzAPI v2.9.0.
This new version has two new resource properties:
| |
list_unique_id_property allow us to nominate a particular property in a list
as the key, rather than matching by position (index 0, index 1…), or hashing the entire list (as AzureRM does).
It was added to fix a behaviour in diagnostic settings (a post for another day), but as it turns out, it applies to other services too.
Scaling up to Application Gateway
Let’s apply this to Application Gateway. Here’s the relevant block:
| |
Each sub-resource type gets its own entry. Most use name as the
unique key, which makes sense because ARM sub-resources are uniquely
identified by name. The nested backendAddresses list doesn’t have a
name field, so it uses ipAddress instead.
You can also combine multiple properties (comma-separated), but for our use case, one property is sufficient to uniquely identify the list items.
Can I try it out?
This AzAPI Application Gateway module is an AVM-style resource module that illustrates this (written using tfmodmake). You can use this in your own solutions today. I am intending to share this upstream with the AVM team (a few queries before I’m ready to PR).
In part 2, I’ll share a configuration-driven shared app gateway solution that takes advantage of this, but for now, here’s a video teaser:
