diff --git a/azurerm/data_source_network_security_group.go b/azurerm/data_source_network_security_group.go index 6bccebb885f3..a12bc04871cd 100644 --- a/azurerm/data_source_network_security_group.go +++ b/azurerm/data_source_network_security_group.go @@ -76,6 +76,13 @@ func dataSourceArmNetworkSecurityGroup() *schema.Resource { Set: schema.HashString, }, + "source_application_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "destination_address_prefix": { Type: schema.TypeString, Computed: true, @@ -88,6 +95,13 @@ func dataSourceArmNetworkSecurityGroup() *schema.Resource { Set: schema.HashString, }, + "destination_application_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "access": { Type: schema.TypeString, Computed: true, diff --git a/azurerm/import_arm_network_security_rule_test.go b/azurerm/import_arm_network_security_rule_test.go index 7c19c3fa4e09..30eb4d007143 100644 --- a/azurerm/import_arm_network_security_rule_test.go +++ b/azurerm/import_arm_network_security_rule_test.go @@ -20,10 +20,9 @@ func TestAccAzureRMNetworkSecurityRule_importBasic(t *testing.T) { Config: testAccAzureRMNetworkSecurityRule_basic(rInt, testLocation()), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"network_security_group_name"}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) diff --git a/azurerm/resource_arm_network_security_group.go b/azurerm/resource_arm_network_security_group.go index 8b494cc35856..df69e66039bd 100644 --- a/azurerm/resource_arm_network_security_group.go +++ b/azurerm/resource_arm_network_security_group.go @@ -109,6 +109,20 @@ func resourceArmNetworkSecurityGroup() *schema.Resource { Set: schema.HashString, }, + "destination_application_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "source_application_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "access": { Type: schema.TypeString, Required: true, @@ -324,6 +338,28 @@ func expandAzureRmSecurityRules(d *schema.ResourceData) ([]network.SecurityRule, properties.DestinationAddressPrefixes = &destinationAddressPrefixes } + if r, ok := sgRule["source_application_security_group_ids"].(*schema.Set); ok && r.Len() > 0 { + var sourceApplicationSecurityGroups []network.ApplicationSecurityGroup + for _, v := range r.List() { + sg := network.ApplicationSecurityGroup{ + ID: utils.String(v.(string)), + } + sourceApplicationSecurityGroups = append(sourceApplicationSecurityGroups, sg) + } + properties.SourceApplicationSecurityGroups = &sourceApplicationSecurityGroups + } + + if r, ok := sgRule["destination_application_security_group_ids"].(*schema.Set); ok && r.Len() > 0 { + var destinationApplicationSecurityGroups []network.ApplicationSecurityGroup + for _, v := range r.List() { + sg := network.ApplicationSecurityGroup{ + ID: utils.String(v.(string)), + } + destinationApplicationSecurityGroups = append(destinationApplicationSecurityGroups, sg) + } + properties.DestinationApplicationSecurityGroups = &destinationApplicationSecurityGroups + } + rules = append(rules, network.SecurityRule{ Name: &name, SecurityRulePropertiesFormat: &properties, @@ -358,12 +394,30 @@ func flattenNetworkSecurityRules(rules *[]network.SecurityRule) []map[string]int if props.DestinationPortRanges != nil { sgRule["destination_port_ranges"] = sliceToSet(*props.DestinationPortRanges) } + + destinationApplicationSecurityGroups := make([]string, 0) + if props.DestinationApplicationSecurityGroups != nil { + for _, g := range *props.DestinationApplicationSecurityGroups { + destinationApplicationSecurityGroups = append(destinationApplicationSecurityGroups, *g.ID) + } + } + sgRule["destination_application_security_group_ids"] = sliceToSet(destinationApplicationSecurityGroups) + if props.SourceAddressPrefix != nil { sgRule["source_address_prefix"] = *props.SourceAddressPrefix } if props.SourceAddressPrefixes != nil { sgRule["source_address_prefixes"] = sliceToSet(*props.SourceAddressPrefixes) } + + sourceApplicationSecurityGroups := make([]string, 0) + if props.SourceApplicationSecurityGroups != nil { + for _, g := range *props.SourceApplicationSecurityGroups { + sourceApplicationSecurityGroups = append(sourceApplicationSecurityGroups, *g.ID) + } + } + sgRule["source_application_security_group_ids"] = sliceToSet(sourceApplicationSecurityGroups) + if props.SourcePortRange != nil { sgRule["source_port_range"] = *props.SourcePortRange } diff --git a/azurerm/resource_arm_network_security_group_test.go b/azurerm/resource_arm_network_security_group_test.go index e473b0ed9415..8cdc462c5b46 100644 --- a/azurerm/resource_arm_network_security_group_test.go +++ b/azurerm/resource_arm_network_security_group_test.go @@ -168,6 +168,25 @@ func TestAccAzureRMNetworkSecurityGroup_augmented(t *testing.T) { }) } +func TestAccAzureRMNetworkSecurityGroup_applicationSecurityGroup(t *testing.T) { + resourceName := "azurerm_network_security_group.test" + rInt := acctest.RandInt() + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMNetworkSecurityGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkSecurityGroup_applicationSecurityGroup(rInt, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkSecurityGroupExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "security_rule.#", "1"), + ), + }, + }, + }) +} + func testCheckAzureRMNetworkSecurityGroupExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -423,3 +442,42 @@ resource "azurerm_network_security_group" "test" { } `, rInt, location) } + +func testAccAzureRMNetworkSecurityGroup_applicationSecurityGroup(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_application_security_group" "first" { + name = "acctest-first%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_application_security_group" "second" { + name = "acctest-second%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_network_security_group" "test" { + name = "acctestnsg-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + + security_rule { + name = "test123" + priority = 100 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_application_security_group_ids = ["${azurerm_application_security_group.first.id}"] + destination_application_security_group_ids = ["${azurerm_application_security_group.second.id}"] + source_port_ranges = [ "10000-40000" ] + destination_port_ranges = [ "80", "443", "8080", "8190" ] + } +} +`, rInt, location, rInt, rInt, rInt) +} diff --git a/azurerm/resource_arm_network_security_rule.go b/azurerm/resource_arm_network_security_rule.go index 71af8b0aee02..3d5d8055b9fd 100644 --- a/azurerm/resource_arm_network_security_rule.go +++ b/azurerm/resource_arm_network_security_rule.go @@ -107,6 +107,20 @@ func resourceArmNetworkSecurityRule() *schema.Resource { ConflictsWith: []string{"destination_address_prefix"}, }, + "source_application_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "destination_application_security_group_ids": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "access": { Type: schema.TypeString, Required: true, @@ -215,6 +229,28 @@ func resourceArmNetworkSecurityRuleCreate(d *schema.ResourceData, meta interface rule.SecurityRulePropertiesFormat.DestinationAddressPrefixes = &destinationAddressPrefixes } + if r, ok := d.GetOk("source_application_security_group_ids"); ok { + var sourceApplicationSecurityGroups []network.ApplicationSecurityGroup + for _, v := range r.(*schema.Set).List() { + sg := network.ApplicationSecurityGroup{ + ID: utils.String(v.(string)), + } + sourceApplicationSecurityGroups = append(sourceApplicationSecurityGroups, sg) + } + rule.SourceApplicationSecurityGroups = &sourceApplicationSecurityGroups + } + + if r, ok := d.GetOk("destination_application_security_group_ids"); ok { + var destinationApplicationSecurityGroups []network.ApplicationSecurityGroup + for _, v := range r.(*schema.Set).List() { + sg := network.ApplicationSecurityGroup{ + ID: utils.String(v.(string)), + } + destinationApplicationSecurityGroups = append(destinationApplicationSecurityGroups, sg) + } + rule.DestinationApplicationSecurityGroups = &destinationApplicationSecurityGroups + } + future, err := client.CreateOrUpdate(ctx, resGroup, nsgName, name, rule) if err != nil { return fmt.Errorf("Error Creating/Updating Network Security Rule %q (NSG %q / Resource Group %q): %+v", name, nsgName, resGroup, err) @@ -261,6 +297,7 @@ func resourceArmNetworkSecurityRuleRead(d *schema.ResourceData, meta interface{} d.Set("name", resp.Name) d.Set("resource_group_name", resGroup) + d.Set("network_security_group_name", networkSGName) if props := resp.SecurityRulePropertiesFormat; props != nil { d.Set("description", props.Description) diff --git a/azurerm/resource_arm_network_security_rule_test.go b/azurerm/resource_arm_network_security_rule_test.go index fc4a581ed372..4389d66c98c5 100644 --- a/azurerm/resource_arm_network_security_rule_test.go +++ b/azurerm/resource_arm_network_security_rule_test.go @@ -92,6 +92,23 @@ func TestAccAzureRMNetworkSecurityRule_augmented(t *testing.T) { }) } +func TestAccAzureRMNetworkSecurityRule_applicationSecurityGroups(t *testing.T) { + rInt := acctest.RandInt() + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMNetworkSecurityRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMNetworkSecurityRule_applicationSecurityGroups(rInt, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMNetworkSecurityRuleExists("azurerm_network_security_rule.test1"), + ), + }, + }, + }) +} + func testCheckAzureRMNetworkSecurityRuleExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -307,3 +324,44 @@ resource "azurerm_network_security_rule" "test1" { } `, rInt, location) } + +func testAccAzureRMNetworkSecurityRule_applicationSecurityGroups(rInt int, location string) string { + return fmt.Sprintf(` +resource "azurerm_resource_group" "test" { + name = "acctestRG-%d" + location = "%s" +} + +resource "azurerm_application_security_group" "first" { + name = "acctest-first%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_application_security_group" "second" { + name = "acctest-second%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_network_security_group" "test" { + name = "acctestnsg-%d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" +} + +resource "azurerm_network_security_rule" "test1" { + name = "test123" + resource_group_name = "${azurerm_resource_group.test.name}" + network_security_group_name = "${azurerm_network_security_group.test.name}" + priority = 100 + direction = "Outbound" + access = "Allow" + protocol = "Tcp" + source_application_security_group_ids = ["${azurerm_application_security_group.first.id}"] + destination_application_security_group_ids = ["${azurerm_application_security_group.second.id}"] + source_port_ranges = [ "10000-40000" ] + destination_port_ranges = [ "80", "443", "8080", "8190" ] +} +`, rInt, location, rInt, rInt, rInt) +} diff --git a/website/docs/d/network_security_group.html.markdown b/website/docs/d/network_security_group.html.markdown index 5642cc6556cb..82c04e7dd167 100644 --- a/website/docs/d/network_security_group.html.markdown +++ b/website/docs/d/network_security_group.html.markdown @@ -56,6 +56,10 @@ The `security_rule` block supports: * `destination_address_prefix` - CIDR or destination IP range or * to match any IP. +* `source_application_security_group_ids` - A List of source Application Security Group ID's + +* `destination_application_security_group_ids` - A List of destination Application Security Group ID's + * `access` - Is network traffic is allowed or denied? * `priority` - The priority of the rule diff --git a/website/docs/r/network_security_group.html.markdown b/website/docs/r/network_security_group.html.markdown index 1f0fb61aaf49..905ebdf5c207 100644 --- a/website/docs/r/network_security_group.html.markdown +++ b/website/docs/r/network_security_group.html.markdown @@ -81,10 +81,14 @@ The `security_rule` block supports: * `source_address_prefixes` - (Optional) List of source address prefixes. Tags may not be used. This is required if `source_address_prefix` is not specified. +* `source_application_security_group_ids` - (Optional) A List of source Application Security Group ID's + * `destination_address_prefix` - (Optional) CIDR or destination IP range or * to match any IP. Tags such as ‘VirtualNetwork’, ‘AzureLoadBalancer’ and ‘Internet’ can also be used. This is required if `destination_address_prefixes` is not specified. * `destination_address_prefixes` - (Optional) List of destination address prefixes. Tags may not be used. This is required if `destination_address_prefix` is not specified. +* `destination_application_security_group_ids` - (Optional) A List of destination Application Security Group ID's + * `access` - (Required) Specifies whether network traffic is allowed or denied. Possible values are `Allow` and `Deny`. * `priority` - (Required) Specifies the priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule. diff --git a/website/docs/r/network_security_rule.html.markdown b/website/docs/r/network_security_rule.html.markdown index ca66264b5419..f1c565af9226 100644 --- a/website/docs/r/network_security_rule.html.markdown +++ b/website/docs/r/network_security_rule.html.markdown @@ -70,10 +70,14 @@ The following arguments are supported: * `source_address_prefixes` - (Optional) List of source address prefixes. Tags may not be used. This is required if `source_address_prefix` is not specified. +* `source_application_security_group_ids` - (Optional) A List of source Application Security Group ID's + * `destination_address_prefix` - (Optional) CIDR or destination IP range or * to match any IP. Tags such as ‘VirtualNetwork’, ‘AzureLoadBalancer’ and ‘Internet’ can also be used. This is required if `destination_address_prefixes` is not specified. * `destination_address_prefixes` - (Optional) List of destination address prefixes. Tags may not be used. This is required if `destination_address_prefix` is not specified. +* `destination_application_security_group_ids` - (Optional) A List of destination Application Security Group ID's + * `access` - (Required) Specifies whether network traffic is allowed or denied. Possible values are `Allow` and `Deny`. * `priority` - (Required) Specifies the priority of the rule. The value can be between 100 and 4096. The priority number must be unique for each rule in the collection. The lower the priority number, the higher the priority of the rule.