diff --git a/azurerm/resource_arm_application_gateway.go b/azurerm/resource_arm_application_gateway.go index 58bea99717ab..1105334527a4 100644 --- a/azurerm/resource_arm_application_gateway.go +++ b/azurerm/resource_arm_application_gateway.go @@ -14,6 +14,15 @@ import ( "github.com/terraform-providers/terraform-provider-azurerm/azurerm/utils" ) +// See https://github.com/Azure/azure-sdk-for-go/blob/master/services/network/mgmt/2018-04-01/network/models.go +func possibleArmApplicationGatewaySslCipherSuiteValues() []string { + cipherSuites := make([]string, 0) + for _, cipherSuite := range network.PossibleApplicationGatewaySslCipherSuiteValues() { + cipherSuites = append(cipherSuites, string(cipherSuite)) + } + return cipherSuites +} + func resourceArmApplicationGateway() *schema.Resource { return &schema.Resource{ Create: resourceArmApplicationGatewayCreateUpdate, @@ -633,10 +642,12 @@ func resourceArmApplicationGateway() *schema.Resource { }, }, - // TODO: @tombuildsstuff deprecate this in favour of a full `ssl_protocol` block in the future + // TODO: remove in 2.0 "disabled_ssl_protocols": { - Type: schema.TypeList, - Optional: true, + Type: schema.TypeList, + Optional: true, + Computed: true, + Deprecated: "has been replaced by `ssl_policy`.`disabled_protocols`", Elem: &schema.Schema{ Type: schema.TypeString, DiffSuppressFunc: suppress.CaseDifference, @@ -648,6 +659,65 @@ func resourceArmApplicationGateway() *schema.Resource { }, }, + "ssl_policy": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "disabled_protocols": { + Type: schema.TypeList, + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(network.TLSv10), + string(network.TLSv11), + string(network.TLSv12), + }, false), + }, + }, + + "policy_type": { + Type: schema.TypeString, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{ + string(network.Custom), + string(network.Predefined), + }, false), + }, + }, + + "policy_name": { + Type: schema.TypeString, + Optional: true, + }, + + "cipher_suites": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(possibleArmApplicationGatewaySslCipherSuiteValues(), false), + }, + }, + + "min_protocol_version": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + string(network.TLSv10), + string(network.TLSv11), + string(network.TLSv12), + }, false), + }, + }, + }, + }, + "enable_http2": { Type: schema.TypeBool, Optional: true, @@ -1228,6 +1298,10 @@ func resourceArmApplicationGatewayRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Error setting `disabled_ssl_protocols`: %+v", setErr) } + if setErr := d.Set("ssl_policy", flattenApplicationGatewaySslPolicy(props.SslPolicy)); setErr != nil { + return fmt.Errorf("Error setting `ssl_policy`: %+v", setErr) + } + d.Set("enable_http2", props.EnableHTTP2) httpListeners, err := flattenApplicationGatewayHTTPListeners(props.HTTPListeners) @@ -1661,16 +1735,94 @@ func flattenApplicationGatewayConnectionDraining(input *network.ApplicationGatew } func expandApplicationGatewaySslPolicy(d *schema.ResourceData) *network.ApplicationGatewaySslPolicy { - vs := d.Get("disabled_ssl_protocols").([]interface{}) - results := make([]network.ApplicationGatewaySslProtocol, 0) + policy := network.ApplicationGatewaySslPolicy{} + disabledSSLPolicies := make([]network.ApplicationGatewaySslProtocol, 0) - for _, v := range vs { - results = append(results, network.ApplicationGatewaySslProtocol(v.(string))) + vs := d.Get("ssl_policy").([]interface{}) + vsdsp := d.Get("disabled_ssl_protocols").([]interface{}) + + if len(vsdsp) == 0 && len(vs) == 0 { + policy = network.ApplicationGatewaySslPolicy{ + DisabledSslProtocols: &disabledSSLPolicies, + } } - return &network.ApplicationGatewaySslPolicy{ - DisabledSslProtocols: &results, + for _, policy := range vsdsp { + disabledSSLPolicies = append(disabledSSLPolicies, network.ApplicationGatewaySslProtocol(policy.(string))) } + + if len(vs) > 0 { + v := vs[0].(map[string]interface{}) + policyType := network.ApplicationGatewaySslPolicyType(v["policy_type"].(string)) + + // reset disabledSSLPolicies here to always use the new disabled_protocols block in favor of disabled_ssl_protocols + disabledSSLPolicies = disabledSSLPolicies[:0] + + for _, policy := range v["disabled_protocols"].([]interface{}) { + disabledSSLPolicies = append(disabledSSLPolicies, network.ApplicationGatewaySslProtocol(policy.(string))) + } + + if policyType == network.Predefined { + policyName := network.ApplicationGatewaySslPolicyName(v["policy_name"].(string)) + policy = network.ApplicationGatewaySslPolicy{ + PolicyType: policyType, + PolicyName: policyName, + } + } else if policyType == network.Custom { + minProtocolVersion := network.ApplicationGatewaySslProtocol(v["min_protocol_version"].(string)) + cipherSuites := make([]network.ApplicationGatewaySslCipherSuite, 0) + + for _, cipherSuite := range v["cipher_suites"].([]interface{}) { + cipherSuites = append(cipherSuites, network.ApplicationGatewaySslCipherSuite(cipherSuite.(string))) + } + + policy = network.ApplicationGatewaySslPolicy{ + PolicyType: policyType, + MinProtocolVersion: minProtocolVersion, + CipherSuites: &cipherSuites, + } + } + } + + if len(disabledSSLPolicies) > 0 { + policy = network.ApplicationGatewaySslPolicy{ + DisabledSslProtocols: &disabledSSLPolicies, + } + } + + return &policy +} + +func flattenApplicationGatewaySslPolicy(input *network.ApplicationGatewaySslPolicy) []interface{} { + results := make([]interface{}, 0) + + if input == nil { + return results + } + + output := map[string]interface{}{} + output["policy_name"] = input.PolicyName + output["policy_type"] = input.PolicyType + output["min_protocol_version"] = input.MinProtocolVersion + + cipherSuites := make([]interface{}, 0) + if input.CipherSuites != nil { + for _, v := range *input.CipherSuites { + cipherSuites = append(cipherSuites, string(v)) + } + } + output["cipher_suites"] = cipherSuites + + disabledSslProtocols := make([]interface{}, 0) + if input.DisabledSslProtocols != nil { + for _, v := range *input.DisabledSslProtocols { + disabledSslProtocols = append(disabledSslProtocols, string(v)) + } + } + output["disabled_protocols"] = disabledSslProtocols + + results = append(results, output) + return results } func flattenApplicationGatewayDisabledSSLProtocols(input *network.ApplicationGatewaySslPolicy) []interface{} { diff --git a/azurerm/resource_arm_application_gateway_test.go b/azurerm/resource_arm_application_gateway_test.go index 3f62b1c5fbcf..a8389bd18460 100644 --- a/azurerm/resource_arm_application_gateway_test.go +++ b/azurerm/resource_arm_application_gateway_test.go @@ -724,6 +724,91 @@ func TestAccAzureRMApplicationGateway_webApplicationFirewall_exclusions(t *testi }, }) } +func TestAccAzureRMApplicationGateway_sslPolicy_policyType_predefined(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_sslPolicy_policyType_predefined(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.policy_type", "Predefined"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.policy_name", "AppGwSslPolicy20170401S"), + ), + }, + }, + }) +} + +func TestAccAzureRMApplicationGateway_sslPolicy_policyType_custom(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_sslPolicy_policyType_custom(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.policy_type", "Custom"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.min_protocol_version", "TLSv1_1"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.cipher_suites.0", "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.cipher_suites.1", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.cipher_suites.2", "TLS_RSA_WITH_AES_128_GCM_SHA256"), + ), + }, + }, + }) +} +func TestAccAzureRMApplicationGateway_sslPolicy_disabledProtocols(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_sslPolicy_disabledProtocols(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.disabled_protocols.0", "TLSv1_0"), + resource.TestCheckResourceAttr(resourceName, "ssl_policy.0.disabled_protocols.1", "TLSv1_1"), + ), + }, + }, + }) +} + +func TestAccAzureRMApplicationGateway_disabledSslProtocols(t *testing.T) { + resourceName := "azurerm_application_gateway.test" + ri := tf.AccRandTimeInt() + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testCheckAzureRMApplicationGatewayDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAzureRMApplicationGateway_disabledSslProtocols(ri, testLocation()), + Check: resource.ComposeTestCheckFunc( + testCheckAzureRMApplicationGatewayExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "disabled_ssl_protocols.0", "TLSv1_0"), + resource.TestCheckResourceAttr(resourceName, "disabled_ssl_protocols.1", "TLSv1_1"), + ), + }, + }, + }) +} func testCheckAzureRMApplicationGatewayExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { @@ -2848,6 +2933,291 @@ resource "azurerm_application_gateway" "test" { `, template, rInt, rInt) } +func testAccAzureRMApplicationGateway_sslPolicy_policyType_predefined(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%s +# since these variables are re-used - a locals block makes this more maintainable +locals { + 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" "test_standard" { + name = "acctest-pubip-%d-standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "Standard" + allocation_method = "Static" +} +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + sku { + name = "Standard_v2" + tier = "Standard_v2" + capacity = 1 + } + ssl_policy { + policy_name = "AppGwSslPolicy20170401S" + policy_type = "Predefined" + } + 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.test_standard.id}" + } + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + 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, rInt) +} + +func testAccAzureRMApplicationGateway_sslPolicy_policyType_custom(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%s +# since these variables are re-used - a locals block makes this more maintainable +locals { + 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" "test_standard" { + name = "acctest-pubip-%d-standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "Standard" + allocation_method = "Static" +} +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + sku { + name = "Standard_v2" + tier = "Standard_v2" + capacity = 1 + } + ssl_policy { + policy_type = "Custom" + min_protocol_version = "TLSv1_1" + cipher_suites = ["TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", "TLS_RSA_WITH_AES_128_GCM_SHA256"] + } + 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.test_standard.id}" + } + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + 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, rInt) +} + +func testAccAzureRMApplicationGateway_sslPolicy_disabledProtocols(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%s +# since these variables are re-used - a locals block makes this more maintainable +locals { + 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" "test_standard" { + name = "acctest-pubip-%d-standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "Standard" + allocation_method = "Static" +} +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + sku { + name = "Standard_v2" + tier = "Standard_v2" + capacity = 1 + } + ssl_policy { + disabled_protocols = ["TLSv1_0", "TLSv1_1"] + } + 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.test_standard.id}" + } + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + 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, rInt) +} + +func testAccAzureRMApplicationGateway_disabledSslProtocols(rInt int, location string) string { + template := testAccAzureRMApplicationGateway_template(rInt, location) + return fmt.Sprintf(` +%s +# since these variables are re-used - a locals block makes this more maintainable +locals { + 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" "test_standard" { + name = "acctest-pubip-%d-standard" + location = "${azurerm_resource_group.test.location}" + resource_group_name = "${azurerm_resource_group.test.name}" + sku = "Standard" + allocation_method = "Static" +} +resource "azurerm_application_gateway" "test" { + name = "acctestag-%d" + resource_group_name = "${azurerm_resource_group.test.name}" + location = "${azurerm_resource_group.test.location}" + sku { + name = "Standard_v2" + tier = "Standard_v2" + capacity = 1 + } + disabled_ssl_protocols = ["TLSv1_0", "TLSv1_1"] + 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.test_standard.id}" + } + backend_address_pool { + name = "${local.backend_address_pool_name}" + } + backend_http_settings { + name = "${local.http_setting_name}" + cookie_based_affinity = "Disabled" + port = 80 + protocol = "Http" + request_timeout = 1 + } + 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, rInt) +} + func testAccAzureRMApplicationGateway_template(rInt int, location string) string { return fmt.Sprintf(` resource "azurerm_resource_group" "test" { diff --git a/website/docs/r/application_gateway.html.markdown b/website/docs/r/application_gateway.html.markdown index 93ea15f20050..df82bd4ff7f9 100644 --- a/website/docs/r/application_gateway.html.markdown +++ b/website/docs/r/application_gateway.html.markdown @@ -147,7 +147,10 @@ The following arguments are supported: * `authentication_certificate` - (Optional) One or more `authentication_certificate` blocks as defined below. -* `disabled_ssl_protocols` - (Optional) A list of SSL Protocols which should be disabled on this Application Gateway. Possible values are `TLSv1_0`, `TLSv1_1` and `TLSv1_2`. +* `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. + +* `ssl_policy` (Optional) a `ssl policy` block as defined below. * `enable_http2` - (Optional) Is HTTP2 enabled on the application gateway resource? Defaults to `false`. @@ -381,6 +384,31 @@ A `url_path_map` block supports the following: * `path_rule` - (Required) One or more `path_rule` blocks as defined above. +--- + +A `ssl_policy` block supports the following: + +* `disabled_protocols` - (Optional) 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_protocols` cannot be set when `policy_name` or `policy_type` are set. + +* `policy_type` - (Optional) The Type of the Policy. Possible values are `Predefined` and `Custom`. + +~> **NOTE:** `policy_type` is Required when `policy_name` is set - cannot be set if `disabled_protocols` is set. + +When using a `policy_type` of `Predefined` the following fields are supported: + +* `policy_name` - (Optional) The Name of the Policy e.g AppGwSslPolicy20170401S. Required if `policy_type` is set to `Predefined`. Possible values can change over time and +are published here https://docs.microsoft.com/en-us/azure/application-gateway/application-gateway-ssl-policy-overview. Not compatible with `disabled_protocols`. + +When using a `policy_type` of `Custom` the following fields are supported: + +* `cipher_suites` - (Required) A List of accepted cipher suites. Possible values are: `TLS_DHE_DSS_WITH_AES_128_CBC_SHA`, `TLS_DHE_DSS_WITH_AES_128_CBC_SHA256`, `TLS_DHE_DSS_WITH_AES_256_CBC_SHA`, `TLS_DHE_DSS_WITH_AES_256_CBC_SHA256`, `TLS_DHE_RSA_WITH_AES_128_CBC_SHA`, `TLS_DHE_RSA_WITH_AES_128_GCM_SHA256`, `TLS_DHE_RSA_WITH_AES_256_CBC_SHA`, `TLS_DHE_RSA_WITH_AES_256_GCM_SHA384`, `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA`, `TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256`, `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256`, `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA`, `TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384`, `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384`, `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA`, `TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256`, `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA`, `TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384`, `TLS_RSA_WITH_3DES_EDE_CBC_SHA`, `TLS_RSA_WITH_AES_128_CBC_SHA`, `TLS_RSA_WITH_AES_128_CBC_SHA256`, `TLS_RSA_WITH_AES_128_GCM_SHA256`, `TLS_RSA_WITH_AES_256_CBC_SHA`, `TLS_RSA_WITH_AES_256_CBC_SHA256` and `TLS_RSA_WITH_AES_256_GCM_SHA384`. + +* `min_protocol_version` - (Required) The minimal TLS version. Possible values are `TLSv1_0`, `TLSv1_1` and `TLSv1_2`. + + + --- A `waf_configuration` block supports the following: