diff --git a/internal/services/firewall/firewall_policy_rule_collection_group_resource.go b/internal/services/firewall/firewall_policy_rule_collection_group_resource.go index bafdc6094e86..521432e3e6f0 100644 --- a/internal/services/firewall/firewall_policy_rule_collection_group_resource.go +++ b/internal/services/firewall/firewall_policy_rule_collection_group_resource.go @@ -8,6 +8,7 @@ import ( "github.com/Azure/azure-sdk-for-go/services/network/mgmt/2021-02-01/network" "github.com/hashicorp/go-azure-helpers/response" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" azValidate "github.com/hashicorp/terraform-provider-azurerm/helpers/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" @@ -15,7 +16,6 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" - "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" "github.com/hashicorp/terraform-provider-azurerm/internal/timeouts" "github.com/hashicorp/terraform-provider-azurerm/utils" ) @@ -95,9 +95,14 @@ func resourceFirewallPolicyRuleCollectionGroup() *pluginsdk.Resource { Required: true, ValidateFunc: validate.FirewallPolicyRuleName(), }, + "description": { + Type: pluginsdk.TypeString, + Optional: true, + ValidateFunc: validate.FirewallPolicyRuleName(), + }, "protocols": { Type: pluginsdk.TypeSet, - Required: true, + Optional: true, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "type": { @@ -136,6 +141,18 @@ func resourceFirewallPolicyRuleCollectionGroup() *pluginsdk.Resource { ValidateFunc: validation.StringIsNotEmpty, }, }, + "destination_addresses": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.Any( + validation.IsIPAddress, + validation.IsCIDR, + validation.StringInSlice([]string{`*`}, false), + ), + }, + }, "destination_fqdns": { Type: pluginsdk.TypeSet, Optional: true, @@ -144,6 +161,14 @@ func resourceFirewallPolicyRuleCollectionGroup() *pluginsdk.Resource { ValidateFunc: validation.StringIsNotEmpty, }, }, + "destination_urls": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, "destination_fqdn_tags": { Type: pluginsdk.TypeSet, Optional: true, @@ -152,6 +177,18 @@ func resourceFirewallPolicyRuleCollectionGroup() *pluginsdk.Resource { ValidateFunc: validation.StringIsNotEmpty, }, }, + "terminate_tls": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "web_categories": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringIsNotEmpty, + }, + }, }, }, }, @@ -564,13 +601,18 @@ func expandFirewallPolicyRuleApplication(input []interface{}) *[]network.BasicFi }) } output := &network.ApplicationRule{ - Name: utils.String(condition["name"].(string)), - RuleType: network.RuleTypeApplicationRule, - Protocols: &protocols, - SourceAddresses: utils.ExpandStringSlice(condition["source_addresses"].(*pluginsdk.Set).List()), - SourceIPGroups: utils.ExpandStringSlice(condition["source_ip_groups"].(*pluginsdk.Set).List()), - TargetFqdns: utils.ExpandStringSlice(condition["destination_fqdns"].(*pluginsdk.Set).List()), - FqdnTags: utils.ExpandStringSlice(condition["destination_fqdn_tags"].(*pluginsdk.Set).List()), + Name: utils.String(condition["name"].(string)), + Description: utils.String(condition["description"].(string)), + RuleType: network.RuleTypeApplicationRule, + Protocols: &protocols, + SourceAddresses: utils.ExpandStringSlice(condition["source_addresses"].(*pluginsdk.Set).List()), + SourceIPGroups: utils.ExpandStringSlice(condition["source_ip_groups"].(*pluginsdk.Set).List()), + DestinationAddresses: utils.ExpandStringSlice(condition["destination_addresses"].(*pluginsdk.Set).List()), + TargetFqdns: utils.ExpandStringSlice(condition["destination_fqdns"].(*pluginsdk.Set).List()), + TargetUrls: utils.ExpandStringSlice(condition["destination_urls"].(*pluginsdk.Set).List()), + FqdnTags: utils.ExpandStringSlice(condition["destination_fqdn_tags"].(*pluginsdk.Set).List()), + TerminateTLS: utils.Bool(condition["terminate_tls"].(bool)), + WebCategories: utils.ExpandStringSlice(condition["web_categories"].(*pluginsdk.Set).List()), } result = append(result, output) } @@ -739,6 +781,16 @@ func flattenFirewallPolicyRuleApplication(input *[]network.BasicFirewallPolicyRu name = *rule.Name } + var description string + if rule.Description != nil { + description = *rule.Description + } + + var terminate_tls bool + if rule.TerminateTLS != nil { + terminate_tls = *rule.TerminateTLS + } + protocols := make([]interface{}, 0) if rule.Protocols != nil { for _, protocol := range *rule.Protocols { @@ -755,11 +807,16 @@ func flattenFirewallPolicyRuleApplication(input *[]network.BasicFirewallPolicyRu output = append(output, map[string]interface{}{ "name": name, + "description": description, "protocols": protocols, "source_addresses": utils.FlattenStringSlice(rule.SourceAddresses), "source_ip_groups": utils.FlattenStringSlice(rule.SourceIPGroups), + "destination_addresses": utils.FlattenStringSlice(rule.DestinationAddresses), + "destination_urls": utils.FlattenStringSlice(rule.TargetUrls), "destination_fqdns": utils.FlattenStringSlice(rule.TargetFqdns), "destination_fqdn_tags": utils.FlattenStringSlice(rule.FqdnTags), + "terminate_tls": terminate_tls, + "web_categories": utils.FlattenStringSlice(rule.WebCategories), }) } diff --git a/internal/services/firewall/firewall_policy_rule_collection_group_resource_test.go b/internal/services/firewall/firewall_policy_rule_collection_group_resource_test.go index 26ba5816d7aa..32d52379524d 100644 --- a/internal/services/firewall/firewall_policy_rule_collection_group_resource_test.go +++ b/internal/services/firewall/firewall_policy_rule_collection_group_resource_test.go @@ -46,6 +46,21 @@ func TestAccFirewallPolicyRuleCollectionGroup_complete(t *testing.T) { }) } +func TestAccFirewallPolicyRuleCollectionGroup_completePremium(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_firewall_policy_rule_collection_group", "test") + r := FirewallPolicyRuleCollectionGroupResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.completePremium(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccFirewallPolicyRuleCollectionGroup_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_firewall_policy_rule_collection_group", "test") r := FirewallPolicyRuleCollectionGroupResource{} @@ -75,6 +90,35 @@ func TestAccFirewallPolicyRuleCollectionGroup_update(t *testing.T) { }) } +func TestAccFirewallPolicyRuleCollectionGroup_updatePremium(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_firewall_policy_rule_collection_group", "test") + r := FirewallPolicyRuleCollectionGroupResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.completePremium(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.updatePremium(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + { + Config: r.completePremium(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccFirewallPolicyRuleCollectionGroup_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_firewall_policy_rule_collection_group", "test") r := FirewallPolicyRuleCollectionGroupResource{} @@ -109,18 +153,15 @@ func (FirewallPolicyRuleCollectionGroupResource) basic(data acceptance.TestData) provider "azurerm" { features {} } - resource "azurerm_resource_group" "test" { name = "acctestRG-fwpolicy-RCG-%[1]d" location = "%[2]s" } - resource "azurerm_firewall_policy" "test" { name = "acctest-fwpolicy-RCG-%[1]d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location } - resource "azurerm_firewall_policy_rule_collection_group" "test" { name = "acctest-fwpolicy-RCG-%[1]d" firewall_policy_id = azurerm_firewall_policy.test.id @@ -134,12 +175,10 @@ func (FirewallPolicyRuleCollectionGroupResource) complete(data acceptance.TestDa provider "azurerm" { features {} } - resource "azurerm_resource_group" "test" { name = "acctestRG-fwpolicy-RCG-%[1]d" location = "%[2]s" } - resource "azurerm_firewall_policy" "test" { name = "acctest-fwpolicy-RCG-%[1]d" resource_group_name = azurerm_resource_group.test.name @@ -149,21 +188,18 @@ resource "azurerm_firewall_policy" "test" { proxy_enabled = true } } - resource "azurerm_ip_group" "test_source" { name = "acctestIpGroupForFirewallPolicySource" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name cidrs = ["1.2.3.4/32", "12.34.56.0/24"] } - resource "azurerm_ip_group" "test_destination" { name = "acctestIpGroupForFirewallPolicyDest" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name cidrs = ["192.168.0.0/25", "192.168.0.192/26"] } - resource "azurerm_firewall_policy_rule_collection_group" "test" { name = "acctest-fwpolicy-RCG-%[1]d" firewall_policy_id = azurerm_firewall_policy.test.id @@ -212,7 +248,6 @@ resource "azurerm_firewall_policy_rule_collection_group" "test" { destination_fqdn_tags = ["WindowsDiagnostics"] } } - network_rule_collection { name = "network_rule_collection1" priority = 400 @@ -246,7 +281,6 @@ resource "azurerm_firewall_policy_rule_collection_group" "test" { destination_ports = ["*"] } } - nat_rule_collection { name = "nat_rule_collection1" priority = 300 @@ -279,12 +313,10 @@ func (FirewallPolicyRuleCollectionGroupResource) update(data acceptance.TestData provider "azurerm" { features {} } - resource "azurerm_resource_group" "test" { name = "acctestRG-fwpolicy-RCG-%[1]d" location = "%[2]s" } - resource "azurerm_firewall_policy" "test" { name = "acctest-fwpolicy-RCG-%[1]d" resource_group_name = azurerm_resource_group.test.name @@ -294,21 +326,18 @@ resource "azurerm_firewall_policy" "test" { proxy_enabled = true } } - resource "azurerm_ip_group" "test_source" { name = "acctestIpGroupForFirewallPolicySource" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name cidrs = ["1.2.3.4/32", "12.34.56.0/24"] } - resource "azurerm_ip_group" "test_destination" { name = "acctestIpGroupForFirewallPolicyDest" location = azurerm_resource_group.test.location resource_group_name = azurerm_resource_group.test.name cidrs = ["192.168.0.0/25", "192.168.0.192/26"] } - resource "azurerm_firewall_policy_rule_collection_group" "test" { name = "acctest-fwpolicy-RCG-%[1]d" firewall_policy_id = azurerm_firewall_policy.test.id @@ -353,7 +382,6 @@ resource "azurerm_firewall_policy_rule_collection_group" "test" { destination_fqdn_tags = ["WindowsDiagnostics"] } } - network_rule_collection { name = "network_rule_collection1" priority = 400 @@ -387,7 +415,294 @@ resource "azurerm_firewall_policy_rule_collection_group" "test" { destination_ports = ["*"] } } + nat_rule_collection { + name = "nat_rule_collection1" + priority = 300 + action = "Dnat" + rule { + name = "nat_rule_collection1_rule1" + protocols = ["TCP", "UDP"] + source_addresses = ["10.0.0.1", "10.0.0.2"] + destination_address = "192.168.1.1" + destination_ports = ["80"] + translated_address = "192.168.0.1" + translated_port = "8080" + } + } +} +`, data.RandomInteger, data.Locations.Primary) +} +func (FirewallPolicyRuleCollectionGroupResource) completePremium(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-fwpolicy-RCG-%[1]d" + location = "%[2]s" +} +resource "azurerm_firewall_policy" "test" { + name = "acctest-fwpolicy-RCG-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + sku = "Premium" + dns { + network_rule_fqdn_enabled = false + proxy_enabled = true + } +} +resource "azurerm_ip_group" "test_source" { + name = "acctestIpGroupForFirewallPolicySource" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + cidrs = ["1.2.3.4/32", "12.34.56.0/24"] +} +resource "azurerm_ip_group" "test_destination" { + name = "acctestIpGroupForFirewallPolicyDest" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + cidrs = ["192.168.0.0/25", "192.168.0.192/26"] +} +resource "azurerm_firewall_policy_rule_collection_group" "test" { + name = "acctest-fwpolicy-RCG-%[1]d" + firewall_policy_id = azurerm_firewall_policy.test.id + priority = 500 + application_rule_collection { + name = "app_rule_collection1" + priority = 500 + action = "Deny" + rule { + name = "app_rule_collection1_rule1" + description = "app_rule_collection1_rule1" + protocols { + type = "Http" + port = 80 + } + protocols { + type = "Https" + port = 443 + } + source_addresses = ["10.0.0.1"] + destination_addresses = ["10.0.0.1"] + destination_urls = ["www.google.com/en"] + terminate_tls = true + web_categories = ["News"] + } + rule { + name = "app_rule_collection1_rule2" + description = "app_rule_collection1_rule2" + protocols { + type = "Http" + port = 80 + } + protocols { + type = "Https" + port = 443 + } + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_addresses = ["10.0.0.1"] + destination_fqdns = ["pluginsdk.io"] + terminate_tls = true + web_categories = ["News"] + } + rule { + name = "app_rule_collection1_rule3" + description = "app_rule_collection1_rule3" + protocols { + type = "Http" + port = 80 + } + protocols { + type = "Https" + port = 443 + } + source_addresses = ["10.0.0.1"] + destination_addresses = ["10.0.0.1"] + destination_urls = ["www.google.com/en"] + terminate_tls = true + web_categories = ["News"] + } + } + network_rule_collection { + name = "network_rule_collection1" + priority = 400 + action = "Deny" + rule { + name = "network_rule_collection1_rule1" + protocols = ["TCP", "UDP"] + source_addresses = ["10.0.0.1"] + destination_addresses = ["192.168.1.1", "ApiManagement"] + destination_ports = ["80", "1000-2000"] + } + rule { + name = "network_rule_collection1_rule2" + protocols = ["TCP", "UDP"] + source_addresses = ["10.0.0.1"] + destination_fqdns = ["time.windows.com"] + destination_ports = ["80", "1000-2000"] + } + rule { + name = "network_rule_collection1_rule3" + protocols = ["TCP", "UDP"] + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_ip_groups = [azurerm_ip_group.test_destination.id] + destination_ports = ["80", "1000-2000"] + } + rule { + name = "network_rule_collection1_rule4" + protocols = ["ICMP"] + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_ip_groups = [azurerm_ip_group.test_destination.id] + destination_ports = ["*"] + } + } + nat_rule_collection { + name = "nat_rule_collection1" + priority = 300 + action = "Dnat" + rule { + name = "nat_rule_collection1_rule1" + protocols = ["TCP", "UDP"] + source_addresses = ["10.0.0.1", "10.0.0.2"] + destination_address = "192.168.1.1" + destination_ports = ["80"] + translated_address = "192.168.0.1" + translated_port = "8080" + } + rule { + name = "nat_rule_collection1_rule2" + protocols = ["TCP", "UDP"] + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_address = "192.168.1.1" + destination_ports = ["80"] + translated_address = "192.168.0.1" + translated_port = "8080" + } + } +} +`, data.RandomInteger, data.Locations.Primary) +} + +func (FirewallPolicyRuleCollectionGroupResource) updatePremium(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} +resource "azurerm_resource_group" "test" { + name = "acctestRG-fwpolicy-RCG-%[1]d" + location = "%[2]s" +} +resource "azurerm_firewall_policy" "test" { + name = "acctest-fwpolicy-RCG-%[1]d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + dns { + network_rule_fqdn_enabled = false + proxy_enabled = true + } +} +resource "azurerm_ip_group" "test_source" { + name = "acctestIpGroupForFirewallPolicySource" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + cidrs = ["1.2.3.4/32", "12.34.56.0/24"] +} +resource "azurerm_ip_group" "test_destination" { + name = "acctestIpGroupForFirewallPolicyDest" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + cidrs = ["192.168.0.0/25", "192.168.0.192/26"] +} +resource "azurerm_firewall_policy_rule_collection_group" "test" { + name = "acctest-fwpolicy-RCG-%[1]d" + firewall_policy_id = azurerm_firewall_policy.test.id + priority = 500 + application_rule_collection { + name = "app_rule_collection1" + priority = 500 + action = "Deny" + rule { + name = "app_rule_collection1_rule1" + description = "app_rule_collection1_rule1" + protocols { + type = "Http" + port = 80 + } + protocols { + type = "Https" + port = 443 + } + source_addresses = ["10.0.0.1"] + destination_addresses = ["10.0.0.1"] + destination_urls = ["www.google.com/en"] + terminate_tls = true + web_categories = ["News"] + } + rule { + name = "app_rule_collection1_rule2" + description = "app_rule_collection1_rule2" + protocols { + type = "Http" + port = 80 + } + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_addresses = ["10.0.0.1"] + destination_fqdns = ["pluginsdk.io"] + terminate_tls = true + web_categories = ["News"] + } + rule { + name = "app_rule_collection1_rule3" + description = "app_rule_collection1_rule3" + protocols { + type = "Http" + port = 80 + } + protocols { + type = "Https" + port = 443 + } + source_addresses = ["10.0.0.1", "10.0.0.2"] + destination_addresses = ["10.0.0.1", "10.0.0.2"] + destination_urls = ["www.google.com/en"] + terminate_tls = true + web_categories = ["News"] + } + } + network_rule_collection { + name = "network_rule_collection1" + priority = 400 + action = "Deny" + rule { + name = "network_rule_collection1_rule1" + protocols = ["TCP", "UDP"] + source_addresses = ["10.0.0.1"] + destination_addresses = ["192.168.1.2", "ApiManagement"] + destination_ports = ["80", "1-65535"] + } + rule { + name = "network_rule_collection1_rule2" + protocols = ["TCP", "UDP"] + source_addresses = ["10.0.0.1", "10.0.0.2"] + destination_fqdns = ["time.windows.com"] + destination_ports = ["80", "1-65535"] + } + rule { + name = "network_rule_collection1_rule3" + protocols = ["TCP"] + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_ip_groups = [azurerm_ip_group.test_destination.id] + destination_ports = ["80", "1-65535"] + } + rule { + name = "network_rule_collection1_rule4" + protocols = ["ICMP"] + source_ip_groups = [azurerm_ip_group.test_source.id] + destination_ip_groups = [azurerm_ip_group.test_destination.id] + destination_ports = ["*"] + } + } nat_rule_collection { name = "nat_rule_collection1" priority = 300 @@ -410,7 +725,6 @@ func (FirewallPolicyRuleCollectionGroupResource) requiresImport(data acceptance. template := FirewallPolicyRuleCollectionGroupResource{}.basic(data) return fmt.Sprintf(` %s - resource "azurerm_firewall_policy_rule_collection_group" "import" { name = azurerm_firewall_policy_rule_collection_group.test.name firewall_policy_id = azurerm_firewall_policy_rule_collection_group.test.firewall_policy_id diff --git a/website/docs/r/firewall_policy_rule_collection_group.html.markdown b/website/docs/r/firewall_policy_rule_collection_group.html.markdown index 0fa32ceae71e..259d6f0b355a 100644 --- a/website/docs/r/firewall_policy_rule_collection_group.html.markdown +++ b/website/docs/r/firewall_policy_rule_collection_group.html.markdown @@ -137,16 +137,27 @@ A `rule` (application rule) block supports the following: * `name` - (Required) The name which should be used for this rule. -* `protocols` - (Required) One or more `protocols` blocks as defined below. +* `description` - (Optional) The description which should be used for this rule. + +* `protocols` - (Optional) One or more `protocols` blocks as defined below. Not required when specifying `destination_fqdn_tags`, but required when specifying `destination_fqdns`. * `source_addresses` - (Optional) Specifies a list of source IP addresses (including CIDR and `*`). * `source_ip_groups` - (Optional) Specifies a list of source IP groups. -* `destination_fqdns` - (Optional) Specifies a list of destination FQDNs. +* `destination_addresses` - (Optional) Specifies a list of destination IP addresses (including CIDR and `*`). + +* `destination_urls` - (Optional) Specifies a list of destination URLs for which policy should hold. Needs Premium SKU for Firewall Policy. Conflicts with `destination_fqdns`. + +* `destination_fqdns` - (Optional) Specifies a list of destination FQDNs. Conflicts with `destination_urls`. * `destination_fqdn_tags` - (Optional) Specifies a list of destination FQDN tags. +* `terminate_tls` - (Optional) Boolean specifying if TLS shall be terminated (true) or not (false). Needs Premium SKU for Firewall Policy. + +* `web_categories` - (Optional) Specifies a list of web categories to which access is denied or allowed depending on the value of `action` above. Needs Premium SKU for Firewall Policy. + + --- A `rule` (network rule) block supports the following: