From e6655756ccd960726cfd22da01c27c0ff37213ab Mon Sep 17 00:00:00 2001 From: kt Date: Thu, 12 Sep 2019 09:39:25 -0700 Subject: [PATCH] azurerm_application_gateway: add trusted root cert property (#4206) fixes #3115 --- azurerm/resource_arm_application_gateway.go | 230 +++++++--- .../resource_arm_application_gateway_test.go | 404 +++++++++++++++++- go.mod | 2 +- .../docs/r/application_gateway.html.markdown | 10 + 4 files changed, 584 insertions(+), 62 deletions(-) diff --git a/azurerm/resource_arm_application_gateway.go b/azurerm/resource_arm_application_gateway.go index 50ca1a2797e4..99bded2a6a2f 100644 --- a/azurerm/resource_arm_application_gateway.go +++ b/azurerm/resource_arm_application_gateway.go @@ -678,21 +678,56 @@ func resourceArmApplicationGateway() *schema.Resource { // Optional "authentication_certificate": { - Type: schema.TypeList, + Type: schema.TypeList, // todo this should probably be a map Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + }, + + "data": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + Sensitive: true, + }, + + "id": { Type: schema.TypeString, - Required: true, + Computed: true, + }, + }, + }, + }, + + "trusted_root_certificate": { + Type: schema.TypeList, // todo this should probably be a map + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, }, "data": { - Type: schema.TypeString, - Required: true, - Sensitive: true, + Type: schema.TypeString, + Required: true, + ValidateFunc: validate.NoEmptyStrings, + Sensitive: true, }, + // TODO required soft delete on the keyvault + /*"key_vault_secret_id": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: azure.ValidateKeyVaultChildId, + },*/ + "id": { Type: schema.TypeString, Computed: true, @@ -1334,21 +1369,10 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte gatewayIDFmt := "/subscriptions/%s/resourceGroups/%s/providers/Microsoft.Network/applicationGateways/%s" gatewayID := fmt.Sprintf(gatewayIDFmt, armClient.subscriptionId, resGroup, name) - authenticationCertificates := expandApplicationGatewayAuthenticationCertificates(d) - backendAddressPools := expandApplicationGatewayBackendAddressPools(d) - backendHTTPSettingsCollection := expandApplicationGatewayBackendHTTPSettings(d, gatewayID) - frontendIPConfigurations := expandApplicationGatewayFrontendIPConfigurations(d) - frontendPorts := expandApplicationGatewayFrontendPorts(d) - gatewayIPConfigurations, stopApplicationGateway := expandApplicationGatewayIPConfigurations(d) - httpListeners := expandApplicationGatewayHTTPListeners(d, gatewayID) - probes := expandApplicationGatewayProbes(d) - sku := expandApplicationGatewaySku(d) - autoscaleConfiguration := expandApplicationGatewayAutoscaleConfiguration(d) - sslCertificates := expandApplicationGatewaySslCertificates(d) - sslPolicy := expandApplicationGatewaySslPolicy(d) - customErrorConfigurations := expandApplicationGatewayCustomErrorConfigurations(d.Get("custom_error_configuration").([]interface{})) - rewriteRuleSets := expandApplicationGatewayRewriteRuleSets(d) - zones := azure.ExpandZones(d.Get("zones").([]interface{})) + trustedRootCertificates, err := expandApplicationGatewayTrustedRootCertificates(d.Get("trusted_root_certificate").([]interface{})) + if err != nil { + return fmt.Errorf("Error expanding `trusted_root_certificate`: %+v", err) + } requestRoutingRules, err := expandApplicationGatewayRequestRoutingRules(d, gatewayID) if err != nil { @@ -1365,30 +1389,34 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte return fmt.Errorf("Error expanding `redirect_configuration`: %+v", err) } + gatewayIPConfigurations, stopApplicationGateway := expandApplicationGatewayIPConfigurations(d) + gateway := network.ApplicationGateway{ Location: utils.String(location), - Zones: zones, + Zones: azure.ExpandZones(d.Get("zones").([]interface{})), Tags: tags.Expand(t), ApplicationGatewayPropertiesFormat: &network.ApplicationGatewayPropertiesFormat{ - AuthenticationCertificates: authenticationCertificates, - BackendAddressPools: backendAddressPools, - BackendHTTPSettingsCollection: backendHTTPSettingsCollection, + AutoscaleConfiguration: expandApplicationGatewayAutoscaleConfiguration(d), + AuthenticationCertificates: expandApplicationGatewayAuthenticationCertificates(d.Get("authentication_certificate").([]interface{})), + TrustedRootCertificates: trustedRootCertificates, + CustomErrorConfigurations: expandApplicationGatewayCustomErrorConfigurations(d.Get("custom_error_configuration").([]interface{})), + BackendAddressPools: expandApplicationGatewayBackendAddressPools(d), + BackendHTTPSettingsCollection: expandApplicationGatewayBackendHTTPSettings(d, gatewayID), EnableHTTP2: utils.Bool(enablehttp2), - FrontendIPConfigurations: frontendIPConfigurations, - FrontendPorts: frontendPorts, + FrontendIPConfigurations: expandApplicationGatewayFrontendIPConfigurations(d), + FrontendPorts: expandApplicationGatewayFrontendPorts(d), GatewayIPConfigurations: gatewayIPConfigurations, - HTTPListeners: httpListeners, - Probes: probes, + HTTPListeners: expandApplicationGatewayHTTPListeners(d, gatewayID), + Probes: expandApplicationGatewayProbes(d), RequestRoutingRules: requestRoutingRules, RedirectConfigurations: redirectConfigurations, - Sku: sku, - SslCertificates: sslCertificates, - SslPolicy: sslPolicy, - CustomErrorConfigurations: customErrorConfigurations, - RewriteRuleSets: rewriteRuleSets, - URLPathMaps: urlPathMaps, - AutoscaleConfiguration: autoscaleConfiguration, + Sku: expandApplicationGatewaySku(d), + SslCertificates: expandApplicationGatewaySslCertificates(d), + SslPolicy: expandApplicationGatewaySslPolicy(d), + + RewriteRuleSets: expandApplicationGatewayRewriteRuleSets(d), + URLPathMaps: urlPathMaps, }, } @@ -1396,7 +1424,8 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte gateway.Identity = expandAzureRmApplicationGatewayIdentity(d) } - for _, backendHttpSettings := range *backendHTTPSettingsCollection { + // validation (todo these should probably be moved into their respective expand functions, which would then return an error?) + for _, backendHttpSettings := range *gateway.ApplicationGatewayPropertiesFormat.BackendHTTPSettingsCollection { if props := backendHttpSettings.ApplicationGatewayBackendHTTPSettingsPropertiesFormat; props != nil { if props.HostName == nil || props.PickHostNameFromBackendAddress == nil { continue @@ -1408,7 +1437,7 @@ func resourceArmApplicationGatewayCreateUpdate(d *schema.ResourceData, meta inte } } - for _, probe := range *probes { + for _, probe := range *gateway.ApplicationGatewayPropertiesFormat.Probes { if props := probe.ApplicationGatewayProbePropertiesFormat; props != nil { if props.Host == nil || props.PickHostNameFromBackendHTTPSettings == nil { continue @@ -1502,14 +1531,17 @@ func resourceArmApplicationGatewayRead(d *schema.ResourceData, meta interface{}) d.Set("zones", applicationGateway.Zones) identity := flattenRmApplicationGatewayIdentity(applicationGateway.Identity) - if err := d.Set("identity", identity); err != nil { + if err = d.Set("identity", identity); err != nil { return err } if props := applicationGateway.ApplicationGatewayPropertiesFormat; props != nil { - flattenedCerts := flattenApplicationGatewayAuthenticationCertificates(props.AuthenticationCertificates, d) - if setErr := d.Set("authentication_certificate", flattenedCerts); setErr != nil { - return fmt.Errorf("Error setting `authentication_certificate`: %+v", setErr) + if err = d.Set("authentication_certificate", flattenApplicationGatewayAuthenticationCertificates(props.AuthenticationCertificates, d)); err != nil { + return fmt.Errorf("Error setting `authentication_certificate`: %+v", err) + } + + if err = d.Set("trusted_root_certificate", flattenApplicationGatewayTrustedRootCertificates(props.TrustedRootCertificates, d)); err != nil { + return fmt.Errorf("Error setting `trusted_root_certificate`: %+v", err) } if setErr := d.Set("backend_address_pool", flattenApplicationGatewayBackendAddressPools(props.BackendAddressPools)); setErr != nil { @@ -1678,11 +1710,10 @@ func flattenRmApplicationGatewayIdentity(identity *network.ManagedServiceIdentit return []interface{}{result} } -func expandApplicationGatewayAuthenticationCertificates(d *schema.ResourceData) *[]network.ApplicationGatewayAuthenticationCertificate { - vs := d.Get("authentication_certificate").([]interface{}) +func expandApplicationGatewayAuthenticationCertificates(certs []interface{}) *[]network.ApplicationGatewayAuthenticationCertificate { results := make([]network.ApplicationGatewayAuthenticationCertificate, 0) - for _, raw := range vs { + for _, raw := range certs { v := raw.(map[string]interface{}) name := v["name"].(string) @@ -1704,31 +1735,112 @@ func expandApplicationGatewayAuthenticationCertificates(d *schema.ResourceData) return &results } -func flattenApplicationGatewayAuthenticationCertificates(input *[]network.ApplicationGatewayAuthenticationCertificate, d *schema.ResourceData) []interface{} { +func expandApplicationGatewayTrustedRootCertificates(certs []interface{}) (*[]network.ApplicationGatewayTrustedRootCertificate, error) { + results := make([]network.ApplicationGatewayTrustedRootCertificate, 0) + + for _, raw := range certs { + v := raw.(map[string]interface{}) + + name := v["name"].(string) + data := v["data"].(string) + // kvsid := v["key_vault_secret_id"].(string) + + output := network.ApplicationGatewayTrustedRootCertificate{ + Name: utils.String(name), + ApplicationGatewayTrustedRootCertificatePropertiesFormat: &network.ApplicationGatewayTrustedRootCertificatePropertiesFormat{}, + } + + /* if data == "" && kvsid == "" { + return nil, fmt.Errorf("Error: either `key_vault_secret_id` or `data` must be specified for the `trusted_root_certificate` block %q", name) + } + if data != "" && kvsid != "" { + return nil, fmt.Errorf("Error: only one of `key_vault_secret_id` or `data` must be specified for the `trusted_root_certificate` block %q", name) + }*/ + + if data != "" { + output.ApplicationGatewayTrustedRootCertificatePropertiesFormat.Data = utils.String(utils.Base64EncodeIfNot(data)) + } + // output.ApplicationGatewayTrustedRootCertificatePropertiesFormat.KeyVaultSecretID = &kvsid + + results = append(results, output) + } + + return &results, nil +} + +func flattenApplicationGatewayAuthenticationCertificates(certs *[]network.ApplicationGatewayAuthenticationCertificate, d *schema.ResourceData) []interface{} { results := make([]interface{}, 0) - if input == nil { + if certs == nil { return results } - for i, v := range *input { + // since the certificate data isn't returned lets load any existing data + nameToDataMap := map[string]string{} + if existing, ok := d.GetOk("authentication_certificate"); ok && existing != nil { + for _, c := range existing.([]interface{}) { + b := c.(map[string]interface{}) + nameToDataMap[b["name"].(string)] = b["data"].(string) + } + } + + for _, cert := range *certs { output := map[string]interface{}{} - if v.ID != nil { - output["id"] = *v.ID + if v := cert.ID; v != nil { + output["id"] = *v } - if v.Name != nil { - output["name"] = *v.Name + if v := cert.Name; v != nil { + output["name"] = *v + + // we have a name, so try and look up the old data to pass it along + if data, ok := nameToDataMap[*v]; ok && data != "" { + output["data"] = data + } } - // since the certificate data isn't returned we have to load it from the same index - if existing, ok := d.GetOk("authentication_certificate"); ok && existing != nil { - existingVals := existing.([]interface{}) - if len(existingVals) > i { - existingCerts := existingVals[i].(map[string]interface{}) - if data := existingCerts["data"]; data != nil { - output["data"] = data.(string) - } + results = append(results, output) + } + + return results +} + +func flattenApplicationGatewayTrustedRootCertificates(certs *[]network.ApplicationGatewayTrustedRootCertificate, d *schema.ResourceData) []interface{} { + results := make([]interface{}, 0) + if certs == nil { + return results + } + + // since the certificate data isn't returned lets load any existing data + nameToDataMap := map[string]string{} + if existing, ok := d.GetOk("trusted_root_certificate"); ok && existing != nil { + for _, c := range existing.([]interface{}) { + b := c.(map[string]interface{}) + nameToDataMap[b["name"].(string)] = b["data"].(string) + } + } + + for _, cert := range *certs { + output := map[string]interface{}{} + + if v := cert.ID; v != nil { + output["id"] = *v + } + + /*kvsid := "" + if props := cert.ApplicationGatewayTrustedRootCertificatePropertiesFormat; props != nil { + if v := props.KeyVaultSecretID; v != nil { + kvsid = *v + output["key_vault_secret_id"] = *v + } + }*/ + + if v := cert.Name; v != nil { + output["name"] = *v + + // if theres no key vauld ID and we have a name, so try and look up the old data to pass it along + if data, ok := nameToDataMap[*v]; ok && data != "" { + output["data"] = data } } diff --git a/azurerm/resource_arm_application_gateway_test.go b/azurerm/resource_arm_application_gateway_test.go index 70de9e17c017..e7dfd9528404 100644 --- a/azurerm/resource_arm_application_gateway_test.go +++ b/azurerm/resource_arm_application_gateway_test.go @@ -263,6 +263,81 @@ func TestAccAzureRMApplicationGateway_authCertificate(t *testing.T) { }) } +// TODO required soft delete on the keyvault +func TestAccAzureRMApplicationGateway_trustedRootCertificate_keyvault(t *testing.T) { + t.Skip() + + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_trustedRootCertificate_keyvault(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "trusted_root_certificate.0.name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAzureRMApplicationGateway_trustedRootCertificate(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + location := testLocation() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_trustedRootCertificate(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "trusted_root_certificate.0.name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + // since these are read from the existing state + "trusted_root_certificate.0.data", + }, + }, + { + Config: testAccAzureRMApplicationGateway_trustedRootCertificateUpdated(ri, location), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttrSet(resourceName, "trusted_root_certificate.0.name"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + // since these are read from the existing state + "trusted_root_certificate.0.data", + }, + }, + }, + }) +} + func TestAccAzureRMApplicationGateway_pathBasedRouting(t *testing.T) { resourceName := "azurerm_application_gateway.test" ri := tf.AccRandTimeInt() @@ -792,6 +867,7 @@ func TestAccAzureRMApplicationGateway_webApplicationFirewall_exclusions(t *testi }, }) } + func TestAccAzureRMApplicationGateway_sslPolicy_policyType_predefined(t *testing.T) { resourceName := "azurerm_application_gateway.test" ri := tf.AccRandTimeInt() @@ -836,6 +912,7 @@ func TestAccAzureRMApplicationGateway_sslPolicy_policyType_custom(t *testing.T) }, }) } + func TestAccAzureRMApplicationGateway_sslPolicy_disabledProtocols(t *testing.T) { resourceName := "azurerm_application_gateway.test" ri := tf.AccRandTimeInt() @@ -949,6 +1026,7 @@ func TestAccAzureRMApplicationGateway_gatewayIP(t *testing.T) { }, }) } + func TestAccAzureRMApplicationGateway_UserAssignedIdentity(t *testing.T) { resourceName := "azurerm_application_gateway.test" ri := tf.AccRandTimeInt() @@ -1720,10 +1798,246 @@ resource "azurerm_application_gateway" "test" { `, template, rInt) } +func testAccAzureRMApplicationGateway_trustedRootCertificate_keyvault(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%[1]s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + auth_cert_name = "${azurerm_virtual_network.test.name}-auth" + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +data "azurerm_client_config" "test" {} + +data "azuread_service_principal" "test" { + display_name = "Microsoft Azure App Service" +} + +resource "azurerm_user_assigned_identity" "test" { + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + name = "acctest%[2]d" +} + +resource "azurerm_public_ip" "testStd" { + name = "acctest-PubIpStd-%[2]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_key_vault" "test" { + name = "acct%[2]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + tenant_id = "${data.azurerm_client_config.test.tenant_id}" + sku_name = "standard" + + access_policy { + tenant_id = "${data.azurerm_client_config.test.tenant_id}" + object_id = "${data.azurerm_client_config.test.service_principal_object_id }" + secret_permissions = ["delete", "get", "set"] + certificate_permissions = ["create", "delete", "get", "import"] + } + + access_policy { + tenant_id = "${data.azurerm_client_config.test.tenant_id}" + object_id = "${azurerm_user_assigned_identity.test.principal_id}" + secret_permissions = ["get"] + certificate_permissions = ["get"] + } +} + +resource "azurerm_key_vault_certificate" "test" { + name = "acctest%[2]d" + key_vault_id = "${azurerm_key_vault.test.id}" + + certificate { + contents = filebase64("testdata/app_service_certificate.pfx") + password = "terraform" + } + + 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" + } + } +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%[2]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + sku { + name = "WAF_v2" + tier = "WAF_v2" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = "${azurerm_subnet.test.id}" + } + + identity { + identity_ids = ["${azurerm_user_assigned_identity.test.id}"] + } + + frontend_port { + name = "${local.frontend_port_name}" + port = 80 + } + + frontend_ip_configuration { + name = "${local.frontend_ip_configuration_name}" + public_ip_address_id = "${azurerm_public_ip.testStd.id}" + } + + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 443 + protocol = "Https" + request_timeout = 1 + } + + trusted_root_certificate { + name = "${local.auth_cert_name}" + key_vault_secret_id = "${azurerm_key_vault_certificate.test.secret_id}" + } + + http_listener { + name = "${local.listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name}" + protocol = "Http" + } + + request_routing_rule { + name = "${local.request_routing_rule_name}" + rule_type = "Basic" + http_listener_name = "${local.listener_name}" + backend_address_pool_name = "${local.backend_address_pool_name}" + backend_http_settings_name = "${local.http_setting_name}" + } +} +`, template, rInt) +} + +func testAccAzureRMApplicationGateway_trustedRootCertificate(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%[1]s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + auth_cert_name = "${azurerm_virtual_network.test.name}-auth" + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +resource "azurerm_public_ip" "teststd" { + name = "acctest-PubIpStd-%[2]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" + sku = "Standard" +} + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%[2]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + sku { + name = "WAF_v2" + tier = "WAF_v2" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = "${azurerm_subnet.test.id}" + } + + frontend_port { + name = "${local.frontend_port_name}" + port = 80 + } + + frontend_ip_configuration { + name = "${local.frontend_ip_configuration_name}" + public_ip_address_id = "${azurerm_public_ip.teststd.id}" + } + + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 443 + protocol = "Https" + request_timeout = 1 + } + + trusted_root_certificate { + name = "${local.auth_cert_name}" + data = "${file("testdata/application_gateway_test.cer")}" + } + + http_listener { + name = "${local.listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name}" + protocol = "Http" + } + + request_routing_rule { + name = "${local.request_routing_rule_name}" + rule_type = "Basic" + http_listener_name = "${local.listener_name}" + backend_address_pool_name = "${local.backend_address_pool_name}" + backend_http_settings_name = "${local.http_setting_name}" + } +} +`, template, rInt) +} + func testAccAzureRMApplicationGateway_authCertificateUpdated(rInt int, location string) string { template := testAccAzureRMApplicationGateway_template(rInt, location) return fmt.Sprintf(` -%s +%[1]s # since these variables are re-used - a locals block makes this more maintainable locals { @@ -1737,7 +2051,7 @@ locals { } resource "azurerm_application_gateway" "test" { - name = "acctestag-%d" + name = "acctestag-%[2]d" resource_group_name = "${azurerm_resource_group.test.name}" location = "${azurerm_resource_group.test.location}" @@ -1801,6 +2115,92 @@ resource "azurerm_application_gateway" "test" { `, template, rInt) } +func testAccAzureRMApplicationGateway_trustedRootCertificateUpdated(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%[1]s + +# since these variables are re-used - a locals block makes this more maintainable +locals { + auth_cert_name = "${azurerm_virtual_network.test.name}-auth2" + backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap" + frontend_port_name = "${azurerm_virtual_network.test.name}-feport" + frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip" + http_setting_name = "${azurerm_virtual_network.test.name}-be-htst" + listener_name = "${azurerm_virtual_network.test.name}-httplstn" + request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt" +} + +resource "azurerm_public_ip" "teststd" { + name = "acctest-PubIpStd-%[2]d" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + allocation_method = "Static" + sku = "Standard" +} + + +resource "azurerm_application_gateway" "test" { + name = "acctestag-%[2]d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + + sku { + name = "WAF_v2" + tier = "WAF_v2" + capacity = 2 + } + + gateway_ip_configuration { + name = "my-gateway-ip-configuration" + subnet_id = "${azurerm_subnet.test.id}" + } + + frontend_port { + name = "${local.frontend_port_name}" + port = 80 + } + + frontend_ip_configuration { + name = "${local.frontend_ip_configuration_name}" + public_ip_address_id = "${azurerm_public_ip.teststd.id}" + } + + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 443 + protocol = "Https" + request_timeout = 1 + } + + trusted_root_certificate { + name = "${local.auth_cert_name}" + data = "${file("testdata/application_gateway_test_2.crt")}" + } + + http_listener { + name = "${local.listener_name}" + frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}" + frontend_port_name = "${local.frontend_port_name}" + protocol = "Http" + } + + request_routing_rule { + name = "${local.request_routing_rule_name}" + rule_type = "Basic" + http_listener_name = "${local.listener_name}" + backend_address_pool_name = "${local.backend_address_pool_name}" + backend_http_settings_name = "${local.http_setting_name}" + } +} +`, template, rInt) +} + func testAccAzureRMApplicationGateway_pathBasedRouting(rInt int, location string) string { template := testAccAzureRMApplicationGateway_template(rInt, location) return fmt.Sprintf(` diff --git a/go.mod b/go.mod index f2948a6ec38d..148c2032d8b5 100644 --- a/go.mod +++ b/go.mod @@ -21,4 +21,4 @@ require ( golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 golang.org/x/net v0.0.0-20190502183928-7f726cade0ab gopkg.in/yaml.v2 v2.2.2 -) \ No newline at end of file +) diff --git a/website/docs/r/application_gateway.html.markdown b/website/docs/r/application_gateway.html.markdown index 9ae719f0cc2e..ed3b0cb14ff0 100644 --- a/website/docs/r/application_gateway.html.markdown +++ b/website/docs/r/application_gateway.html.markdown @@ -149,6 +149,8 @@ The following arguments are supported: * `authentication_certificate` - (Optional) One or more `authentication_certificate` blocks as defined below. +* `trusted_root_certificate` - (Optional) One or more `trusted_root_certificate` blocks as defined below. + * `disabled_ssl_protocols` - (Optional / **Deprecated**) A list of SSL Protocols which should be disabled on this Application Gateway. Possible values are `TLSv1_0`, `TLSv1_1` and `TLSv1_2`. ~> **NOTE:** `disabled_ssl_protocols ` has been deprecated in favour of `disabled_protocols` in the `ssl_policy` block. @@ -184,6 +186,14 @@ A `authentication_certificate` block supports the following: --- +A `trusted_root_certificate` block supports the following: + +* `name` - (Required) The Name of the Authentication Certificate to use. + +* `data` - (Required) The contents of the Authentication Certificate which should be used. + +--- + A `authentication_certificate` block, within the `backend_http_settings` block supports the following: * `name` - (Required) The name of the Authentication Certificate.