diff --git a/internal/services/firewall/firewall_policy_resource.go b/internal/services/firewall/firewall_policy_resource.go index 83941fb7e9e3..c7e2fd2b3e16 100644 --- a/internal/services/firewall/firewall_policy_resource.go +++ b/internal/services/firewall/firewall_policy_resource.go @@ -14,6 +14,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/internal/locks" "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall/parse" "github.com/hashicorp/terraform-provider-azurerm/internal/services/firewall/validate" + msiValidate "github.com/hashicorp/terraform-provider-azurerm/internal/services/msi/validate" "github.com/hashicorp/terraform-provider-azurerm/internal/tags" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk" "github.com/hashicorp/terraform-provider-azurerm/internal/tf/validation" @@ -142,6 +143,163 @@ func resourceFirewallPolicy() *pluginsdk.Resource { }, }, + "intrusion_detection": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "mode": { + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(network.FirewallPolicyIntrusionDetectionStateTypeOff), + string(network.FirewallPolicyIntrusionDetectionStateTypeAlert), + string(network.FirewallPolicyIntrusionDetectionStateTypeDeny), + }, false), + Optional: true, + }, + "signature_overrides": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "state": { + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(network.FirewallPolicyIntrusionDetectionStateTypeOff), + string(network.FirewallPolicyIntrusionDetectionStateTypeAlert), + string(network.FirewallPolicyIntrusionDetectionStateTypeDeny), + }, false), + Optional: true, + }, + "id": { + Type: pluginsdk.TypeString, + Optional: true, + }, + }, + }, + }, + "traffic_bypass": { + Type: pluginsdk.TypeList, + Optional: true, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + "description": { + Type: pluginsdk.TypeString, + Optional: true, + }, + "protocol": { + Type: pluginsdk.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.FirewallPolicyIntrusionDetectionProtocolICMP), + string(network.FirewallPolicyIntrusionDetectionProtocolANY), + string(network.FirewallPolicyIntrusionDetectionProtocolTCP), + string(network.FirewallPolicyIntrusionDetectionProtocolUDP), + }, true), + }, + "source_addresses": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + "destination_addresses": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + "destination_ports": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + "source_ip_groups": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + "destination_ip_groups": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + }, + }, + }, + }, + }, + }, + }, + }, + + "identity": { + Type: pluginsdk.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "type": { + Type: pluginsdk.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.ResourceIdentityTypeNone), + string(network.ResourceIdentityTypeUserAssigned), + }, false), + }, + "principal_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "tenant_id": { + Type: pluginsdk.TypeString, + Computed: true, + }, + "user_assigned_identity_ids": { + Type: pluginsdk.TypeSet, + Optional: true, + MinItems: 1, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: msiValidate.UserAssignedIdentityID, + }, + }, + }, + }, + }, + + "tls_certificate": { + Type: pluginsdk.TypeList, + Optional: true, + MaxItems: 1, + MinItems: 1, + Elem: &pluginsdk.Resource{ + Schema: map[string]*pluginsdk.Schema{ + "key_vault_secret_id": { + Type: pluginsdk.TypeString, + Required: true, + }, + "name": { + Type: pluginsdk.TypeString, + Required: true, + }, + }, + }, + }, + "child_policies": { Type: pluginsdk.TypeList, Computed: true, @@ -210,7 +368,10 @@ func resourceFirewallPolicyCreateUpdate(d *pluginsdk.ResourceData, meta interfac ThreatIntelMode: network.AzureFirewallThreatIntelMode(d.Get("threat_intelligence_mode").(string)), ThreatIntelWhitelist: expandFirewallPolicyThreatIntelWhitelist(d.Get("threat_intelligence_allowlist").([]interface{})), DNSSettings: expandFirewallPolicyDNSSetting(d.Get("dns").([]interface{})), + IntrusionDetection: expandFirewallPolicyIntrusionDetection(d.Get("intrusion_detection").([]interface{})), + TransportSecurity: expandFirewallPolicyTransportSecurity(d.Get("tls_certificate").([]interface{})), }, + Identity: expandFirewallPolicyIdentity(d.Get("identity").([]interface{})), Location: utils.String(location.Normalize(d.Get("location").(string))), Tags: tags.Expand(d.Get("tags").(map[string]interface{})), } @@ -225,9 +386,9 @@ func resourceFirewallPolicyCreateUpdate(d *pluginsdk.ResourceData, meta interfac } if v, ok := d.GetOk("private_ip_ranges"); ok { - privateIpRanges := utils.ExpandStringSlice(v.([]interface{})) + privateIPRanges := utils.ExpandStringSlice(v.([]interface{})) props.FirewallPolicyPropertiesFormat.Snat = &network.FirewallPolicySNAT{ - PrivateRanges: privateIpRanges, + PrivateRanges: privateIPRanges, } } @@ -296,6 +457,14 @@ func resourceFirewallPolicyRead(d *pluginsdk.ResourceData, meta interface{}) err return fmt.Errorf(`setting "dns": %+v`, err) } + if err := d.Set("intrusion_detection", flattenFirewallPolicyIntrusionDetection(resp.IntrusionDetection)); err != nil { + return fmt.Errorf(`setting "intrusion_detection": %+v`, err) + } + + if err := d.Set("tls_certificate", flattenFirewallPolicyTransportSecurity(prop.TransportSecurity)); err != nil { + return fmt.Errorf(`setting "tls_certificate": %+v`, err) + } + if err := d.Set("child_policies", flattenNetworkSubResourceID(prop.ChildPolicies)); err != nil { return fmt.Errorf(`setting "child_policies": %+v`, err) } @@ -308,15 +477,20 @@ func resourceFirewallPolicyRead(d *pluginsdk.ResourceData, meta interface{}) err return fmt.Errorf(`setting "rule_collection_groups": %+v`, err) } - var privateIpRanges []interface{} + var privateIPRanges []interface{} if prop.Snat != nil { - privateIpRanges = utils.FlattenStringSlice(prop.Snat.PrivateRanges) + privateIPRanges = utils.FlattenStringSlice(prop.Snat.PrivateRanges) } - if err := d.Set("private_ip_ranges", privateIpRanges); err != nil { + if err := d.Set("private_ip_ranges", privateIPRanges); err != nil { return fmt.Errorf("setting `private_ip_ranges`: %+v", err) } } + if err := d.Set("identity", flattenFirewallPolicyIdentity(resp.Identity)); err != nil { + return fmt.Errorf("flattening identity on Firewall Policy %q (Resource Group %q): %+v", + id.Name, id.ResourceGroup, err) + } + return tags.FlattenAndSet(d, resp.Tags) } @@ -374,6 +548,88 @@ func expandFirewallPolicyDNSSetting(input []interface{}) *network.DNSSettings { return output } +func expandFirewallPolicyIntrusionDetection(input []interface{}) *network.FirewallPolicyIntrusionDetection { + if len(input) == 0 || input[0] == nil { + return nil + } + + raw := input[0].(map[string]interface{}) + + var signatureOverrides []network.FirewallPolicyIntrusionDetectionSignatureSpecification + for _, v := range raw["signature_overrides"].([]interface{}) { + overrides := v.(map[string]interface{}) + signatureOverrides = append(signatureOverrides, network.FirewallPolicyIntrusionDetectionSignatureSpecification{ + ID: utils.String(overrides["id"].(string)), + Mode: network.FirewallPolicyIntrusionDetectionStateType(overrides["state"].(string)), + }) + } + + var trafficBypass []network.FirewallPolicyIntrusionDetectionBypassTrafficSpecifications + + for _, v := range raw["traffic_bypass"].([]interface{}) { + bypass := v.(map[string]interface{}) + trafficBypass = append(trafficBypass, network.FirewallPolicyIntrusionDetectionBypassTrafficSpecifications{ + Name: utils.String(bypass["name"].(string)), + Description: utils.String(bypass["description"].(string)), + Protocol: network.FirewallPolicyIntrusionDetectionProtocol(bypass["protocol"].(string)), + SourceAddresses: utils.ExpandStringSlice(bypass["source_addresses"].(*pluginsdk.Set).List()), + DestinationAddresses: utils.ExpandStringSlice(bypass["destination_addresses"].(*pluginsdk.Set).List()), + DestinationPorts: utils.ExpandStringSlice(bypass["destination_ports"].(*pluginsdk.Set).List()), + SourceIPGroups: utils.ExpandStringSlice(bypass["source_ip_groups"].(*pluginsdk.Set).List()), + DestinationIPGroups: utils.ExpandStringSlice(bypass["destination_ip_groups"].(*pluginsdk.Set).List()), + }) + } + + return &network.FirewallPolicyIntrusionDetection{ + Mode: network.FirewallPolicyIntrusionDetectionStateType(raw["mode"].(string)), + Configuration: &network.FirewallPolicyIntrusionDetectionConfiguration{ + SignatureOverrides: &signatureOverrides, + BypassTrafficSettings: &trafficBypass, + }, + } + +} + +func expandFirewallPolicyTransportSecurity(input []interface{}) *network.FirewallPolicyTransportSecurity { + if len(input) == 0 || input[0] == nil { + return nil + } + + raw := input[0].(map[string]interface{}) + + return &network.FirewallPolicyTransportSecurity{ + CertificateAuthority: &network.FirewallPolicyCertificateAuthority{ + KeyVaultSecretID: utils.String(raw["key_vault_secret_id"].(string)), + Name: utils.String(raw["name"].(string)), + }, + } +} + +func expandFirewallPolicyIdentity(input []interface{}) *network.ManagedServiceIdentity { + if len(input) == 0 { + return nil + } + + v := input[0].(map[string]interface{}) + + var identityIDSet []interface{} + if identityIds, exists := v["user_assigned_identity_ids"]; exists { + identityIDSet = identityIds.(*pluginsdk.Set).List() + } + + userAssignedIdentities := make(map[string]*network.ManagedServiceIdentityUserAssignedIdentitiesValue) + for _, id := range identityIDSet { + userAssignedIdentities[id.(string)] = &network.ManagedServiceIdentityUserAssignedIdentitiesValue{} + } + + return &network.ManagedServiceIdentity{ + Type: network.ResourceIdentityType(v["type"].(string)), + PrincipalID: utils.String(v["principal_id"].(string)), + TenantID: utils.String(v["tenant_id"].(string)), + UserAssignedIdentities: userAssignedIdentities, + } +} + func flattenFirewallPolicyThreatIntelWhitelist(input *network.FirewallPolicyThreatIntelWhitelist) []interface{} { if input == nil { return []interface{}{} @@ -406,3 +662,126 @@ func flattenFirewallPolicyDNSSetting(input *network.DNSSettings) []interface{} { }, } } + +func flattenFirewallPolicyIntrusionDetection(input *network.FirewallPolicyIntrusionDetection) []interface{} { + if input == nil { + return []interface{}{} + } + + signatureOverrides := make([]interface{}, 0) + if overrides := input.Configuration.SignatureOverrides; overrides != nil { + for _, override := range *overrides { + id := "" + if override.ID != nil { + id = *override.ID + } + signatureOverrides = append(signatureOverrides, map[string]interface{}{ + "id": id, + "state": string(override.Mode), + }) + } + } + + trafficBypass := make([]interface{}, 0) + if bypasses := input.Configuration.BypassTrafficSettings; bypasses != nil { + for _, bypass := range *bypasses { + name := "" + if bypass.Name != nil { + name = *bypass.Name + } + + description := "" + if bypass.Description != nil { + description = *bypass.Description + } + + sourceAddresses := make([]string, 0) + if bypass.SourceAddresses != nil { + sourceAddresses = *bypass.SourceAddresses + } + + destinationAddresses := make([]string, 0) + if bypass.DestinationAddresses != nil { + destinationAddresses = *bypass.DestinationAddresses + } + + destinationPorts := make([]string, 0) + if bypass.DestinationPorts != nil { + destinationPorts = *bypass.DestinationPorts + } + + sourceIPGroups := make([]string, 0) + if bypass.SourceIPGroups != nil { + sourceIPGroups = *bypass.SourceIPGroups + } + + destinationIPGroups := make([]string, 0) + if bypass.DestinationIPGroups != nil { + destinationIPGroups = *bypass.DestinationIPGroups + } + + trafficBypass = append(trafficBypass, map[string]interface{}{ + "name": name, + "description": description, + "protocol": string(bypass.Protocol), + "source_addresses": sourceAddresses, + "destination_addresses": destinationAddresses, + "destination_ports": destinationPorts, + "source_ip_groups": sourceIPGroups, + "destination_ip_groups": destinationIPGroups, + }) + } + } + + return []interface{}{ + map[string]interface{}{ + "mode": string(input.Mode), + "signature_overrides": signatureOverrides, + "traffic_bypass": trafficBypass, + }, + } +} + +func flattenFirewallPolicyTransportSecurity(input *network.FirewallPolicyTransportSecurity) []interface{} { + if input == nil { + return []interface{}{} + } + + return []interface{}{ + map[string]interface{}{ + "key_vault_secret_id": input.CertificateAuthority.KeyVaultSecretID, + "name": input.CertificateAuthority.Name, + }, + } +} + +func flattenFirewallPolicyIdentity(identity *network.ManagedServiceIdentity) []interface{} { + if identity == nil { + return []interface{}{} + } + + principalID := "" + if identity.PrincipalID != nil { + principalID = *identity.PrincipalID + } + + tenantID := "" + if identity.TenantID != nil { + tenantID = *identity.TenantID + } + + userAssignedIdentities := make([]string, 0) + + for id := range identity.UserAssignedIdentities { + userAssignedIdentities = append(userAssignedIdentities, id) + } + + return []interface{}{ + map[string]interface{}{ + "type": string(identity.Type), + "principal_id": principalID, + "tenant_id": tenantID, + "user_assigned_identity_ids": userAssignedIdentities, + }, + } +} diff --git a/internal/services/firewall/firewall_policy_resource_test.go b/internal/services/firewall/firewall_policy_resource_test.go index 3fb49294a79a..5c5adafe7012 100644 --- a/internal/services/firewall/firewall_policy_resource_test.go +++ b/internal/services/firewall/firewall_policy_resource_test.go @@ -61,6 +61,21 @@ func TestAccFirewallPolicy_complete(t *testing.T) { }) } +func TestAccFirewallPolicy_completePremium(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_firewall_policy", "test") + r := FirewallPolicyResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.completePremium(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccFirewallPolicy_update(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_firewall_policy", "test") r := FirewallPolicyResource{} @@ -90,6 +105,35 @@ func TestAccFirewallPolicy_update(t *testing.T) { }) } +func TestAccFirewallPolicy_updatePremium(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_firewall_policy", "test") + r := FirewallPolicyResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.basic(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(), + { + Config: r.basic(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func TestAccFirewallPolicy_requiresImport(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_firewall_policy", "test") r := FirewallPolicyResource{} @@ -135,10 +179,10 @@ func (FirewallPolicyResource) Exists(ctx context.Context, clients *clients.Clien } func (FirewallPolicyResource) basic(data acceptance.TestData) string { - template := FirewallPolicyResource{}.template(data) + r := FirewallPolicyResource{} + template := r.template(data) return fmt.Sprintf(` %s - resource "azurerm_firewall_policy" "test" { name = "acctest-networkfw-Policy-%d" resource_group_name = azurerm_resource_group.test.name @@ -148,10 +192,10 @@ resource "azurerm_firewall_policy" "test" { } func (FirewallPolicyResource) basicPremium(data acceptance.TestData) string { - template := FirewallPolicyResource{}.template(data) + r := FirewallPolicyResource{} + template := r.template(data) return fmt.Sprintf(` %s - resource "azurerm_firewall_policy" "test" { name = "acctest-networkfw-Policy-%d" resource_group_name = azurerm_resource_group.test.name @@ -162,14 +206,40 @@ resource "azurerm_firewall_policy" "test" { } func (FirewallPolicyResource) complete(data acceptance.TestData) string { - template := FirewallPolicyResource{}.template(data) + r := FirewallPolicyResource{} + template := r.template(data) return fmt.Sprintf(` %s +resource "azurerm_firewall_policy" "test" { + name = "acctest-networkfw-Policy-%d" + resource_group_name = azurerm_resource_group.test.name + location = azurerm_resource_group.test.location + threat_intelligence_mode = "Off" + threat_intelligence_allowlist { + ip_addresses = ["1.1.1.1", "2.2.2.2"] + fqdns = ["foo.com", "bar.com"] + } + dns { + servers = ["1.1.1.1", "2.2.2.2"] + proxy_enabled = true + } + tags = { + env = "Test" + } +} +`, template, data.RandomInteger) +} +func (FirewallPolicyResource) completePremium(data acceptance.TestData) string { + r := FirewallPolicyResource{} + template := r.templatePremium(data) + return fmt.Sprintf(` +%s resource "azurerm_firewall_policy" "test" { name = "acctest-networkfw-Policy-%d" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location + sku = "Premium" threat_intelligence_mode = "Off" threat_intelligence_allowlist { ip_addresses = ["1.1.1.1", "2.2.2.2"] @@ -179,6 +249,35 @@ resource "azurerm_firewall_policy" "test" { servers = ["1.1.1.1", "2.2.2.2"] proxy_enabled = true } + intrusion_detection { + mode = "Alert" + signature_overrides { + state = "Alert" + id = "1" + } + traffic_bypass { + name = "Name bypass traffic settings" + description = "Description bypass traffic settings" + protocol = "Any" + destination_ports = ["*"] + source_ip_groups = [ + azurerm_ip_group.test_source.id, + ] + destination_ip_groups = [ + azurerm_ip_group.test_destination.id, + ] + } + } + identity { + type = "UserAssigned" + user_assigned_identity_ids = [ + azurerm_user_assigned_identity.test.id, + ] + } + tls_certificate { + key_vault_secret_id = azurerm_key_vault_certificate.test.secret_id + name = azurerm_key_vault_certificate.test.name + } private_ip_ranges = ["172.16.0.0/12", "192.168.0.0/16"] tags = { env = "Test" @@ -188,10 +287,10 @@ resource "azurerm_firewall_policy" "test" { } func (FirewallPolicyResource) requiresImport(data acceptance.TestData) string { - template := FirewallPolicyResource{}.basic(data) + r := FirewallPolicyResource{} + template := r.basic(data) return fmt.Sprintf(` %s - resource "azurerm_firewall_policy" "import" { name = azurerm_firewall_policy.test.name resource_group_name = azurerm_firewall_policy.test.resource_group_name @@ -201,16 +300,15 @@ resource "azurerm_firewall_policy" "import" { } func (FirewallPolicyResource) inherit(data acceptance.TestData) string { - template := FirewallPolicyResource{}.template(data) + r := FirewallPolicyResource{} + template := r.template(data) return fmt.Sprintf(` %s - resource "azurerm_firewall_policy" "test-parent" { name = "acctest-networkfw-Policy-%d-parent" resource_group_name = azurerm_resource_group.test.name location = azurerm_resource_group.test.location } - resource "azurerm_firewall_policy" "test" { name = "acctest-networkfw-Policy-%d" resource_group_name = azurerm_resource_group.test.name @@ -236,10 +334,163 @@ func (FirewallPolicyResource) template(data acceptance.TestData) string { provider "azurerm" { features {} } - resource "azurerm_resource_group" "test" { name = "acctestRG-networkfw-%d" location = "%s" } `, data.RandomInteger, data.Locations.Primary) } + +func (FirewallPolicyResource) templatePremium(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +data "azurerm_client_config" "current" { +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-networkfw-%d" + location = "%s" +} + +resource "azurerm_key_vault" "test" { + name = "tlskv%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + enabled_for_disk_encryption = true + enabled_for_deployment = true + enabled_for_template_deployment = true + tenant_id = data.azurerm_client_config.current.tenant_id + sku_name = "standard" +} + +resource "azurerm_ip_group" "test_source" { + name = "acctestIpGroupForFirewallNetworkRulesSource" + 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 = "acctestIpGroupForFirewallNetworkRulesDestination" + 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_user_assigned_identity" "test" { + name = "acctestUAI-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_key_vault_access_policy" "test" { + key_vault_id = azurerm_key_vault.test.id + application_id = azurerm_user_assigned_identity.test.client_id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = azurerm_user_assigned_identity.test.principal_id + + key_permissions = [ + "backup", + "create", + "delete", + "get", + "import", + "list", + "purge", + "recover", + "restore", + "update" + ] + + certificate_permissions = [ + "backup", + "create", + "get", + "list", + "import", + "purge", + "delete", + "recover", + ] + + secret_permissions = [ + "get", + "list", + "set", + "purge", + "delete", + "recover" + ] +} + +resource "azurerm_key_vault_access_policy" "test2" { + key_vault_id = azurerm_key_vault.test.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + key_permissions = [ + "backup", + "create", + "delete", + "get", + "import", + "list", + "purge", + "recover", + "restore", + "update" + ] + + certificate_permissions = [ + "backup", + "create", + "get", + "list", + "import", + "purge", + "delete", + "recover", + ] + + secret_permissions = [ + "get", + "list", + "set", + "purge", + "delete", + "recover" + ] +} + +resource "azurerm_key_vault_certificate" "test" { + name = "AzureFirewallPolicyCertificate" + key_vault_id = azurerm_key_vault.test.id + + certificate { + contents = filebase64("testdata/certificate.pfx") + } + + certificate_policy { + issuer_parameters { + name = "Self" + } + + key_properties { + exportable = true + key_size = 2048 + key_type = "RSA" + reuse_key = false + } + + secret_properties { + content_type = "application/x-pkcs12" + } + } + + depends_on = [azurerm_key_vault_access_policy.test2] +} +`, data.RandomInteger, "westeurope", data.RandomInteger, data.RandomInteger) +} diff --git a/internal/services/firewall/testdata/HOWTO.md b/internal/services/firewall/testdata/HOWTO.md new file mode 100644 index 000000000000..0ec5e949e0f9 --- /dev/null +++ b/internal/services/firewall/testdata/HOWTO.md @@ -0,0 +1,11 @@ +# How Certificates were generated + +## How Key and Certificate was generated +```bash +openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem +``` + +## How PFX was generated from above Key and Certificate +```bash +openssl pkcs12 -export -out certificate.pfx -inkey key.pem -in cert.pem +``` \ No newline at end of file diff --git a/internal/services/firewall/testdata/cert.pem b/internal/services/firewall/testdata/cert.pem new file mode 100644 index 000000000000..a0334a6afa4d --- /dev/null +++ b/internal/services/firewall/testdata/cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkjCCAnoCCQDY1A4aUvTZ0TANBgkqhkiG9w0BAQsFADCBijELMAkGA1UEBhMC +Q0gxCzAJBgNVBAgMAlpIMQswCQYDVQQHDAJaSDESMBAGA1UECgwJVGVycmFmb3Jt +MQ4wDAYDVQQLDAVBenVyZTEYMBYGA1UEAwwPd3d3LmNvbnRvc28uY29tMSMwIQYJ +KoZIhvcNAQkBFhR3aGF0ZXZlckBjb250b3NvLmNvbTAeFw0yMTA0MjIxOTU4MTBa +Fw0zMTA0MjAxOTU4MTBaMIGKMQswCQYDVQQGEwJDSDELMAkGA1UECAwCWkgxCzAJ +BgNVBAcMAlpIMRIwEAYDVQQKDAlUZXJyYWZvcm0xDjAMBgNVBAsMBUF6dXJlMRgw +FgYDVQQDDA93d3cuY29udG9zby5jb20xIzAhBgkqhkiG9w0BCQEWFHdoYXRldmVy +QGNvbnRvc28uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5rx3 +fTN0UUV1ktetzM2AEIJ4ZKQlibrLtVORPX2LQp2Vl/n74DPD2Re/ZgO2NtjhjItY +O65ZSqOgGz3R8ED4r12AokLCFmqhBnnr4IybeaQos7prjLKwSIyj5NbVMGuzNO6P +55W1zTMfV+CstbCtXtRPa7zizXjYbT3dfpw8FgJLh9sVWaiCO34Nu9PWF9NRIlzI +e/Ek3ss/JnNqskH+xnxgxq68slaZa4qojBjiLl/IdIs4A9DtyJnFd99xuh8nShMg +4ykccPr9/+YBaz8/Ef7/zmXj3g9DLTrIa7JV6s80V5oVINaF7KXu9jmjD+a03SsR +/8eKX6K+xDBtqxpz8wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQAOGe2knCVxje06 +ihfhzprg7lTM7GCgiXqa4fdCVwq0hJAYpMg29F7Df3OE/zVD/mzdRWZe2yVTY47f +YFEfDKMmkGepgqICs0wTfhBSham8vkk2yDcoT01Lar+Im3GToP3JSM5YFbqxam0R +/AVskE5aHQ+tIGUwcuwWhjjKQuWua59tI0USjgGaK3cZ5tyFOQPcE3ZFzndWM3Rz +ojNHH5UJOT7zt4RebBzGRpcNdrbkOtVkRVZIwH0wJfm44zR+L36UhpXUd8XGKvua +KFlqJhw/8UtYzXXX5bwHb/JTkOLUbs8gobG23lFhxXG5QhqtwqYnHXRw9Jhclv8p +weEgmhnj +-----END CERTIFICATE----- diff --git a/internal/services/firewall/testdata/certificate.pfx b/internal/services/firewall/testdata/certificate.pfx new file mode 100644 index 000000000000..cbf0f300daeb Binary files /dev/null and b/internal/services/firewall/testdata/certificate.pfx differ diff --git a/internal/services/firewall/testdata/key.pem b/internal/services/firewall/testdata/key.pem new file mode 100644 index 000000000000..87761f711640 --- /dev/null +++ b/internal/services/firewall/testdata/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDmvHd9M3RRRXWS +163MzYAQgnhkpCWJusu1U5E9fYtCnZWX+fvgM8PZF79mA7Y22OGMi1g7rllKo6Ab +PdHwQPivXYCiQsIWaqEGeevgjJt5pCizumuMsrBIjKPk1tUwa7M07o/nlbXNMx9X +4Ky1sK1e1E9rvOLNeNhtPd1+nDwWAkuH2xVZqII7fg2709YX01EiXMh78STeyz8m +c2qyQf7GfGDGrryyVplriqiMGOIuX8h0izgD0O3ImcV333G6HydKEyDjKRxw+v3/ +5gFrPz8R/v/OZePeD0MtOshrslXqzzRXmhUg1oXspe72OaMP5rTdKxH/x4pfor7E +MG2rGnPzAgMBAAECggEAAXJvIWbgNN5FpX0axu0G/5OB48evwJReUK3MfGE8LVfF +p2VW8goBEWx3s9EUJHXpvDLng8BNKQ2rpGAX3/TYWmkwtFPM2c0jY2ICW68mDnY8 +Fxx1LjW0q0/Oe1HpllsmjY9tcZtbv4SxjqCHFMCd5blZIijWF0nJua2opPGf4tdv +yvN/D9HYPdRlynj6SjUij0rR2PFN134LLaKhRrAsaeKHqSk+Pngxt6HStRLPSnN+ +dqk+6rA0fJ97YXeiNRjYfRbJEMOedJFW5wavddIXkNzI/3iwrDc5P0A+9X+SbIGm +6BlKNy6EbFtEsbsbdcefZaVuaRXEVNsiRXBoUHjkYQKBgQD7yZWZDPr0JWtL+Mav +dewbQUd8xVMzAc9r2mjRCNJi5qanQRDNIDhkYkNVrpBnsKpCe8cDRb3SaawTqYEv +ASCPGOU92ooQ1AMKMwETaCsrSDAEwpS6NdCSuYZbu6yGqWc8/v4Oi8ZAv10I1TJP +2WaG2PkvfOpsvXs8ixQWZ4f5QwKBgQDqmLgV86pnDFUEfW8W8f0n6PG0gPSofcF7 +DKDEcRj3ZmkBWDUKiICBInrPgQaxw5rLA4lL1GwRgxMQg51fit52mQcsMK56/aQx +3BmSIoA3Uf+mzHp+bSL+o1vYmoOtklUF09DGIf+y4XyQy9GjojSzxCVkXqBwFldj +9+jL0NXXkQKBgECyo8YYF8P0eYWj/ynG20yFkaD181L//BRyosxTv/u52MjRZ0fO +J69jsHmryV9bfeRnedPVb9lJXfYPcCpr17ntY7ppFWENmVpdkMEz2yPcALq4ZQ8U +FOwez+9yYfqYPPbnbtC+CctJYNaMMcliy32K8zzIlFQsvCXqdtbq832RAoGAAtPw +dCNJzJAzfihc7HPiT1bZgwmC6X0Klgci8PtEB8duQJvll8jpc6UMwe+WOxJWjVfv +kcBvxQ5Fbo+HmB0+bUOO+JNlpwnjrs4uaLqNvRz57fLNDzUVlOg3NTc3myIGcFmL +TLggMvHQ5JXwYv6TkA8vPDR/zpoWV5gncD2GNmECgYEA8e9f30xeVtce5eUebRkB +bNCxi1sApTIPq8CXRN5JzX5plFj7K1HUlgqQsIxpdWJhi8G7DMj8C4/K7V+PjCTo +dU1ulbuFWwrIuSS3W6S1gh+eBhODfU80iO6SvSbGLiq11iRrQL/xMsCLgOExZE5d +BXgz1uzIrvJt5jmZh6bPSYc= +-----END PRIVATE KEY----- diff --git a/website/docs/r/firewall_policy.html.markdown b/website/docs/r/firewall_policy.html.markdown index 0c8c134203fb..c7dcc58a00ab 100644 --- a/website/docs/r/firewall_policy.html.markdown +++ b/website/docs/r/firewall_policy.html.markdown @@ -32,36 +32,98 @@ The following arguments are supported: --- -* `sku` - (Optional) The SKU Tier of the Firewall Policy. Possible values are `Standard`, `Premium`. - * `base_policy_id` - (Optional) The ID of the base Firewall Policy. * `dns` - (Optional) A `dns` block as defined below. -* `threat_intelligence_mode` - (Optional) The operation mode for Threat Intelligence. Possible values are `Alert`, `Deny` and `Off`. Defaults to `Alert`. +* `identity` - (Optional) An `identity` block as defined below. Changing this forces a new Firewall Policy to be created. -* `threat_intelligence_allowlist` - (Optional) A `threat_intelligence_allowlist` block as defined below. +* `intrusion_detection` - (Optional) A `intrusion_detection` block as defined below. + +* `private_ip_ranges` - (Optional) A list of private IP ranges to which traffic will not be SNAT. + +* `sku` - (Optional) The SKU Tier of the Firewall Policy. Possible values are `Standard`, `Premium`. Changing this forces a new Firewall Policy to be created. * `tags` - (Optional) A mapping of tags which should be assigned to the Firewall Policy. +* `threat_intelligence_allowlist` - (Optional) A `threat_intelligence_allowlist` block as defined below. + +* `threat_intelligence_mode` - (Optional) The operation mode for Threat Intelligence. Possible values are `Alert`, `Deny` and `Off`. Defaults to `Alert`. + +* `tls_certificate` - (Optional) A `tls_certificate` block as defined below. + --- A `dns` block supports the following: -* `servers` - (Optional) A list of custom DNS servers' IP addresses. +* `network_rule_fqdn_enabled` - (Optional) Should the network rule fqdn be enabled? * `proxy_enabled` - (Optional) Whether to enable DNS proxy on Firewalls attached to this Firewall Policy? Defaults to `false`. +* `servers` - (Optional) A list of custom DNS servers' IP addresses. + +--- + +A `identity` block supports the following: + +* `type` - (Required) Type of the identity. At the moment only "UserAssigned" is supported. Changing this forces a new Firewall Policy to be created. + +* `user_assigned_identity_ids` - (Optional) Specifies a list of user assigned managed identities. + +--- + +A `intrusion_detection` block supports the following: + +* `mode` - (Optional) In which mode you want to run intrusion detection: "Off", "Alert" or "Deny". + +* `signature_overrides` - (Optional) One or more `signature_overrides` blocks as defined below. + +* `traffic_bypass` - (Optional) One or more `traffic_bypass` blocks as defined below. + +--- + +A `signature_overrides` block supports the following: + +* `id` - (Optional) 12-digit number (id) which identifies your signature. + +* `state` - (Optional) state can be any of "Off", "Alert" or "Deny". + --- A `threat_intelligence_allowlist` block supports the following: +* `fqdns` - (Optional) A list of FQDNs that will be skipped for threat detection. + * `ip_addresses` - (Optional) A list of IP addresses or IP address ranges that will be skipped for threat detection. -* `fqdns` - (Optional) A list of FQDNs that will be skipped for threat detection. +--- + +A `tls_certificate` block supports the following: + +* `key_vault_secret_id` - (Required) The ID of the Key Vault, where the secret or certificate is stored. + +* `name` - (Required) The name of the certificate. --- +A `traffic_bypass` block supports the following: + +* `name` - (Required) The name which should be used for this bypass traffic setting. + +* `protocol` - (Required) The protocols any of "ANY", "TCP", "ICMP", "UDP" that shall be bypassed by intrusion detection. + +* `description` - (Optional) The description for this bypass traffic setting. + +* `destination_addresses` - (Optional) Specifies a list of destination IP addresses that shall be bypassed by intrusion detection. + +* `destination_ip_groups` - (Optional) Specifies a list of destination IP groups that shall be bypassed by intrusion detection. + +* `destination_ports` - (Optional) Specifies a list of destination IP ports that shall be bypassed by intrusion detection. + +* `source_addresses` - (Optional) Specifies a list of source addresses that shall be bypassed by intrusion detection. + +* `source_ip_groups` - (Optional) Specifies a list of source ip groups that shall be bypassed by intrusion detection. + ## Attributes Reference In addition to the Arguments listed above - the following Attributes are exported: @@ -74,8 +136,6 @@ In addition to the Arguments listed above - the following Attributes are exporte * `rule_collection_groups` - A list of references to Firewall Policy Rule Collection Groups that belongs to this Firewall Policy. -* `private_ip_ranges` - A list of private IP ranges to which traffic will not be SNAT. - ## Timeouts The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/docs/configuration/resources.html#timeouts) for certain actions: @@ -87,7 +147,7 @@ The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/d ## Import -networks can be imported using the `resource id`, e.g. +Firewall Policies can be imported using the `resource id`, e.g. ```shell terraform import azurerm_firewall_policy.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/mygroup1/providers/Microsoft.Network/firewallPolicies/policy1