Terraform – Concat + formatlist multiple lists

An issue I ran in to recently was that I needed to assign multiple lists to the ip_rules block of an Azure Key Vault in Terraform. Doing so was easy enough using Terraform’s concat function. Initially, the use case was simple… combine three lists that were stored as variables.

ip_rules = "${concat(var.list1, var.list2, var.list3)}"

I then ran in to a frustrating problem. Each of these lists contain one or more static IP addresses without a subnet prefix. In other words, 1.2.3.4, 2.4.6.8, etc. as opposed to 1.2.34./32, 2.4.6.8/32. An Azure Key Vault will accept this non-classed IP address no problem, but if you then look in the portal at the IP rules, you’ll notice that Azure has appended a /32 suffix for you. What’s the problem, then? The issue is that when you re-run Terraform, your deployment sees that there has been a change (the /32 now exists) and so it wants to strip that out to remain consistent with the contents of the state file. And you can safely apply that change without breaking the access list. It just creates an annoying Terraform loop that would be better off dead.

Why not add /32 to the lists? I would like to re-use these same lists for Storage Account access lists and as it turns out, a Storage Account access list will not accept the /32 prefix! Using the formatlist function is helpful here:

formatlist("%s/32", var.list1)

Now, just to concatenate and format all of the lists…

${concat(formatlist("%s/32", var.list1), formatlist("%s/32", var.list2), formatlist("%s/32", var.list3))

Unfortunately, this and other similar variants don’t seem to work. What does work, is concatenating your lists as a locals variable, and then using the formatlist against that variable:

locals {
keyvault_ip_rules = "${concat(var.list1, var.list2, var.list3)}"
}
ip_rules = formatlist("%s/32", local.keyvault_ip_rules)

Shout out to tstraub on the Azure Terraform Slack channel for helping out with this one.

Leave a comment

Close Bitnami banner
Bitnami