From f8d3717bc8641c0bfc9368e95c6e87b19954da2e Mon Sep 17 00:00:00 2001 From: catriona-m <86247157+catriona-m@users.noreply.github.com> Date: Thu, 9 Sep 2021 02:24:28 +0100 Subject: [PATCH] azurerm_virtual_network_gateway_resource - Allow multiple vpn auth types (#13228) Co-authored-by: Johann Weging --- .../virtual_network_gateway_resource.go | 94 +++++++++---------- .../virtual_network_gateway_resource_test.go | 86 +++++++++++++++++ .../r/virtual_network_gateway.html.markdown | 22 ++--- 3 files changed, 138 insertions(+), 64 deletions(-) diff --git a/internal/services/network/virtual_network_gateway_resource.go b/internal/services/network/virtual_network_gateway_resource.go index b900bcdeb990..c8a4281576f3 100644 --- a/internal/services/network/virtual_network_gateway_resource.go +++ b/internal/services/network/virtual_network_gateway_resource.go @@ -178,45 +178,19 @@ func resourceVirtualNetworkGateway() *pluginsdk.Resource { "aad_tenant": { Type: pluginsdk.TypeString, Optional: true, - ConflictsWith: []string{ - "vpn_client_configuration.0.radius_server_address", - "vpn_client_configuration.0.radius_server_secret", - "vpn_client_configuration.0.root_certificate", - "vpn_client_configuration.0.revoked_certificate", - }, }, "aad_audience": { Type: pluginsdk.TypeString, Optional: true, - ConflictsWith: []string{ - "vpn_client_configuration.0.radius_server_address", - "vpn_client_configuration.0.radius_server_secret", - "vpn_client_configuration.0.root_certificate", - "vpn_client_configuration.0.revoked_certificate", - }, }, "aad_issuer": { Type: pluginsdk.TypeString, Optional: true, - ConflictsWith: []string{ - "vpn_client_configuration.0.radius_server_address", - "vpn_client_configuration.0.radius_server_secret", - "vpn_client_configuration.0.root_certificate", - "vpn_client_configuration.0.revoked_certificate", - }, }, "root_certificate": { Type: pluginsdk.TypeSet, Optional: true, - - ConflictsWith: []string{ - "vpn_client_configuration.0.aad_tenant", - "vpn_client_configuration.0.aad_audience", - "vpn_client_configuration.0.aad_issuer", - "vpn_client_configuration.0.radius_server_address", - "vpn_client_configuration.0.radius_server_secret", - }, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "name": { @@ -235,13 +209,6 @@ func resourceVirtualNetworkGateway() *pluginsdk.Resource { "revoked_certificate": { Type: pluginsdk.TypeSet, Optional: true, - ConflictsWith: []string{ - "vpn_client_configuration.0.aad_tenant", - "vpn_client_configuration.0.aad_audience", - "vpn_client_configuration.0.aad_issuer", - "vpn_client_configuration.0.radius_server_address", - "vpn_client_configuration.0.radius_server_secret", - }, Elem: &pluginsdk.Resource{ Schema: map[string]*pluginsdk.Schema{ "name": { @@ -258,27 +225,28 @@ func resourceVirtualNetworkGateway() *pluginsdk.Resource { }, "radius_server_address": { - Type: pluginsdk.TypeString, - Optional: true, - ConflictsWith: []string{ - "vpn_client_configuration.0.aad_tenant", - "vpn_client_configuration.0.aad_audience", - "vpn_client_configuration.0.aad_issuer", - "vpn_client_configuration.0.root_certificate", - "vpn_client_configuration.0.revoked_certificate", - }, + Type: pluginsdk.TypeString, + Optional: true, ValidateFunc: validation.IsIPv4Address, }, "radius_server_secret": { Type: pluginsdk.TypeString, Optional: true, - ConflictsWith: []string{ - "vpn_client_configuration.0.aad_tenant", - "vpn_client_configuration.0.aad_audience", - "vpn_client_configuration.0.aad_issuer", - "vpn_client_configuration.0.root_certificate", - "vpn_client_configuration.0.revoked_certificate", + }, + + "vpn_auth_types": { + Type: pluginsdk.TypeSet, + Optional: true, + Computed: true, + MaxItems: 3, + Elem: &pluginsdk.Schema{ + Type: pluginsdk.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(network.VpnAuthenticationTypeCertificate), + string(network.VpnAuthenticationTypeAAD), + string(network.VpnAuthenticationTypeRadius), + }, false), }, }, @@ -788,6 +756,12 @@ func expandVirtualNetworkGatewayVpnClientConfig(d *pluginsdk.ResourceData) *netw confRadiusServerAddress := conf["radius_server_address"].(string) confRadiusServerSecret := conf["radius_server_secret"].(string) + var vpnAuthTypes []network.VpnAuthenticationType + for _, vpnAuthType := range conf["vpn_auth_types"].(*pluginsdk.Set).List() { + a := network.VpnAuthenticationType(vpnAuthType.(string)) + vpnAuthTypes = append(vpnAuthTypes, a) + } + return &network.VpnClientConfiguration{ VpnClientAddressPool: &network.AddressSpace{ AddressPrefixes: &addresses, @@ -800,6 +774,7 @@ func expandVirtualNetworkGatewayVpnClientConfig(d *pluginsdk.ResourceData) *netw VpnClientProtocols: &vpnClientProtocols, RadiusServerAddress: &confRadiusServerAddress, RadiusServerSecret: &confRadiusServerSecret, + VpnAuthenticationTypes: &vpnAuthTypes, } } @@ -966,6 +941,14 @@ func flattenVirtualNetworkGatewayVpnClientConfig(cfg *network.VpnClientConfigura } flat["vpn_client_protocols"] = vpnClientProtocols + vpnAuthTypes := &pluginsdk.Set{F: pluginsdk.HashString} + if authTypes := cfg.VpnAuthenticationTypes; authTypes != nil { + for _, authType := range *authTypes { + vpnAuthTypes.Add(string(authType)) + } + } + flat["vpn_auth_types"] = vpnAuthTypes + if v := cfg.RadiusServerAddress; v != nil { flat["radius_server_address"] = *v } @@ -1067,6 +1050,21 @@ func resourceVirtualNetworkGatewayCustomizeDiff(ctx context.Context, diff *plugi if !hasRadiusAddress && hasRadiusSecret { return fmt.Errorf("if radius_server_secret is set radius_server_address must also be set") } + + hasRootCert := len(vpnClientConfig["root_certificate"].(*pluginsdk.Set).List()) > 0 + + vpnAuthTypes := utils.ExpandStringSlice(vpnClientConfig["vpn_auth_types"].(*pluginsdk.Set).List()) + for _, authType := range *vpnAuthTypes { + if authType == "Certificate" && !hasRootCert { + return fmt.Errorf("if Certificate is listed in vpn_auth_types then root_certificate must also be set") + } + if authType == "Radius" && (!hasRadiusAddress || !hasRadiusSecret) { + return fmt.Errorf("if Radius is listed in vpn_auth_types then radius_server_address and radius_server_secret must also be set") + } + if authType == "AAD" && (!hasAadTenant || !hasAadIssuer || !hasAadAudience) { + return fmt.Errorf("if AAD is listed in vpn_auth_types then aad_issuer, aad_tenant and aad_audience must also be set") + } + } } } return nil diff --git a/internal/services/network/virtual_network_gateway_resource_test.go b/internal/services/network/virtual_network_gateway_resource_test.go index 40612d685989..7636908aaead 100644 --- a/internal/services/network/virtual_network_gateway_resource_test.go +++ b/internal/services/network/virtual_network_gateway_resource_test.go @@ -199,6 +199,28 @@ func TestAccVirtualNetworkGateway_vpnClientConfigOpenVPN(t *testing.T) { }) } +func TestAccVirtualNetworkGateway_vpnClientConfigMultipleAuthTypes(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_virtual_network_gateway", "test") + r := VirtualNetworkGatewayResource{} + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.vpnClientConfigMultipleAuthTypes(data), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + check.That(data.ResourceName).Key("vpn_client_configuration.0.vpn_client_protocols.#").HasValue("1"), + check.That(data.ResourceName).Key("vpn_client_configuration.0.vpn_auth_types.0").HasValue("AAD"), + check.That(data.ResourceName).Key("vpn_client_configuration.0.vpn_auth_types.1").HasValue("Radius"), + check.That(data.ResourceName).Key("vpn_client_configuration.0.aad_tenant").IsSet(), + check.That(data.ResourceName).Key("vpn_client_configuration.0.aad_audience").HasValue("41b23e61-6c1e-4545-b367-cd054e0ed4b4"), + check.That(data.ResourceName).Key("vpn_client_configuration.0.aad_issuer").IsSet(), + check.That(data.ResourceName).Key("vpn_client_configuration.0.radius_server_address").HasValue("1.2.3.4"), + check.That(data.ResourceName).Key("vpn_client_configuration.0.radius_server_secret").HasValue("1234"), + ), + }, + }) +} + func TestAccVirtualNetworkGateway_enableBgp(t *testing.T) { data := acceptance.BuildTestData(t, "azurerm_virtual_network_gateway", "test") r := VirtualNetworkGatewayResource{} @@ -1324,3 +1346,67 @@ resource "azurerm_virtual_network_gateway" "test" { } `, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.RandomInteger) } + +func (VirtualNetworkGatewayResource) vpnClientConfigMultipleAuthTypes(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_prefix = "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" { + depends_on = [azurerm_public_ip.test] + name = "acctestvng-%d" + location = azurerm_resource_group.test.location + resource_group_name = azurerm_resource_group.test.name + + type = "Vpn" + vpn_type = "RouteBased" + sku = "VpnGw1" + + ip_configuration { + public_ip_address_id = azurerm_public_ip.test.id + private_ip_address_allocation = "Dynamic" + subnet_id = azurerm_subnet.test.id + } + + vpn_client_configuration { + address_space = ["10.2.0.0/24"] + vpn_client_protocols = ["OpenVPN"] + vpn_auth_types = ["AAD", "Radius"] + + aad_tenant = "https://login.microsoftonline.com/%s/" + aad_audience = "41b23e61-6c1e-4545-b367-cd054e0ed4b4" + aad_issuer = "https://sts.windows.net/%s/" + + radius_server_address = "1.2.3.4" + radius_server_secret = "1234" + } +} +`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, data.Client().TenantID, data.Client().TenantID) +} diff --git a/website/docs/r/virtual_network_gateway.html.markdown b/website/docs/r/virtual_network_gateway.html.markdown index d6c60855ef7f..888260490118 100644 --- a/website/docs/r/virtual_network_gateway.html.markdown +++ b/website/docs/r/virtual_network_gateway.html.markdown @@ -190,42 +190,32 @@ The `vpn_client_configuration` block supports: in CIDR notation. * `aad_tenant` - (Optional) AzureAD Tenant URL - This setting is incompatible with the use of - `root_certificate` and `revoked_certificate`, `radius_server_address`, and `radius_server_secret`. * `aad_audience` - (Optional) The client id of the Azure VPN application. See [Create an Active Directory (AD) tenant for P2S OpenVPN protocol connections](https://docs.microsoft.com/en-gb/azure/vpn-gateway/openvpn-azure-ad-tenant-multi-app) for values - This setting is incompatible with the use of - `root_certificate` and `revoked_certificate`, `radius_server_address`, and `radius_server_secret`. - + * `aad_issuer` - (Optional) The STS url for your tenant - This setting is incompatible with the use of - `root_certificate` and `revoked_certificate`, `radius_server_address`, and `radius_server_secret`. * `root_certificate` - (Optional) One or more `root_certificate` blocks which are defined below. These root certificates are used to sign the client certificate used by the VPN clients to connect to the gateway. - This setting is incompatible with the use of - `aad_tenant`, `aad_audience`, `aad_issuer`, `radius_server_address`, and `radius_server_secret`. * `revoked_certificate` - (Optional) One or more `revoked_certificate` blocks which are defined below. - This setting is incompatible with the use of - `aad_tenant`, `aad_audience`, `aad_issuer`, `radius_server_address`, and `radius_server_secret`. * `radius_server_address` - (Optional) The address of the Radius server. - This setting is incompatible with the use of - `aad_tenant`, `aad_audience`, `aad_issuer`, `root_certificate` and `revoked_certificate`. * `radius_server_secret` - (Optional) The secret used by the Radius server. - This setting is incompatible with the use of - `aad_tenant`, `aad_audience`, `aad_issuer`, `root_certificate` and `revoked_certificate`. * `vpn_client_protocols` - (Optional) List of the protocols supported by the vpn client. The supported values are `SSTP`, `IkeV2` and `OpenVPN`. Values `SSTP` and `IkeV2` are incompatible with the use of `aad_tenant`, `aad_audience` and `aad_issuer`. - + +* `vpn_auth_types` - (Optional) List of the vpn authentication types for the virtual network gateway. + The supported values are `AAD`, `Radius` and `Certificate`. + +-> **NOTE:** `vpn_auth_types` must be set when using multiple vpn authentication types. --- The `bgp_settings` block supports: