Skip to content

Commit d72c037

Browse files
Add threshold_configs in Cloud Armor Adaptive Protection security policy (#12367) (#8818)
[upstream:831a3d1475bf9a40a9fab4f225ff72cbef0973a4] Signed-off-by: Modular Magician <[email protected]>
1 parent 9203119 commit d72c037

File tree

4 files changed

+271
-5
lines changed

4 files changed

+271
-5
lines changed

.changelog/12367.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note: enhancement
2+
compute: added `threshold_configs` field to `google_compute_security_policy` resource
3+
```

google-beta/services/compute/resource_compute_security_policy.go

Lines changed: 149 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,80 @@ func ResourceComputeSecurityPolicy() *schema.Resource {
543543
ValidateFunc: validation.StringInSlice([]string{"STANDARD", "PREMIUM"}, false),
544544
Description: `Rule visibility. Supported values include: "STANDARD", "PREMIUM".`,
545545
},
546+
"threshold_configs": {
547+
Type: schema.TypeList,
548+
Description: `Configuration options for layer7 adaptive protection for various customizable thresholds.`,
549+
Optional: true,
550+
Elem: &schema.Resource{
551+
Schema: map[string]*schema.Schema{
552+
"name": {
553+
Type: schema.TypeString,
554+
Required: true,
555+
Description: `The name must be 1-63 characters long, and comply with RFC1035. The name must be unique within the security policy.`,
556+
ValidateFunc: validation.StringLenBetween(1, 63),
557+
},
558+
"auto_deploy_load_threshold": {
559+
Type: schema.TypeFloat,
560+
Optional: true,
561+
ValidateFunc: validation.FloatAtLeast(0.0),
562+
},
563+
"auto_deploy_confidence_threshold": {
564+
Type: schema.TypeFloat,
565+
Optional: true,
566+
ValidateFunc: validation.FloatBetween(0.0, 1.0),
567+
},
568+
"auto_deploy_impacted_baseline_threshold": {
569+
Type: schema.TypeFloat,
570+
Optional: true,
571+
ValidateFunc: validation.FloatBetween(0.0, 1.0),
572+
},
573+
"auto_deploy_expiration_sec": {
574+
Type: schema.TypeInt,
575+
Optional: true,
576+
ValidateFunc: validation.IntBetween(1, 7776000),
577+
},
578+
"detection_load_threshold": {
579+
Type: schema.TypeFloat,
580+
Optional: true,
581+
ValidateFunc: validation.FloatAtLeast(0.0),
582+
},
583+
"detection_absolute_qps": {
584+
Type: schema.TypeFloat,
585+
Optional: true,
586+
ValidateFunc: validation.FloatAtLeast(0.0),
587+
},
588+
"detection_relative_to_baseline_qps": {
589+
Type: schema.TypeFloat,
590+
Optional: true,
591+
ValidateFunc: validation.FloatAtLeast(1.0),
592+
},
593+
"traffic_granularity_configs": {
594+
Type: schema.TypeList,
595+
Optional: true,
596+
Elem: &schema.Resource{
597+
Schema: map[string]*schema.Schema{
598+
"type": {
599+
Type: schema.TypeString,
600+
Required: true,
601+
Description: `Type of this configuration.`,
602+
ValidateFunc: validation.StringInSlice([]string{"HTTP_HEADER_HOST", "HTTP_PATH"}, false),
603+
},
604+
"value": {
605+
Type: schema.TypeString,
606+
Optional: true,
607+
Description: `Requests that match this value constitute a granular traffic unit.`,
608+
},
609+
"enable_each_unique_value": {
610+
Type: schema.TypeBool,
611+
Optional: true,
612+
Description: `If enabled, traffic matching each unique value for the specified type constitutes a separate traffic unit. It can only be set to true if value is empty.`,
613+
},
614+
},
615+
},
616+
},
617+
},
618+
},
619+
},
546620
},
547621
},
548622
},
@@ -1322,12 +1396,49 @@ func expandLayer7DdosDefenseConfig(configured []interface{}) *compute.SecurityPo
13221396

13231397
data := configured[0].(map[string]interface{})
13241398
return &compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfig{
1325-
Enable: data["enable"].(bool),
1326-
RuleVisibility: data["rule_visibility"].(string),
1327-
ForceSendFields: []string{"Enable"},
1399+
Enable: data["enable"].(bool),
1400+
RuleVisibility: data["rule_visibility"].(string),
1401+
ThresholdConfigs: expandThresholdConfigs(data["threshold_configs"].([]interface{})),
1402+
ForceSendFields: []string{"Enable"},
13281403
}
13291404
}
13301405

1406+
func expandThresholdConfigs(configured []interface{}) []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig {
1407+
params := make([]*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig, 0, len(configured))
1408+
for _, raw := range configured {
1409+
params = append(params, expandThresholdConfig(raw))
1410+
}
1411+
return params
1412+
}
1413+
1414+
func expandThresholdConfig(configured interface{}) *compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig {
1415+
data := configured.(map[string]interface{})
1416+
return &compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig{
1417+
AutoDeployConfidenceThreshold: data["auto_deploy_confidence_threshold"].(float64),
1418+
AutoDeployExpirationSec: int64(data["auto_deploy_expiration_sec"].(int)),
1419+
AutoDeployImpactedBaselineThreshold: data["auto_deploy_impacted_baseline_threshold"].(float64),
1420+
AutoDeployLoadThreshold: data["auto_deploy_load_threshold"].(float64),
1421+
DetectionAbsoluteQps: data["detection_absolute_qps"].(float64),
1422+
DetectionLoadThreshold: data["detection_load_threshold"].(float64),
1423+
DetectionRelativeToBaselineQps: data["detection_relative_to_baseline_qps"].(float64),
1424+
Name: data["name"].(string),
1425+
TrafficGranularityConfigs: expandTrafficGranularityConfig(data["traffic_granularity_configs"].([]interface{})),
1426+
}
1427+
}
1428+
1429+
func expandTrafficGranularityConfig(configured []interface{}) []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig {
1430+
params := make([]*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig, 0, len(configured))
1431+
for _, raw := range configured {
1432+
data := raw.(map[string]interface{})
1433+
params = append(params, &compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig{
1434+
EnableEachUniqueValue: data["enable_each_unique_value"].(bool),
1435+
Type: data["type"].(string),
1436+
Value: data["value"].(string),
1437+
})
1438+
}
1439+
return params
1440+
}
1441+
13311442
func expandAutoDeployConfig(configured []interface{}) *compute.SecurityPolicyAdaptiveProtectionConfigAutoDeployConfig {
13321443
if len(configured) == 0 || configured[0] == nil {
13331444
return nil
@@ -1361,13 +1472,46 @@ func flattenLayer7DdosDefenseConfig(conf *compute.SecurityPolicyAdaptiveProtecti
13611472
}
13621473

13631474
data := map[string]interface{}{
1364-
"enable": conf.Enable,
1365-
"rule_visibility": conf.RuleVisibility,
1475+
"enable": conf.Enable,
1476+
"rule_visibility": conf.RuleVisibility,
1477+
"threshold_configs": flattenThresholdConfigs(conf.ThresholdConfigs),
13661478
}
13671479

13681480
return []map[string]interface{}{data}
13691481
}
13701482

1483+
func flattenThresholdConfigs(conf []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfig) []map[string]interface{} {
1484+
configs := make([]map[string]interface{}, 0, len(conf))
1485+
for _, field := range conf {
1486+
data := map[string]interface{}{
1487+
"name": field.Name,
1488+
"auto_deploy_load_threshold": field.AutoDeployLoadThreshold,
1489+
"auto_deploy_confidence_threshold": field.AutoDeployConfidenceThreshold,
1490+
"auto_deploy_impacted_baseline_threshold": field.AutoDeployImpactedBaselineThreshold,
1491+
"auto_deploy_expiration_sec": field.AutoDeployExpirationSec,
1492+
"detection_load_threshold": field.DetectionLoadThreshold,
1493+
"detection_absolute_qps": field.DetectionAbsoluteQps,
1494+
"detection_relative_to_baseline_qps": field.DetectionRelativeToBaselineQps,
1495+
"traffic_granularity_configs": flattenTrafficGranularityConfigs(field.TrafficGranularityConfigs),
1496+
}
1497+
configs = append(configs, data)
1498+
}
1499+
return configs
1500+
}
1501+
1502+
func flattenTrafficGranularityConfigs(conf []*compute.SecurityPolicyAdaptiveProtectionConfigLayer7DdosDefenseConfigThresholdConfigTrafficGranularityConfig) []map[string]interface{} {
1503+
configs := make([]map[string]interface{}, 0, len(conf))
1504+
for _, field := range conf {
1505+
data := map[string]interface{}{
1506+
"type": field.Type,
1507+
"value": field.Value,
1508+
"enable_each_unique_value": field.EnableEachUniqueValue,
1509+
}
1510+
configs = append(configs, data)
1511+
}
1512+
return configs
1513+
}
1514+
13711515
func flattenAutoDeployConfig(conf *compute.SecurityPolicyAdaptiveProtectionConfigAutoDeployConfig) []map[string]interface{} {
13721516
if conf == nil {
13731517
return nil

google-beta/services/compute/resource_compute_security_policy_test.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,36 @@ func TestAccComputeSecurityPolicy_withoutAdaptiveProtection(t *testing.T) {
370370
})
371371
}
372372

373+
func TestAccComputeSecurityPolicy_withAdaptiveProtection_withThresholdConfigs(t *testing.T) {
374+
t.Parallel()
375+
376+
spName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
377+
378+
acctest.VcrTest(t, resource.TestCase{
379+
PreCheck: func() { acctest.AccTestPreCheck(t) },
380+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
381+
CheckDestroy: testAccCheckComputeSecurityPolicyDestroyProducer(t),
382+
Steps: []resource.TestStep{
383+
{
384+
Config: testAccComputeSecurityPolicy_withAdaptiveProtection_enabled_withThresholdConfigs(spName),
385+
},
386+
{
387+
ResourceName: "google_compute_security_policy.policy",
388+
ImportState: true,
389+
ImportStateVerify: true,
390+
},
391+
{
392+
Config: testAccComputeSecurityPolicy_withAdaptiveProtection_update_ThresholdConfigs(spName),
393+
},
394+
{
395+
ResourceName: "google_compute_security_policy.policy",
396+
ImportState: true,
397+
ImportStateVerify: true,
398+
},
399+
},
400+
})
401+
}
402+
373403
func TestAccComputeSecurityPolicy_withAdaptiveProtectionAutoDeployConfig(t *testing.T) {
374404
t.Parallel()
375405

@@ -1474,6 +1504,62 @@ resource "google_compute_security_policy" "policy" {
14741504
`, spName)
14751505
}
14761506

1507+
func testAccComputeSecurityPolicy_withAdaptiveProtection_enabled_withThresholdConfigs(spName string) string {
1508+
return fmt.Sprintf(`
1509+
resource "google_compute_security_policy" "policy" {
1510+
name = "%s"
1511+
description = "updated description"
1512+
1513+
adaptive_protection_config {
1514+
layer_7_ddos_defense_config {
1515+
enable = true
1516+
rule_visibility = "STANDARD"
1517+
threshold_configs {
1518+
name = "threshold-name"
1519+
auto_deploy_load_threshold = 0.1
1520+
auto_deploy_confidence_threshold = 0.5
1521+
auto_deploy_impacted_baseline_threshold = 0.02
1522+
auto_deploy_expiration_sec = 3600
1523+
detection_load_threshold = 0.7
1524+
detection_absolute_qps = 1.0
1525+
detection_relative_to_baseline_qps = 1.1
1526+
traffic_granularity_configs {
1527+
type = "HTTP_HEADER_HOST"
1528+
enable_each_unique_value = true
1529+
}
1530+
}
1531+
}
1532+
}
1533+
}
1534+
`, spName)
1535+
}
1536+
1537+
func testAccComputeSecurityPolicy_withAdaptiveProtection_update_ThresholdConfigs(spName string) string {
1538+
return fmt.Sprintf(`
1539+
resource "google_compute_security_policy" "policy" {
1540+
name = "%s"
1541+
description = "updated description"
1542+
1543+
adaptive_protection_config {
1544+
layer_7_ddos_defense_config {
1545+
enable = true
1546+
rule_visibility = "STANDARD"
1547+
threshold_configs {
1548+
name = "threshold-name-updated"
1549+
auto_deploy_load_threshold = 0.2
1550+
auto_deploy_confidence_threshold = 0.6
1551+
auto_deploy_impacted_baseline_threshold = 0.03
1552+
auto_deploy_expiration_sec = 7200
1553+
detection_load_threshold = 0.8
1554+
detection_absolute_qps = 1.1
1555+
detection_relative_to_baseline_qps = 1.2
1556+
}
1557+
}
1558+
}
1559+
}
1560+
`, spName)
1561+
}
1562+
14771563
func testAccComputeSecurityPolicy_withAdaptiveProtection_update(spName string) string {
14781564
return fmt.Sprintf(`
14791565
resource "google_compute_security_policy" "policy" {

website/docs/r/compute_security_policy.html.markdown

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,39 @@ The following arguments are supported:
430430
* `STANDARD` - opaque rules. (default)
431431
* `PREMIUM` - transparent rules.
432432

433+
* `threshold_configs` - (Optional) Configuration options for layer7 adaptive protection for various customizable thresholds. Structure is [documented below](#nested_threshold_configs).
434+
435+
<a name="nested_threshold_configs"></a>The `threshold_configs` block supports:
436+
437+
* `name` - The name of config. The name must be 1-63 characters long, and comply with RFC1035. The name must be unique within the security policy.
438+
439+
* `auto_deploy_load_threshold` - (Optional) Load threshold above which Adaptive Protection automatically deploy threshold based on the backend load threshold and detect a new rule during an alerted attack.
440+
441+
* `auto_deploy_confidence_threshold` - (Optional) Confidence threshold above which Adaptive Protection's auto-deploy takes actions.
442+
443+
* `auto_deploy_impacted_baseline_threshold` - (Optional) Impacted baseline threshold below which Adaptive Protection's auto-deploy takes actions.
444+
445+
* `auto_deploy_expiration_sec` - (Optional) Duration over which Adaptive Protection's auto-deployed actions last.
446+
447+
* `detection_load_threshold` - (Optional) Detection threshold based on the backend service's load.
448+
449+
* `detection_absolute_qps` - (Optional) Detection threshold based on absolute QPS.
450+
451+
* `detection_relative_to_baseline_qps` - (Optional) Detection threshold based on QPS relative to the average of baseline traffic.
452+
453+
* `traffic_granularity_configs` - (Optional) Configuration options for enabling Adaptive Protection to work on the specified service granularity. Structure is [documented below](#nested_traffic_granularity_configs).
454+
455+
<a name="nested_traffic_granularity_configs"></a>The `traffic_granularity_configs` block supports:
456+
457+
* `type` - The type of this configuration, a granular traffic unit can be one of the following:
458+
* `HTTP_HEADER_HOST`
459+
* `HTTP_PATH`
460+
461+
* `value` - (Optional) Requests that match this value constitute a granular traffic unit.
462+
463+
* `enable_each_unique_value` - (Optional) If enabled, traffic matching each unique value for the specified type constitutes a separate traffic unit. It can only be set to true if value is empty.
464+
465+
433466
<a name="nested_auto_deploy_config"></a>The `auto_deploy_config` block supports:
434467

435468
* `load_threshold` - (Optional) Identifies new attackers only when the load to the backend service that is under attack exceeds this threshold.

0 commit comments

Comments
 (0)