diff --git a/internal/services/network/virtual_network_gateway_connection_resource.go b/internal/services/network/virtual_network_gateway_connection_resource.go index 63ffb782f201..1351c6e73593 100644 --- a/internal/services/network/virtual_network_gateway_connection_resource.go +++ b/internal/services/network/virtual_network_gateway_connection_resource.go @@ -10,6 +10,7 @@ import ( "github.com/hashicorp/terraform-provider-azurerm/helpers/tf" "github.com/hashicorp/terraform-provider-azurerm/internal/clients" "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/parse" + "github.com/hashicorp/terraform-provider-azurerm/internal/services/network/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" @@ -86,6 +87,24 @@ func resourceVirtualNetworkGatewayConnection() *pluginsdk.Resource { ValidateFunc: azure.ValidateResourceIDOrEmpty, }, + "egress_nat_rule_ids": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.VirtualNetworkGatewayNatRuleID, + }, + }, + + "ingress_nat_rule_ids": { + Type: pluginsdk.TypeSet, + Optional: true, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validate.VirtualNetworkGatewayNatRuleID, + }, + }, + "peer_virtual_network_gateway_id": { Type: pluginsdk.TypeString, Optional: true, @@ -501,6 +520,14 @@ func resourceVirtualNetworkGatewayConnectionRead(d *pluginsdk.ResourceData, meta return fmt.Errorf("setting `traffic_selector_policy`: %+v", err) } + if err := d.Set("egress_nat_rule_ids", flattenVirtualNetworkGatewayConnectionNatRuleIds(conn.EgressNatRules)); err != nil { + return fmt.Errorf("setting `egress_nat_rule_ids`: %+v", err) + } + + if err := d.Set("ingress_nat_rule_ids", flattenVirtualNetworkGatewayConnectionNatRuleIds(conn.IngressNatRules)); err != nil { + return fmt.Errorf("setting `ingress_nat_rule_ids`: %+v", err) + } + return tags.FlattenAndSet(d, resp.Tags) } @@ -564,6 +591,14 @@ func getVirtualNetworkGatewayConnectionProperties(d *pluginsdk.ResourceData, vir } } + if v, ok := d.GetOk("egress_nat_rule_ids"); ok { + props.EgressNatRules = expandVirtualNetworkGatewayConnectionNatRuleIds(v.(*pluginsdk.Set).List()) + } + + if v, ok := d.GetOk("ingress_nat_rule_ids"); ok { + props.IngressNatRules = expandVirtualNetworkGatewayConnectionNatRuleIds(v.(*pluginsdk.Set).List()) + } + if v, ok := d.GetOk("peer_virtual_network_gateway_id"); ok { gwid, err := parse.VirtualNetworkGatewayID(v.(string)) if err != nil { @@ -823,3 +858,33 @@ func flattenVirtualNetworkGatewayConnectionTrafficSelectorPolicies(trafficSelect return schemaTrafficSelectorPolicies } + +func expandVirtualNetworkGatewayConnectionNatRuleIds(input []interface{}) *[]network.SubResource { + results := make([]network.SubResource, 0) + + for _, item := range input { + results = append(results, network.SubResource{ + ID: utils.String(item.(string)), + }) + } + + return &results +} + +func flattenVirtualNetworkGatewayConnectionNatRuleIds(input *[]network.SubResource) []interface{} { + results := make([]interface{}, 0) + if input == nil { + return results + } + + for _, item := range *input { + var id string + if item.ID != nil { + id = *item.ID + } + + results = append(results, id) + } + + return results +} diff --git a/internal/services/network/virtual_network_gateway_connection_resource_test.go b/internal/services/network/virtual_network_gateway_connection_resource_test.go index 464bd430d790..f2593fd62dc6 100644 --- a/internal/services/network/virtual_network_gateway_connection_resource_test.go +++ b/internal/services/network/virtual_network_gateway_connection_resource_test.go @@ -233,6 +233,21 @@ func TestAccVirtualNetworkGatewayConnection_useCustomBgpAddresses(t *testing.T) }) } +func TestAccVirtualNetworkGatewayConnection_natRuleIds(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network_gateway_connection", "test") + r := VirtualNetworkGatewayConnectionResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.natRuleIds(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep(), + }) +} + func (t VirtualNetworkGatewayConnectionResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) { gatewayName := state.Attributes["name"] resourceGroup := state.Attributes["resource_group_name"] @@ -1001,7 +1016,7 @@ resource "azurerm_public_ip" "test" { resource_group_name = azurerm_resource_group.test.name allocation_method = "Static" sku = "Standard" - zones = ["1", "2"] + zones = ["3"] } resource "azurerm_virtual_network_gateway" "test" { @@ -1072,6 +1087,7 @@ resource "azurerm_public_ip" "test" { resource_group_name = azurerm_resource_group.test.name allocation_method = "Static" sku = "Standard" + zones = ["3"] } resource "azurerm_virtual_network_gateway" "test" { @@ -1235,3 +1251,115 @@ resource "azurerm_virtual_network_gateway_connection" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } + +func (VirtualNetworkGatewayConnectionResource) natRuleIds(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 = "acctestvn-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + address_space = ["10.0.0.0/16"] +} + +resource "azurerm_subnet" "test" { + name = "GatewaySubnet" + resource_group_name = azurerm_resource_group.test.name + virtual_network_name = azurerm_virtual_network.test.name + address_prefixes = ["10.0.1.0/24"] +} + +resource "azurerm_public_ip" "test" { + name = "acctestpip-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + allocation_method = "Dynamic" +} + +resource "azurerm_virtual_network_gateway" "test" { + name = "acctestvnetgw-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + type = "Vpn" + vpn_type = "RouteBased" + sku = "Basic" + + ip_configuration { + name = "vnetGatewayConfig" + public_ip_address_id = azurerm_public_ip.test.id + private_ip_address_allocation = "Dynamic" + subnet_id = azurerm_subnet.test.id + } +} + +data "azurerm_virtual_network_gateway" "test" { + name = azurerm_virtual_network_gateway.test.name + resource_group_name = azurerm_virtual_network_gateway.test.resource_group_name +} + +resource "azurerm_local_network_gateway" "test" { + name = "acctestlocalnetworkgw-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + gateway_address = "168.62.225.23" + address_space = ["10.1.1.0/24"] +} + +resource "azurerm_virtual_network_gateway_nat_rule" "test" { + name = "acctestvnetgwegressnatrule-%d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_gateway_id = data.azurerm_virtual_network_gateway.test.id + mode = "EgressSnat" + type = "Dynamic" + ip_configuration_id = data.azurerm_virtual_network_gateway.test.ip_configuration.0.id + + external_mapping { + address_space = "10.1.0.0/26" + } + + internal_mapping { + address_space = "10.2.0.0/26" + } +} + +resource "azurerm_virtual_network_gateway_nat_rule" "test2" { + name = "acctestvnetgwingressnatrule-%d" + resource_group_name = azurerm_resource_group.test.name + virtual_network_gateway_id = data.azurerm_virtual_network_gateway.test.id + mode = "IngressSnat" + type = "Dynamic" + ip_configuration_id = data.azurerm_virtual_network_gateway.test.ip_configuration.0.id + + external_mapping { + address_space = "10.7.0.0/26" + } + + internal_mapping { + address_space = "10.8.0.0/26" + } +} + +resource "azurerm_virtual_network_gateway_connection" "test" { + name = "acctestvnetgwconn-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + type = "IPsec" + virtual_network_gateway_id = azurerm_virtual_network_gateway.test.id + local_network_gateway_id = azurerm_local_network_gateway.test.id + + egress_nat_rule_ids = [azurerm_virtual_network_gateway_nat_rule.test.id] + ingress_nat_rule_ids = [azurerm_virtual_network_gateway_nat_rule.test2.id] +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} diff --git a/website/docs/r/virtual_network_gateway_connection.html.markdown b/website/docs/r/virtual_network_gateway_connection.html.markdown index 24b972573c5c..114332be65a9 100644 --- a/website/docs/r/virtual_network_gateway_connection.html.markdown +++ b/website/docs/r/virtual_network_gateway_connection.html.markdown @@ -265,6 +265,10 @@ Changing this value will force a resource to be created. * `express_route_gateway_bypass` - (Optional) If `true`, data packets will bypass ExpressRoute Gateway for data forwarding This is only valid for ExpressRoute connections. +* `egress_nat_rule_ids` - (Optional) A list of the egress NAT Rule Ids. + +* `ingress_nat_rule_ids` - (Optional) A list of the ingress NAT Rule Ids. + * `use_policy_based_traffic_selectors` - (Optional) If `true`, policy-based traffic selectors are enabled for this connection. Enabling policy-based traffic selectors requires an `ipsec_policy` block. Defaults to `false`.