diff --git a/internal/services/firewall/firewall_data_source.go b/internal/services/firewall/firewall_data_source.go index 6d22b58d7ed5..edddb7274487 100644 --- a/internal/services/firewall/firewall_data_source.go +++ b/internal/services/firewall/firewall_data_source.go @@ -117,6 +117,12 @@ func firewallDataSource() *pluginsdk.Resource { }, }, + "dns_proxy_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + }, + "virtual_hub": { Type: pluginsdk.TypeList, Computed: true, @@ -192,7 +198,11 @@ func firewallDataSourceRead(d *pluginsdk.ResourceData, meta interface{}) error { d.Set("threat_intel_mode", string(pointer.From(props.ThreatIntelMode))) - if err := d.Set("dns_servers", flattenFirewallDNSServers(props.AdditionalProperties)); err != nil { + dnsProxyEnabeld, dnsServers := flattenFirewallAdditionalProperty(props.AdditionalProperties) + if err := d.Set("dns_proxy_enabled", dnsProxyEnabeld); err != nil { + return fmt.Errorf("setting `dns_proxy_enabled`: %+v", err) + } + if err := d.Set("dns_servers", dnsServers); err != nil { return fmt.Errorf("setting `dns_servers`: %+v", err) } diff --git a/internal/services/firewall/firewall_data_source_test.go b/internal/services/firewall/firewall_data_source_test.go index 2fde5ed25828..5ff09e5c66fe 100644 --- a/internal/services/firewall/firewall_data_source_test.go +++ b/internal/services/firewall/firewall_data_source_test.go @@ -153,7 +153,7 @@ data "azurerm_firewall" "test" { name = azurerm_firewall.test.name resource_group_name = azurerm_resource_group.test.name } -`, FirewallResource{}.enableDNS(data, dnsServers...)) +`, FirewallResource{}.enableDNS(data, true, dnsServers...)) } func (FirewallDataSource) withManagementIp(data acceptance.TestData) string { diff --git a/internal/services/firewall/firewall_network_rule_collection_resource_test.go b/internal/services/firewall/firewall_network_rule_collection_resource_test.go index 7bf643034612..09b97478fe75 100644 --- a/internal/services/firewall/firewall_network_rule_collection_resource_test.go +++ b/internal/services/firewall/firewall_network_rule_collection_resource_test.go @@ -879,7 +879,7 @@ resource "azurerm_firewall_network_rule_collection" "test" { ] } } -`, FirewallResource{}.enableDNS(data, "1.1.1.1", "8.8.8.8")) +`, FirewallResource{}.enableDNS(data, true, "1.1.1.1", "8.8.8.8")) } func (r FirewallNetworkRuleCollectionResource) noSource(data acceptance.TestData) string { diff --git a/internal/services/firewall/firewall_resource.go b/internal/services/firewall/firewall_resource.go index f54070c02bdb..bf9846f3e728 100644 --- a/internal/services/firewall/firewall_resource.go +++ b/internal/services/firewall/firewall_resource.go @@ -63,7 +63,7 @@ func resourceFirewall() *pluginsdk.Resource { "resource_group_name": commonschema.ResourceGroupName(), - //lintignore:S013 + // lintignore:S013 "sku_name": { Type: pluginsdk.TypeString, Required: true, @@ -74,7 +74,7 @@ func resourceFirewall() *pluginsdk.Resource { }, false), }, - //lintignore:S013 + // lintignore:S013 "sku_tier": { Type: pluginsdk.TypeString, Required: true, @@ -172,6 +172,12 @@ func resourceFirewall() *pluginsdk.Resource { }, }, + "dns_proxy_enabled": { + Type: pluginsdk.TypeBool, + Optional: true, + Computed: true, + }, + "private_ip_ranges": { Type: pluginsdk.TypeSet, Optional: true, @@ -327,7 +333,7 @@ func resourceFirewallCreateUpdate(d *pluginsdk.ResourceData, meta interface{}) e parameters.Properties.Sku.Tier = pointer.To(azurefirewalls.AzureFirewallSkuTier(skuTier)) } - if dnsServerSetting := expandFirewallDNSServers(d.Get("dns_servers").([]interface{})); dnsServerSetting != nil { + if dnsServerSetting := expandFirewallAdditionalProperty(d); dnsServerSetting != nil { for k, v := range dnsServerSetting { attrs := *parameters.Properties.AdditionalProperties attrs[k] = v @@ -429,7 +435,11 @@ func resourceFirewallRead(d *pluginsdk.ResourceData, meta interface{}) error { d.Set("threat_intel_mode", string(pointer.From(props.ThreatIntelMode))) - if err := d.Set("dns_servers", flattenFirewallDNSServers(props.AdditionalProperties)); err != nil { + dnsProxyEnabled, dnsServers := flattenFirewallAdditionalProperty(props.AdditionalProperties) + if err := d.Set("dns_proxy_enabled", dnsProxyEnabled); err != nil { + return fmt.Errorf("setting `dns_proxy_enabled`: %+v", err) + } + if err := d.Set("dns_servers", dnsServers); err != nil { return fmt.Errorf("setting `dns_servers`: %+v", err) } @@ -638,37 +648,38 @@ func flattenFirewallIPConfigurations(input *[]azurefirewalls.AzureFirewallIPConf return result } -func expandFirewallDNSServers(input []interface{}) map[string]string { - if len(input) == 0 { - return nil - } - - var servers []string - for _, server := range input { - servers = append(servers, server.(string)) - } - +func expandFirewallAdditionalProperty(d *pluginsdk.ResourceData) map[string]string { // Swagger issue asking finalize these properties: https://github.com/Azure/azure-rest-api-specs/issues/11278 - return map[string]string{ - "Network.DNS.EnableProxy": "true", - "Network.DNS.Servers": strings.Join(servers, ","), + res := map[string]string{} + if servers := d.Get("dns_servers").([]interface{}); len(servers) > 0 { + var servs []string + for _, server := range servers { + servs = append(servs, server.(string)) + } + res["Network.DNS.EnableProxy"] = "true" + res["Network.DNS.Servers"] = strings.Join(servs, ",") } + if enabled := d.Get("dns_proxy_enabled").(bool); enabled { + res["Network.DNS.EnableProxy"] = "true" + } + return res } -func flattenFirewallDNSServers(input *map[string]string) []interface{} { +func flattenFirewallAdditionalProperty(input *map[string]string) (enabled interface{}, servers []interface{}) { if input == nil || len(*input) == 0 { - return nil + return nil, nil } - attrs := *input - enabled := attrs["Network.DNS.EnableProxy"] == "true" - - if !enabled { - return nil + if enabledPtr, ok := (*input)["Network.DNS.EnableProxy"]; ok { + enabled = enabledPtr == "true" } - servers := strings.Split(attrs["Network.DNS.Servers"], ",") - return utils.FlattenStringSlice(&servers) + if serversPtr, ok := (*input)["Network.DNS.Servers"]; ok { + for _, val := range strings.Split(serversPtr, ",") { + servers = append(servers, val) + } + } + return } func expandFirewallPrivateIpRange(input []interface{}) map[string]string { diff --git a/internal/services/firewall/firewall_resource_test.go b/internal/services/firewall/firewall_resource_test.go index 12329ca15844..73ddaad8a542 100644 --- a/internal/services/firewall/firewall_resource_test.go +++ b/internal/services/firewall/firewall_resource_test.go @@ -68,14 +68,21 @@ func TestAccFirewall_enableDNS(t *testing.T) { }, data.ImportStep(), { - Config: r.enableDNS(data, "1.1.1.1", "8.8.8.8"), + Config: r.enableDNS(data, true, "1.1.1.1"), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), }, data.ImportStep(), { - Config: r.enableDNS(data, "1.1.1.1"), + Config: r.enableDNS(data, true), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.enableDNS(data, false), Check: acceptance.ComposeTestCheckFunc( check.That(data.ResourceName).ExistsInAzure(r), ), @@ -502,10 +509,20 @@ resource "azurerm_firewall" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } -func (FirewallResource) enableDNS(data acceptance.TestData, dnsServers ...string) string { - servers := make([]string, len(dnsServers)) - for idx, server := range dnsServers { - servers[idx] = fmt.Sprintf(`"%s"`, server) +func (FirewallResource) enableDNS(data acceptance.TestData, enableProxy bool, dnsServers ...string) string { + dnsServersStr := "" + if len(dnsServers) > 0 { + servers := make([]string, len(dnsServers)) + for idx, server := range dnsServers { + servers[idx] = fmt.Sprintf(`"%s"`, server) + } + dnsServersStr = fmt.Sprintf("dns_servers = [%s]", strings.Join(servers, ", ")) + } + enableProxyStr := "" + if enableProxy { + enableProxyStr = "dns_proxy_enabled = true" + } else { + enableProxyStr = "dns_proxy_enabled = false" } return fmt.Sprintf(` @@ -553,9 +570,11 @@ resource "azurerm_firewall" "test" { public_ip_address_id = azurerm_public_ip.test.id } threat_intel_mode = "Deny" - dns_servers = [%s] + %s + %s } -`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, strings.Join(servers, ",")) +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, + dnsServersStr, enableProxyStr) } func (FirewallResource) withManagementIp(data acceptance.TestData) string { diff --git a/website/docs/d/firewall.html.markdown b/website/docs/d/firewall.html.markdown index 796b5eb26ef8..e53595b730fa 100644 --- a/website/docs/d/firewall.html.markdown +++ b/website/docs/d/firewall.html.markdown @@ -48,6 +48,8 @@ The following attributes are exported: * `dns_servers` - The list of DNS servers that the Azure Firewall will direct DNS traffic to for name resolution. +* `dns_proxy_enabled` - Whether DNS proxy is enabled. It will forward DNS requests to the DNS servers when it is `true`. + * `management_ip_configuration` - A `management_ip_configuration` block as defined below, which allows force-tunnelling of traffic to be performed by the firewall. * `threat_intel_mode` - The operation mode for threat intelligence-based filtering. diff --git a/website/docs/r/firewall.html.markdown b/website/docs/r/firewall.html.markdown index 894829d2db94..bf4acb9670b4 100644 --- a/website/docs/r/firewall.html.markdown +++ b/website/docs/r/firewall.html.markdown @@ -76,6 +76,8 @@ The following arguments are supported: * `dns_servers` - (Optional) A list of DNS servers that the Azure Firewall will direct DNS traffic to the for name resolution. +* `dns_proxy_enabled` - (Optional) Whether DNS proxy is enabled. It will forward DNS requests to the DNS servers when set to `true`. It will be set to `true` if `dns_servers` provided with a not empty list. + * `private_ip_ranges` - (Optional) A list of SNAT private CIDR IP ranges, or the special string `IANAPrivateRanges`, which indicates Azure Firewall does not SNAT when the destination IP address is a private range per IANA RFC 1918. * `management_ip_configuration` - (Optional) A `management_ip_configuration` block as documented below, which allows force-tunnelling of traffic to be performed by the firewall. Adding or removing this block or changing the `subnet_id` in an existing block forces a new resource to be created. Changing this forces a new resource to be created.