I want to loop through the results of a (looped) data source that gets my VM IPs and add them to an IP rule on an Azure Container Registry. Neither approach here works but I feel like something close should but can't find a way. The data source is working fine. Its just using for_each to loop through and add the IPs to the ACR firewall that I'm having trouble with.
variable "vmips" {
type = map(any)
default = {
"vm1" = "rg1",
"vm2" = "rg2
}
}
data "azurerm_public_ip" "vmips" {
for_each = var.vmips
name = each.key
resource_group_name = each.value
}
resource "azurerm_container_registry" "acr" {
name = "MyAcR"
resource_group_name = "myrg"
location = "uksouth"
sku = "Premium"
admin_enabled = false
public_network_access_enabled = false
network_rule_set {
default_action = "Deny"
ip_rule {
for_each = var.vmips
action = "Allow"
ip_range = data.azurerm_public_ip.vmips[each.key].ip_address
}
# or
dynamic "ip_rule" {
for_each = var.vmips
content {
action = "Allow"
ip_range = data.azurerm_public_ip.vmips[each.key].ip_address
}
}
}
}
When you use dynamic blocks the context of iteration is limited to the block itself. In your use case particularly network_rule_set
can be only one block as per documentation however, ip_rule
can be one or more blocks.
The below code can be used to deploy the acr
with multiple ip_rules as you intend.
variable "vmips" {
type = map(string)
default = {
"vm01" = "stackoverflow-ip-01", ## value can be rg as you intend when using data source.
"vm02" = "stackoverflow-ip-02", ## value can be rg as you intend when using data source.
}
}
resource "azurerm_resource_group" "stackoverflow" {
name = "stackoverflow-rg"
location = "West Europe"
}
## I have used normal resource but the data source will be exactly the same with correct referencing.
resource "azurerm_public_ip" "vmips" {
for_each = var.vmips
name = each.value
resource_group_name = azurerm_resource_group.stackoverflow.name
location = azurerm_resource_group.stackoverflow.location
allocation_method = "Static"
}
resource "azurerm_container_registry" "acr" {
name = "mymostuniqueacr001" ## has to be globally unique
resource_group_name = azurerm_resource_group.stackoverflow.name ## adjust accordingly
location = azurerm_resource_group.stackoverflow.location adjust accordingly
sku = "Premium"
admin_enabled = false
public_network_access_enabled = false
### This is the interesting section ###
dynamic "network_rule_set" {
for_each = length(var.vmips) > 0 ? ["only_one_network_rule_set_is_allowed"] : []
content {
default_action = "Deny"
dynamic "ip_rule" {
for_each = var.vmips
content {
action = "Allow"
ip_range = azurerm_public_ip.vmips[ip_rule.key].ip_address
}
}
}
}
}
official documentation for dynamic blocks: https://developer.hashicorp.com/terraform/language/expressions/dynamic-blocks
Apart from that there seems to be a copy-paste error too in your variable definition.
variable "vmips" {
type = map(any)
default = {
"vm1" = "rg1",
"vm2" = "rg2" ### " is missing ###
}
}
Hope it helps :)