Skip to content

Commit

Permalink
Added new contents in rules[].rateLimitOptionsfields for google_compu…
Browse files Browse the repository at this point in the history
…te_security_policy to support Cloud Armor (#7132) (#5193)

Signed-off-by: Modular Magician <[email protected]>
Co-authored-by: Scott Suarez <[email protected]>
  • Loading branch information
modular-magician and ScottSuarez authored Feb 10, 2023
1 parent 5dafe39 commit b6b115f
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 7 deletions.
3 changes: 3 additions & 0 deletions .changelog/7132.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
compute: Added new contents in rules[].rateLimitOptionsfields for `google_compute_security_policy` to support Cloud Armor Rate Limit Options (beta)
```
81 changes: 74 additions & 7 deletions google-beta/resource_compute_security_policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ func resourceComputeSecurityPolicy() *schema.Resource {
Optional: true,
Default: "ALL",
Description: `Determines the key to enforce the rateLimitThreshold on`,
ValidateFunc: validation.StringInSlice([]string{"ALL", "IP", "HTTP_HEADER", "XFF_IP", "HTTP_COOKIE"}, false),
ValidateFunc: validation.StringInSlice([]string{"ALL", "IP", "HTTP_HEADER", "XFF_IP", "HTTP_COOKIE", "HTTP_PATH", "SNI", "REGION_CODE", ""}, false),
},

"enforce_on_key_name": {
Expand All @@ -264,6 +264,28 @@ func resourceComputeSecurityPolicy() *schema.Resource {
Description: `Rate limit key name applicable only for the following key types: HTTP_HEADER -- Name of the HTTP header whose value is taken as the key value. HTTP_COOKIE -- Name of the HTTP cookie whose value is taken as the key value.`,
},

"enforce_on_key_configs": {
Type: schema.TypeList,
Description: `Enforce On Key Config of this security policy`,
ForceNew: true,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"enforce_on_key_type": {
Type: schema.TypeString,
Optional: true,
Description: `Determines the key to enforce the rate_limit_threshold on`,
ValidateFunc: validation.StringInSlice([]string{"ALL", "IP", "HTTP_HEADER", "XFF_IP", "HTTP_COOKIE", "HTTP_PATH", "SNI", "REGION_CODE"}, false),
},
"enforce_on_key_name": {
Type: schema.TypeString,
Optional: true,
Description: `Rate limit key name applicable only for the following key types: HTTP_HEADER -- Name of the HTTP header whose value is taken as the key value. HTTP_COOKIE -- Name of the HTTP cookie whose value is taken as the key value.`,
},
},
},
},

"ban_threshold": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -1182,6 +1204,7 @@ func expandSecurityPolicyRuleRateLimitOptions(configured []interface{}) *compute
ConformAction: data["conform_action"].(string),
EnforceOnKey: data["enforce_on_key"].(string),
EnforceOnKeyName: data["enforce_on_key_name"].(string),
EnforceOnKeyConfigs: expandSecurityPolicyEnforceOnKeyConfigs(data["enforce_on_key_configs"].([]interface{})),
BanDurationSec: int64(data["ban_duration_sec"].(int)),
ExceedRedirectOptions: expandSecurityPolicyRuleRedirectOptions(data["exceed_redirect_options"].([]interface{})),
}
Expand All @@ -1199,18 +1222,39 @@ func expandThreshold(configured []interface{}) *compute.SecurityPolicyRuleRateLi
}
}

func expandSecurityPolicyEnforceOnKeyConfigs(configured []interface{}) []*compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig {
params := make([]*compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig, 0, len(configured))

for _, raw := range configured {
params = append(params, expandSecurityPolicyEnforceOnKeyConfigsFields(raw))
}

return params
}

func expandSecurityPolicyEnforceOnKeyConfigsFields(raw interface{}) *compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig {
data := raw.(map[string]interface{})

return &compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig{
EnforceOnKeyType: data["enforce_on_key_type"].(string),
EnforceOnKeyName: data["enforce_on_key_name"].(string),
}
}

func flattenSecurityPolicyRuleRateLimitOptions(conf *compute.SecurityPolicyRuleRateLimitOptions) []map[string]interface{} {
if conf == nil {
return nil
}

data := map[string]interface{}{
"ban_threshold": flattenThreshold(conf.BanThreshold),
"rate_limit_threshold": flattenThreshold(conf.RateLimitThreshold),
"exceed_action": conf.ExceedAction,
"conform_action": conf.ConformAction,
"enforce_on_key": conf.EnforceOnKey,
"enforce_on_key_name": conf.EnforceOnKeyName,
"ban_threshold": flattenThreshold(conf.BanThreshold),
"rate_limit_threshold": flattenThreshold(conf.RateLimitThreshold),
"exceed_action": conf.ExceedAction,
"conform_action": conf.ConformAction,
"enforce_on_key": conf.EnforceOnKey,
"enforce_on_key_name": conf.EnforceOnKeyName,
"enforce_on_key_configs": flattenSecurityPolicyEnforceOnKeyConfigs(conf.EnforceOnKeyConfigs),

"ban_duration_sec": conf.BanDurationSec,
"exceed_redirect_options": flattenSecurityPolicyRedirectOptions(conf.ExceedRedirectOptions),
}
Expand Down Expand Up @@ -1243,6 +1287,29 @@ func expandSecurityPolicyRuleRedirectOptions(configured []interface{}) *compute.
}
}

func flattenSecurityPolicyEnforceOnKeyConfigs(conf []*compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig) []map[string]interface{} {
if conf == nil || len(conf) == 0 {
return nil
}

transformed := make([]map[string]interface{}, 0, len(conf))
for _, raw := range conf {
transformed = append(transformed, flattenSecurityPolicyEnforceOnKeyConfigsFields(raw))
}
return transformed
}

func flattenSecurityPolicyEnforceOnKeyConfigsFields(conf *compute.SecurityPolicyRuleRateLimitOptionsEnforceOnKeyConfig) map[string]interface{} {
if conf == nil {
return nil
}

return map[string]interface{}{
"enforce_on_key_name": conf.EnforceOnKeyName,
"enforce_on_key_type": conf.EnforceOnKeyType,
}
}

func flattenSecurityPolicyRedirectOptions(conf *compute.SecurityPolicyRuleRedirectOptions) []map[string]interface{} {
if conf == nil {
return nil
Expand Down
131 changes: 131 additions & 0 deletions google-beta/resource_compute_security_policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,50 @@ func TestAccComputeSecurityPolicy_withRateLimitWithRedirectOptions(t *testing.T)
})
}

func TestAccComputeSecurityPolicy_withRateLimit_withEnforceOnKeyConfigs(t *testing.T) {
t.Parallel()

spName := fmt.Sprintf("tf-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSecurityPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeSecurityPolicy_withRateLimitOptions_withEnforceOnKeyConfigs(spName),
},
{
ResourceName: "google_compute_security_policy.policy",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccComputeSecurityPolicy_withRateLimitOption_withMultipleEnforceOnKeyConfigs(t *testing.T) {
t.Parallel()

spName := fmt.Sprintf("tf-test-%s", randString(t, 10))

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckComputeSecurityPolicyDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccComputeSecurityPolicy_withRateLimitOption_withMultipleEnforceOnKeyConfigs(spName),
},
{
ResourceName: "google_compute_security_policy.policy",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccComputeSecurityPolicy_withRecaptchaOptionsConfig(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -1122,6 +1166,93 @@ resource "google_compute_security_policy" "policy" {
`, spName)
}

func testAccComputeSecurityPolicy_withRateLimitOptions_withEnforceOnKeyConfigs(spName string) string {
return fmt.Sprintf(`
resource "google_compute_security_policy" "policy" {
name = "%s"
description = "throttle rule with enforce_on_key_configs"
rule {
action = "throttle"
priority = "2147483647"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "default rule"
rate_limit_options {
conform_action = "allow"
exceed_action = "redirect"
enforce_on_key = ""
enforce_on_key_configs {
enforce_on_key_type = "IP"
}
exceed_redirect_options {
type = "EXTERNAL_302"
target = "https://www.example.com"
}
rate_limit_threshold {
count = 10
interval_sec = 60
}
}
}
}
`, spName)
}

func testAccComputeSecurityPolicy_withRateLimitOption_withMultipleEnforceOnKeyConfigs(spName string) string {
return fmt.Sprintf(`
resource "google_compute_security_policy" "policy" {
name = "%s"
description = "throttle rule with enforce_on_key_configs"
rule {
action = "throttle"
priority = "2147483647"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "default rule"
rate_limit_options {
conform_action = "allow"
exceed_action = "deny(429)"
rate_limit_threshold {
count = 10
interval_sec = 60
}
enforce_on_key = ""
enforce_on_key_configs {
enforce_on_key_type = "HTTP_PATH"
}
enforce_on_key_configs {
enforce_on_key_type = "HTTP_HEADER"
enforce_on_key_name = "user-agent"
}
enforce_on_key_configs {
enforce_on_key_type = "REGION_CODE"
}
}
}
}
`, spName)
}

func TestAccComputeSecurityPolicy_withRedirectOptionsRecaptcha(t *testing.T) {
t.Parallel()

Expand Down
64 changes: 64 additions & 0 deletions website/docs/r/compute_security_policy.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,48 @@ resource "google_compute_security_policy" "policy" {
}
```

## Example Usage - With enforceOnKey value as empty string
A scenario example that won't cause any conflict between `enforce_on_key` and `enforce_on_key_configs`, because `enforce_on_key` was specified as an empty string:

```hcl
resource "google_compute_security_policy" "policy" {
name = "%s"
description = "throttle rule with enforce_on_key_configs"
rule {
action = "throttle"
priority = "2147483647"
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = ["*"]
}
}
description = "default rule"
rate_limit_options {
conform_action = "allow"
exceed_action = "redirect"
enforce_on_key = ""
enforce_on_key_configs {
enforce_on_key_type = "IP"
}
exceed_redirect_options {
type = "EXTERNAL_302"
target = "<https://www.example.com>"
}
rate_limit_threshold {
count = 10
interval_sec = 60
}
}
}
}
```

## Argument Reference

The following arguments are supported:
Expand Down Expand Up @@ -279,9 +321,31 @@ The following arguments are supported:
* HTTP_HEADER: The value of the HTTP header whose name is configured under "enforceOnKeyName". The key value is truncated to the first 128 bytes of the header value. If no such header is present in the request, the key type defaults to ALL.
* XFF_IP: The first IP address (i.e. the originating client IP address) specified in the list of IPs under X-Forwarded-For HTTP header. If no such header is present or the value is not a valid IP, the key type defaults to ALL.
* HTTP_COOKIE: The value of the HTTP cookie whose name is configured under "enforceOnKeyName". The key value is truncated to the first 128 bytes of the cookie value. If no such cookie is present in the request, the key type defaults to ALL.
* HTTP_PATH: The URL path of the HTTP request. The key value is truncated to the first 128 bytes
* SNI: Server name indication in the TLS session of the HTTPS request. The key value is truncated to the first 128 bytes. The key type defaults to ALL on a HTTP session.
* REGION_CODE: The country/region from which the request originates.

* `enforce_on_key_name` - (Optional) Rate limit key name applicable only for the following key types: HTTP_HEADER -- Name of the HTTP header whose value is taken as the key value. HTTP_COOKIE -- Name of the HTTP cookie whose value is taken as the key value.

* `enforce_on_key_configs` - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) If specified, any combination of values of enforce_on_key_type/enforce_on_key_name is treated as the key on which ratelimit threshold/action is enforced. You can specify up to 3 enforce_on_key_configs. If `enforce_on_key_configs` is specified, enforce_on_key must be set to an empty string. Structure is [documented below](#nested_enforce_on_key_configs).

**Note:** To avoid the conflict between `enforce_on_key` and `enforce_on_key_configs`, the field [`enforce_on_key`](#enforce_on_key) needs to be set to an empty string.

<a name="nested_enforce_on_key_configs"></a>The `enforce_on_key_configs` block supports:

* `enforce_on_key_name` - (Optional) Rate limit key name applicable only for the following key types: HTTP_HEADER: Name of the HTTP header whose value is taken as the key value. HTTP_COOKIE: Name of the HTTP cookie whose value is taken as the key value.

* `enforce_on_key_type` - (Optional) Determines the key to enforce the rate_limit_threshold on. If not specified, defaults to "ALL".

* ALL: A single rate limit threshold is applied to all the requests matching this rule.
* IP: The source IP address of the request is the key. Each IP has this limit enforced separately.
* HTTP_HEADER: The value of the HTTP header whose name is configured under "enforceOnKeyName". The key value is truncated to the first 128 bytes of the header value. If no such header is present in the request, the key type defaults to ALL.
* XFF_IP: The first IP address (i.e. the originating client IP address) specified in the list of IPs under X-Forwarded-For HTTP header. If no such header is present or the value is not a valid IP, the key type defaults to ALL.
* HTTP_COOKIE: The value of the HTTP cookie whose name is configured under "enforceOnKeyName". The key value is truncated to the first 128 bytes of the cookie value. If no such cookie is present in the request, the key type defaults to ALL.
* HTTP_PATH: The URL path of the HTTP request. The key value is truncated to the first 128 bytes
* SNI: Server name indication in the TLS session of the HTTPS request. The key value is truncated to the first 128 bytes. The key type defaults to ALL on a HTTP session.
* REGION_CODE: The country/region from which the request originates.

* `exceed_redirect_options` - (Optional) Parameters defining the redirect action that is used as the exceed action. Cannot be specified if the exceed action is not redirect. Structure is [documented below](#nested_exceed_redirect_options).

<a name="nested_threshold"></a>The `{ban/rate_limit}_threshold` block supports:
Expand Down

0 comments on commit b6b115f

Please sign in to comment.