From 6425c5a74d31696105b5ad75c91e788e1926108b Mon Sep 17 00:00:00 2001 From: Sebastian Rosander Date: Fri, 15 May 2020 18:51:19 +0200 Subject: [PATCH 1/5] Added support for scm ip restrictions. --- azurerm/helpers/azure/app_service.go | 117 +++++ .../tests/resource_arm_app_service_test.go | 451 ++++++++++++++++++ website/docs/r/app_service.html.markdown | 24 + 3 files changed, 592 insertions(+) diff --git a/azurerm/helpers/azure/app_service.go b/azurerm/helpers/azure/app_service.go index ffa49969c936..89b3b48fca3e 100644 --- a/azurerm/helpers/azure/app_service.go +++ b/azurerm/helpers/azure/app_service.go @@ -332,6 +332,45 @@ func SchemaAppServiceSiteConfig() *schema.Schema { }, }, + "scm_use_main_ip_restriction": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "scm_ip_restriction": { + Type: schema.TypeList, + Optional: true, + Computed: true, + ConfigMode: schema.SchemaConfigModeAttr, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_address": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validate.CIDR, + }, + "virtual_network_subnet_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringIsNotEmpty, + }, + "priority": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IntBetween(1, 2147483647), + }, + }, + }, + }, + "java_version": { Type: schema.TypeString, Optional: true, @@ -1486,6 +1525,54 @@ func ExpandAppServiceSiteConfig(input interface{}) (*web.SiteConfig, error) { siteConfig.IPSecurityRestrictions = &restrictions } + if v, ok := config["scm_use_main_ip_restriction"]; ok { + siteConfig.ScmIPSecurityRestrictionsUseMain = utils.Bool(v.(bool)) + } + + if v, ok := config["scm_ip_restriction"]; ok { + scmIPSecurityRestrictions := v.([]interface{}) + scmRestrictions := make([]web.IPSecurityRestriction, 0) + for i, scmIPSecurityRestriction := range scmIPSecurityRestrictions { + scmRestriction := scmIPSecurityRestriction.(map[string]interface{}) + + ipAddress := scmRestriction["ip_address"].(string) + vNetSubnetID := scmRestriction["virtual_network_subnet_id"].(string) + name := scmRestriction["name"].(string) + priority := scmRestriction["priority"].(int) + if vNetSubnetID != "" && ipAddress != "" { + return siteConfig, fmt.Errorf(fmt.Sprintf("only one of `ip_address` or `virtual_network_subnet_id` can be set for `site_config.0.scm_ip_restriction.%d`", i)) + } + + if vNetSubnetID == "" && ipAddress == "" { + return siteConfig, fmt.Errorf(fmt.Sprintf("one of `ip_address` or `virtual_network_subnet_id` must be set for `site_config.0.scm_ip_restriction.%d`", i)) + } + + scmIPSecurityRestriction := web.IPSecurityRestriction{} + if ipAddress == "Any" { + continue + } + + if ipAddress != "" { + scmIPSecurityRestriction.IPAddress = &ipAddress + } + + if vNetSubnetID != "" { + scmIPSecurityRestriction.VnetSubnetResourceID = &vNetSubnetID + } + + if name != "" { + scmIPSecurityRestriction.Name = &name + } + + if priority != 0 { + scmIPSecurityRestriction.Priority = utils.Int32(int32(priority)) + } + + scmRestrictions = append(scmRestrictions, scmIPSecurityRestriction) + } + siteConfig.ScmIPSecurityRestrictions = &scmRestrictions + } + if v, ok := config["local_mysql_enabled"]; ok { siteConfig.LocalMySQLEnabled = utils.Bool(v.(bool)) } @@ -1620,6 +1707,36 @@ func FlattenAppServiceSiteConfig(input *web.SiteConfig) []interface{} { } result["ip_restriction"] = restrictions + if input.ScmIPSecurityRestrictionsUseMain != nil { + result["scm_use_main_ip_restriction"] = *input.ScmIPSecurityRestrictionsUseMain + } + + scmRestrictions := make([]interface{}, 0) + if vs := input.ScmIPSecurityRestrictions; vs != nil { + for _, v := range *vs { + block := make(map[string]interface{}) + + if ip := v.IPAddress; ip != nil { + if *ip == "Any" { + continue + } else { + block["ip_address"] = *ip + } + } + if vNetSubnetID := v.VnetSubnetResourceID; vNetSubnetID != nil { + block["virtual_network_subnet_id"] = *vNetSubnetID + } + if name := v.Name; name != nil { + block["name"] = *name + } + if priority := v.Priority; priority != nil { + block["priority"] = *priority + } + scmRestrictions = append(scmRestrictions, block) + } + } + result["scm_ip_restriction"] = scmRestrictions + result["managed_pipeline_mode"] = string(input.ManagedPipelineMode) if input.PhpVersion != nil { diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go index e03eba2a8cf0..bf0d7457ed14 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go @@ -636,6 +636,166 @@ func TestAccAzureRMAppService_manyIpRestrictions(t *testing.T) { }) } +func TestAccAzureRMAppService_scmUseMainIPRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppService_scmUseMainIPRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_use_main_ip_restriction", "true"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppService_scmOneIpRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppService_scmOneIpRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppService_completeScmIpRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMAppService_manyCompleteScmIpRestrictions(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "2"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.ip_address", "20.20.20.0/24"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.name", "test-restriction-2"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.priority", "1234"), + ), + }, + data.ImportStep(), + { + Config: testAccAzureRMAppService_completeScmIpRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "1"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppService_oneVNetSubnetScmIpRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppService_oneVNetSubnetScmIpRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + ), + }, + data.ImportStep(), + }, + }) +} + +func TestAccAzureRMAppService_zeroedScmIpRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceSlotDestroy, + Steps: []resource.TestStep{ + { + // This configuration includes a single explicit ip_restriction + Config: testAccAzureRMAppService_scmOneIpRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "1"), + ), + }, + { + // This configuration has no site_config blocks at all. + Config: testAccAzureRMAppService_basic(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "1"), + ), + }, + { + // This configuration explicitly sets ip_restriction to [] using attribute syntax. + Config: testAccAzureRMAppService_zeroedScmIpRestriction(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "0"), + ), + }, + }, + }) +} + +func TestAccAzureRMAppService_manyScmIpRestrictions(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_app_service", "test") + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMAppService_manyScmIpRestrictions(data), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMAppServiceExists(data.ResourceName), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.ip_address", "20.20.20.0/24"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.2.ip_address", "30.30.0.0/16"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.3.ip_address", "192.168.1.2/24"), + ), + }, + data.ImportStep(), + }, + }) +} + func TestAccAzureRMAppService_defaultDocuments(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_app_service", "test") resource.ParallelTest(t, resource.TestCase{ @@ -2868,6 +3028,297 @@ resource "azurerm_app_service" "test" { `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) } +func testAccAzureRMAppService_scmUseMainIPRestriction(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_use_main_ip_restriction = true + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppService_scmOneIpRestriction(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_ip_restriction { + ip_address = "10.10.10.10/32" + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppService_completeScmIpRestriction(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_ip_restriction { + ip_address = "10.10.10.10/32" + name = "test-restriction" + priority = 123 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppService_manyCompleteScmIpRestrictions(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_ip_restriction { + ip_address = "10.10.10.10/32" + name = "test-restriction" + priority = 123 + } + + scm_ip_restriction { + ip_address = "20.20.20.0/24" + name = "test-restriction-2" + priority = 1234 + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppService_oneVNetSubnetScmIpRestriction(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_virtual_network" "test" { + name = "acctestvirtnet%d" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name +} + +resource "azurerm_subnet" "test" { + name = "acctestsubnet%d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefix = "10.0.2.0/24" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_ip_restriction { + virtual_network_subnet_id = azurerm_subnet.test.id + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppService_zeroedScmIpRestriction(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_ip_restriction = [] + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + +func testAccAzureRMAppService_manyScmIpRestrictions(data acceptance.TestData) string { + return fmt.Sprintf(` +provider "azurerm" { + features {} +} + +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_app_service_plan" "test" { + name = "acctestASP-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + sku { + tier = "Standard" + size = "S1" + } +} + +resource "azurerm_app_service" "test" { + name = "acctestAS-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + app_service_plan_id = azurerm_app_service_plan.test.id + + site_config { + scm_ip_restriction { + ip_address = "10.10.10.10/32" + } + + scm_ip_restriction { + ip_address = "20.20.20.0/24" + } + + scm_ip_restriction { + ip_address = "30.30.0.0/16" + } + + scm_ip_restriction { + ip_address = "192.168.1.2/24" + } + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger) +} + func testAccAzureRMAppService_defaultDocuments(data acceptance.TestData) string { return fmt.Sprintf(` provider "azurerm" { diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index c8db8d0a13cd..339c56f7d48c 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -197,6 +197,14 @@ A `site_config` block supports the following: -> **NOTE** User has to explicitly set `ip_restriction` to empty slice (`[]`) to remove it. +* `scm_use_main_ip_restriction` - (Optional) IP security restrictions for scm to use main. Defaults to false. + +-> **NOTE** Can't be use together with `scm_ip_restriction`. + +* `scm_ip_restriction` - (Optional) A [List of objects](/docs/configuration/attr-as-blocks.html) representing ip restrictions as defined below. + +-> **NOTE** User has to explicitly set `ip_restriction` to empty slice (`[]`) to remove it. + * `java_version` - (Optional) The version of Java to use. If specified `java_container` and `java_container_version` must also be specified. Possible values are `1.7`, `1.8` and `11` and their specific versions - except for Java 11 (e.g. `1.7.0_80`, `1.8.0_181`, `11`) * `java_container` - (Optional) The Java Container to use. If specified `java_version` and `java_container_version` must also be specified. Possible values are `JAVA`, `JETTY`, and `TOMCAT`. @@ -321,6 +329,22 @@ A `ip_restriction` block supports the following: --- +--- + +A `scm_ip_restriction` block supports the following: + +* `ip_address` - (Optional) The IP Address used for this IP Restriction in CIDR notation. + +* `virtual_network_subnet_id` - (Optional) The Virtual Network Subnet ID used for this IP Restriction. + +-> **NOTE:** One of either `ip_address` or `virtual_network_subnet_id` must be specified + +* `name` - (Optional) The name for this IP Restriction. + +* `priority` - (Optional) The priority for this IP Restriction. Restrictions are enforced in priority order. By default, priority is set to 65000 if not specified. + +--- + A `microsoft` block supports the following: * `client_id` - (Required) The OAuth 2.0 client ID that was created for the app used for authentication. From f215a5d28f795fce2bcef738ee5f77c37802a1fb Mon Sep 17 00:00:00 2001 From: Sebastian Rosander Date: Sat, 16 May 2020 15:19:56 +0200 Subject: [PATCH 2/5] added functionality for scm_ip_restriction - allow or deny & added to data source. --- azurerm/helpers/azure/app_service.go | 52 +++++++++++++++ .../web/tests/data_source_app_service_test.go | 63 +++++++++++++++++++ .../tests/resource_arm_app_service_test.go | 9 +++ website/docs/d/app_service.html.markdown | 17 +++++ website/docs/r/app_service.html.markdown | 2 + 5 files changed, 143 insertions(+) diff --git a/azurerm/helpers/azure/app_service.go b/azurerm/helpers/azure/app_service.go index 89b3b48fca3e..7b374d02f540 100644 --- a/azurerm/helpers/azure/app_service.go +++ b/azurerm/helpers/azure/app_service.go @@ -367,6 +367,15 @@ func SchemaAppServiceSiteConfig() *schema.Schema { Computed: true, ValidateFunc: validation.IntBetween(1, 2147483647), }, + "action": { + Type: schema.TypeString, + Optional: true, + Default: "Allow", + ValidateFunc: validation.StringInSlice([]string{ + "Allow", + "Deny", + }, true), + }, }, }, }, @@ -748,6 +757,40 @@ func SchemaAppServiceDataSourceSiteConfig() *schema.Schema { }, }, + "scm_use_main_ip_restriction": { + Type: schema.TypeBool, + Computed: true, + }, + + "scm_ip_restriction": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ip_address": { + Type: schema.TypeString, + Computed: true, + }, + "virtual_network_subnet_id": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "priority": { + Type: schema.TypeInt, + Computed: true, + }, + "action": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + "java_version": { Type: schema.TypeString, Computed: true, @@ -1539,6 +1582,7 @@ func ExpandAppServiceSiteConfig(input interface{}) (*web.SiteConfig, error) { vNetSubnetID := scmRestriction["virtual_network_subnet_id"].(string) name := scmRestriction["name"].(string) priority := scmRestriction["priority"].(int) + action := scmRestriction["action"].(string) if vNetSubnetID != "" && ipAddress != "" { return siteConfig, fmt.Errorf(fmt.Sprintf("only one of `ip_address` or `virtual_network_subnet_id` can be set for `site_config.0.scm_ip_restriction.%d`", i)) } @@ -1568,6 +1612,10 @@ func ExpandAppServiceSiteConfig(input interface{}) (*web.SiteConfig, error) { scmIPSecurityRestriction.Priority = utils.Int32(int32(priority)) } + if action != "" { + scmIPSecurityRestriction.Action = &action + } + scmRestrictions = append(scmRestrictions, scmIPSecurityRestriction) } siteConfig.ScmIPSecurityRestrictions = &scmRestrictions @@ -1732,6 +1780,10 @@ func FlattenAppServiceSiteConfig(input *web.SiteConfig) []interface{} { if priority := v.Priority; priority != nil { block["priority"] = *priority } + + if action := v.Action; action != nil { + block["action"] = *action + } scmRestrictions = append(scmRestrictions, block) } } diff --git a/azurerm/internal/services/web/tests/data_source_app_service_test.go b/azurerm/internal/services/web/tests/data_source_app_service_test.go index 570d1e9fcf53..0f45f06da873 100644 --- a/azurerm/internal/services/web/tests/data_source_app_service_test.go +++ b/azurerm/internal/services/web/tests/data_source_app_service_test.go @@ -145,6 +145,45 @@ func TestAccDataSourceAzureRMAppService_ipRestriction(t *testing.T) { }) } +func TestAccDataSourceAzureRMAppService_scmUseMainIPRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_scmUseMainIPRestriction(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_use_main_ip_restriction", "true"), + ), + }, + }, + }) +} + +func TestAccDataSourceAzureRMAppService_scmIPRestriction(t *testing.T) { + data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acceptance.PreCheck(t) }, + Providers: acceptance.SupportedProviders, + CheckDestroy: testCheckAzureRMAppServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAppService_scmIPRestriction(data), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), + ), + }, + }, + }) +} + func TestAccDataSourceAzureRMAppService_http2Enabled(t *testing.T) { data := acceptance.BuildTestData(t, "data.azurerm_app_service", "test") @@ -284,6 +323,30 @@ data "azurerm_app_service" "test" { `, config) } +func testAccDataSourceAppService_scmUseMainIPRestriction(data acceptance.TestData) string { + config := testAccAzureRMAppService_scmUseMainIPRestriction(data) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = azurerm_app_service.test.name + resource_group_name = azurerm_app_service.test.resource_group_name +} +`, config) +} + +func testAccDataSourceAppService_scmIPRestriction(data acceptance.TestData) string { + config := testAccAzureRMAppService_completeScmIpRestriction(data) + return fmt.Sprintf(` +%s + +data "azurerm_app_service" "test" { + name = azurerm_app_service.test.name + resource_group_name = azurerm_app_service.test.resource_group_name +} +`, config) +} + func testAccDataSourceAppService_http2Enabled(data acceptance.TestData) string { config := testAccAzureRMAppService_http2Enabled(data) return fmt.Sprintf(` diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go index bf0d7457ed14..834627c07bdc 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go @@ -667,6 +667,7 @@ func TestAccAzureRMAppService_scmOneIpRestriction(t *testing.T) { Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), ), }, data.ImportStep(), @@ -689,6 +690,7 @@ func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), ), }, data.ImportStep(), @@ -700,9 +702,11 @@ func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.ip_address", "20.20.20.0/24"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.name", "test-restriction-2"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.priority", "1234"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.action", "Deny"), ), }, data.ImportStep(), @@ -714,6 +718,7 @@ func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), + resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), ), }, data.ImportStep(), @@ -3094,6 +3099,7 @@ resource "azurerm_app_service" "test" { site_config { scm_ip_restriction { ip_address = "10.10.10.10/32" + action = "Allow" } } } @@ -3133,6 +3139,7 @@ resource "azurerm_app_service" "test" { ip_address = "10.10.10.10/32" name = "test-restriction" priority = 123 + action = "Allow" } } } @@ -3172,12 +3179,14 @@ resource "azurerm_app_service" "test" { ip_address = "10.10.10.10/32" name = "test-restriction" priority = 123 + action = "Allow" } scm_ip_restriction { ip_address = "20.20.20.0/24" name = "test-restriction-2" priority = 1234 + action = "Deny" } } } diff --git a/website/docs/d/app_service.html.markdown b/website/docs/d/app_service.html.markdown index c0507d70afa1..3ed77df1d5dc 100644 --- a/website/docs/d/app_service.html.markdown +++ b/website/docs/d/app_service.html.markdown @@ -89,6 +89,19 @@ A `ip_restriction` block exports the following: * `priority` - The priority for this IP Restriction. +--- +A `scm_ip_restriction` block exports the following: + +* `ip_address` - The IP Address used for this IP Restriction in CIDR notation. + +* `virtual_network_subnet_id` - The Virtual Network Subnet ID used for this IP Restriction. + +* `name` - The name for this IP Restriction. + +* `priority` - The priority for this IP Restriction. Restrictions are enforced in priority order. By default, priority is set to 65000 if not specified. + +* `action` - Allow or Deny access for this IP range. Defaults to Allow. + --- `site_config` supports the following: @@ -111,6 +124,10 @@ A `ip_restriction` block exports the following: * `ip_restriction` - One or more `ip_restriction` blocks as defined above. +* `scm_use_main_ip_restriction` - IP security restrictions for scm to use main. + +* `scm_ip_restriction` - One or more `scm_ip_restriction` blocks as defined above. + * `java_version` - The version of Java in use. * `java_container` - The Java Container in use. diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index 339c56f7d48c..ea07a1cf7d4f 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -343,6 +343,8 @@ A `scm_ip_restriction` block supports the following: * `priority` - (Optional) The priority for this IP Restriction. Restrictions are enforced in priority order. By default, priority is set to 65000 if not specified. +* `action` - (Optional) Allow or Deny access for this IP range. Defaults to Allow. + --- A `microsoft` block supports the following: From 21113fb7a34e1cf2ab5e2ad7b017eecd83bc5725 Mon Sep 17 00:00:00 2001 From: Sebastian Rosander Date: Sat, 16 May 2020 15:47:47 +0200 Subject: [PATCH 3/5] Updates --- .../services/web/tests/resource_arm_app_service_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go index 834627c07bdc..fc7cf0b1546f 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go @@ -3099,7 +3099,7 @@ resource "azurerm_app_service" "test" { site_config { scm_ip_restriction { ip_address = "10.10.10.10/32" - action = "Allow" + action = "Allow" } } } @@ -3139,7 +3139,7 @@ resource "azurerm_app_service" "test" { ip_address = "10.10.10.10/32" name = "test-restriction" priority = 123 - action = "Allow" + action = "Allow" } } } @@ -3179,14 +3179,14 @@ resource "azurerm_app_service" "test" { ip_address = "10.10.10.10/32" name = "test-restriction" priority = 123 - action = "Allow" + action = "Allow" } scm_ip_restriction { ip_address = "20.20.20.0/24" name = "test-restriction-2" priority = 1234 - action = "Deny" + action = "Deny" } } } From 51ccee20b9c3f886973be17eab49e7ebf81782c5 Mon Sep 17 00:00:00 2001 From: SebRosander Date: Mon, 15 Jun 2020 18:44:53 +0200 Subject: [PATCH 4/5] Updates to comments --- azurerm/helpers/azure/app_service.go | 2 +- .../tests/resource_arm_app_service_test.go | 30 ++----------------- website/docs/d/app_service.html.markdown | 2 +- website/docs/r/app_service.html.markdown | 4 +-- 4 files changed, 6 insertions(+), 32 deletions(-) diff --git a/azurerm/helpers/azure/app_service.go b/azurerm/helpers/azure/app_service.go index 7b374d02f540..7d96e6d3dcde 100644 --- a/azurerm/helpers/azure/app_service.go +++ b/azurerm/helpers/azure/app_service.go @@ -364,7 +364,7 @@ func SchemaAppServiceSiteConfig() *schema.Schema { "priority": { Type: schema.TypeInt, Optional: true, - Computed: true, + Default: 65000, ValidateFunc: validation.IntBetween(1, 2147483647), }, "action": { diff --git a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go index fc7cf0b1546f..9ca029129103 100644 --- a/azurerm/internal/services/web/tests/resource_arm_app_service_test.go +++ b/azurerm/internal/services/web/tests/resource_arm_app_service_test.go @@ -647,7 +647,6 @@ func TestAccAzureRMAppService_scmUseMainIPRestriction(t *testing.T) { Config: testAccAzureRMAppService_scmUseMainIPRestriction(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_use_main_ip_restriction", "true"), ), }, data.ImportStep(), @@ -666,8 +665,6 @@ func TestAccAzureRMAppService_scmOneIpRestriction(t *testing.T) { Config: testAccAzureRMAppService_scmOneIpRestriction(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), ), }, data.ImportStep(), @@ -686,11 +683,6 @@ func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { Config: testAccAzureRMAppService_completeScmIpRestriction(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), ), }, data.ImportStep(), @@ -698,15 +690,6 @@ func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { Config: testAccAzureRMAppService_manyCompleteScmIpRestrictions(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "2"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.ip_address", "20.20.20.0/24"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.name", "test-restriction-2"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.priority", "1234"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.action", "Deny"), ), }, data.ImportStep(), @@ -714,11 +697,6 @@ func TestAccAzureRMAppService_completeScmIpRestriction(t *testing.T) { Config: testAccAzureRMAppService_completeScmIpRestriction(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.#", "1"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.name", "test-restriction"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.priority", "123"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.action", "Allow"), ), }, data.ImportStep(), @@ -752,7 +730,7 @@ func TestAccAzureRMAppService_zeroedScmIpRestriction(t *testing.T) { CheckDestroy: testCheckAzureRMAppServiceSlotDestroy, Steps: []resource.TestStep{ { - // This configuration includes a single explicit ip_restriction + // This configuration includes a single explicit scm_ip_restriction Config: testAccAzureRMAppService_scmOneIpRestriction(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), @@ -768,7 +746,7 @@ func TestAccAzureRMAppService_zeroedScmIpRestriction(t *testing.T) { ), }, { - // This configuration explicitly sets ip_restriction to [] using attribute syntax. + // This configuration explicitly sets scm_ip_restriction to [] using attribute syntax. Config: testAccAzureRMAppService_zeroedScmIpRestriction(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), @@ -790,10 +768,6 @@ func TestAccAzureRMAppService_manyScmIpRestrictions(t *testing.T) { Config: testAccAzureRMAppService_manyScmIpRestrictions(data), Check: resource.ComposeTestCheckFunc( testCheckAzureRMAppServiceExists(data.ResourceName), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.0.ip_address", "10.10.10.10/32"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.1.ip_address", "20.20.20.0/24"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.2.ip_address", "30.30.0.0/16"), - resource.TestCheckResourceAttr(data.ResourceName, "site_config.0.scm_ip_restriction.3.ip_address", "192.168.1.2/24"), ), }, data.ImportStep(), diff --git a/website/docs/d/app_service.html.markdown b/website/docs/d/app_service.html.markdown index 3ed77df1d5dc..ec6e931d25b4 100644 --- a/website/docs/d/app_service.html.markdown +++ b/website/docs/d/app_service.html.markdown @@ -98,7 +98,7 @@ A `scm_ip_restriction` block exports the following: * `name` - The name for this IP Restriction. -* `priority` - The priority for this IP Restriction. Restrictions are enforced in priority order. By default, priority is set to 65000 if not specified. +* `priority` - The priority for this IP Restriction. * `action` - Allow or Deny access for this IP range. Defaults to Allow. diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index ea07a1cf7d4f..a31c35274145 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -199,11 +199,11 @@ A `site_config` block supports the following: * `scm_use_main_ip_restriction` - (Optional) IP security restrictions for scm to use main. Defaults to false. --> **NOTE** Can't be use together with `scm_ip_restriction`. +-> **NOTE** Any `scm_ip_restriction` blocks configured are ignored by the service when `scm_use_main_ip_restriction` is set to `true`. Any scm restrictions will become active if this is subsequently set to `false` or removed. * `scm_ip_restriction` - (Optional) A [List of objects](/docs/configuration/attr-as-blocks.html) representing ip restrictions as defined below. --> **NOTE** User has to explicitly set `ip_restriction` to empty slice (`[]`) to remove it. +-> **NOTE** User has to explicitly set `scm_ip_restriction` to empty slice (`[]`) to remove it. * `java_version` - (Optional) The version of Java to use. If specified `java_container` and `java_container_version` must also be specified. Possible values are `1.7`, `1.8` and `11` and their specific versions - except for Java 11 (e.g. `1.7.0_80`, `1.8.0_181`, `11`) From afdd99af260cb54013853f8eb5544f14c161f71e Mon Sep 17 00:00:00 2001 From: SebRosander Date: Mon, 15 Jun 2020 19:11:54 +0200 Subject: [PATCH 5/5] Fix to one missed comment. --- website/docs/r/app_service.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/app_service.html.markdown b/website/docs/r/app_service.html.markdown index a31c35274145..3e5a05356e12 100644 --- a/website/docs/r/app_service.html.markdown +++ b/website/docs/r/app_service.html.markdown @@ -341,7 +341,7 @@ A `scm_ip_restriction` block supports the following: * `name` - (Optional) The name for this IP Restriction. -* `priority` - (Optional) The priority for this IP Restriction. Restrictions are enforced in priority order. By default, priority is set to 65000 if not specified. +* `priority` - (Optional) The priority for this IP Restriction. Restrictions are enforced in priority order. By default, priority is set to 65000 if not specified. * `action` - (Optional) Allow or Deny access for this IP range. Defaults to Allow.