Skip to content

Commit 317ea0b

Browse files
Create region security policies rules (#8477) (#6086)
* creating first version of region security policy and adding ddos protection config * adding rules field in region security policy * creating resource network_edge_security_service and their scenarios of test * adding patch operation and fixing id, import_format and self_link * added fields in the region_security_policy, and fixed the scenario tests for network_edge_security_service * removed duplicated field for region_security_policy * adding ddos_protection_config field in region_security_policy * cleanups * adding self_link field back and removing uncessary fields * adding docs for ddosProtection * making new resources only availabe in beta downstream * fixing eof * adding region security policy rule and basic scenario * code experiments cleanups * adding preconfiguredWafConfig object and some inner fields in region security policy rule * adding mapping for network_match object in region security policy rule * adding rateLimitOptions mapping * adding ruleNumber field to region security policy * adding basic update for region security policy rule * adding network_match and preconfigured_waf scenarios for region sec policy rules * wip - adding user_defined_fields in region security policy * fixing yaml linter issues * fixing review comments * removing validate_only field * fixing comments in region_security_policy_rule test * fixing userDefinedFields and adding tests for regionSecPolicyRule * adding user_defined_fields update test for regionSecPolicy * removing rule_number from regionSecPolicyRule * removing preconfiguredWaf from regionSecPolicyRule because it is not finished yet * removing rateLimitOptions from RegionSecPolicyRule because it is not finished yet * small cleanups * fixing yamllint issues on the worked resources * prevent that netwrokt_match test fails due paralellism * adding new test for multiple rules * fixing code review comments * removing harcoded project from tests * moving network_edge_security_service basic test to another region * fixing code review issues * fixing import cycle issue in downstream repo * updating with upstream and change regions --------- Signed-off-by: Modular Magician <[email protected]> Co-authored-by: diogoEsteves <[email protected]>
1 parent 3a81d1e commit 317ea0b

13 files changed

+2397
-4
lines changed

.changelog/8477.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
```release-note:new-resource
2+
`google_compute_region_security_policy_rule`
3+
```
4+
```release-note:enhancement
5+
compute: added support for `user_defined_fields` to `google_compute_region_security_policy`
6+
```

google-beta/provider/provider.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,9 +1086,9 @@ func DatasourceMapWithErrors() (map[string]*schema.Resource, error) {
10861086
})
10871087
}
10881088

1089-
// Generated resources: 364
1089+
// Generated resources: 365
10901090
// Generated IAM resources: 234
1091-
// Total generated resources: 598
1091+
// Total generated resources: 599
10921092
func ResourceMap() map[string]*schema.Resource {
10931093
resourceMap, _ := ResourceMapWithErrors()
10941094
return resourceMap
@@ -1316,6 +1316,7 @@ func ResourceMapWithErrors() (map[string]*schema.Resource, error) {
13161316
"google_compute_region_network_endpoint_group": compute.ResourceComputeRegionNetworkEndpointGroup(),
13171317
"google_compute_region_per_instance_config": compute.ResourceComputeRegionPerInstanceConfig(),
13181318
"google_compute_region_security_policy": compute.ResourceComputeRegionSecurityPolicy(),
1319+
"google_compute_region_security_policy_rule": compute.ResourceComputeRegionSecurityPolicyRule(),
13191320
"google_compute_region_ssl_certificate": compute.ResourceComputeRegionSslCertificate(),
13201321
"google_compute_region_ssl_policy": compute.ResourceComputeRegionSslPolicy(),
13211322
"google_compute_region_target_http_proxy": compute.ResourceComputeRegionTargetHttpProxy(),

google-beta/services/compute/resource_compute_network_edge_security_service_generated_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ resource "google_compute_network_edge_security_service" "default" {
6363
provider = google-beta
6464
6565
name = "tf-test-my-edge-security-service%{random_suffix}"
66-
region = "asia-southeast1"
66+
region = "us-east1"
6767
description = "My basic resource"
6868
}
6969
`, context)

google-beta/services/compute/resource_compute_region_security_policy.go

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"log"
2323
"reflect"
24+
"strings"
2425
"time"
2526

2627
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
@@ -99,6 +100,49 @@ If it is not provided, the provider region is used.`,
99100
- CLOUD_ARMOR_NETWORK: Cloud Armor network policies can be configured to filter packets targeting network load balancing resources such as backend services, target pools, target instances, and instances with external IPs. They filter requests before the request is served from the application.
100101
This field can be set only at resource creation time. Possible values: ["CLOUD_ARMOR", "CLOUD_ARMOR_EDGE", "CLOUD_ARMOR_NETWORK"]`,
101102
},
103+
"user_defined_fields": {
104+
Type: schema.TypeList,
105+
Optional: true,
106+
Description: `Definitions of user-defined fields for CLOUD_ARMOR_NETWORK policies.
107+
A user-defined field consists of up to 4 bytes extracted from a fixed offset in the packet, relative to the IPv4, IPv6, TCP, or UDP header, with an optional mask to select certain bits.
108+
Rules may then specify matching values for these fields.`,
109+
Elem: &schema.Resource{
110+
Schema: map[string]*schema.Schema{
111+
"base": {
112+
Type: schema.TypeString,
113+
Required: true,
114+
ValidateFunc: verify.ValidateEnum([]string{"IPV4", "IPV6", "TCP", "UDP"}),
115+
Description: `The base relative to which 'offset' is measured. Possible values are:
116+
- IPV4: Points to the beginning of the IPv4 header.
117+
- IPV6: Points to the beginning of the IPv6 header.
118+
- TCP: Points to the beginning of the TCP header, skipping over any IPv4 options or IPv6 extension headers. Not present for non-first fragments.
119+
- UDP: Points to the beginning of the UDP header, skipping over any IPv4 options or IPv6 extension headers. Not present for non-first fragments. Possible values: ["IPV4", "IPV6", "TCP", "UDP"]`,
120+
},
121+
"mask": {
122+
Type: schema.TypeString,
123+
Optional: true,
124+
Description: `If specified, apply this mask (bitwise AND) to the field to ignore bits before matching.
125+
Encoded as a hexadecimal number (starting with "0x").
126+
The last byte of the field (in network byte order) corresponds to the least significant byte of the mask.`,
127+
},
128+
"name": {
129+
Type: schema.TypeString,
130+
Optional: true,
131+
Description: `The name of this field. Must be unique within the policy.`,
132+
},
133+
"offset": {
134+
Type: schema.TypeInt,
135+
Optional: true,
136+
Description: `Offset of the first byte of the field (in network byte order) relative to 'base'.`,
137+
},
138+
"size": {
139+
Type: schema.TypeInt,
140+
Optional: true,
141+
Description: `Size of the field in bytes. Valid values: 1-4.`,
142+
},
143+
},
144+
},
145+
},
102146
"fingerprint": {
103147
Type: schema.TypeString,
104148
Computed: true,
@@ -169,6 +213,12 @@ func resourceComputeRegionSecurityPolicyCreate(d *schema.ResourceData, meta inte
169213
} else if v, ok := d.GetOkExists("ddos_protection_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(ddosProtectionConfigProp)) && (ok || !reflect.DeepEqual(v, ddosProtectionConfigProp)) {
170214
obj["ddosProtectionConfig"] = ddosProtectionConfigProp
171215
}
216+
userDefinedFieldsProp, err := expandComputeRegionSecurityPolicyUserDefinedFields(d.Get("user_defined_fields"), d, config)
217+
if err != nil {
218+
return err
219+
} else if v, ok := d.GetOkExists("user_defined_fields"); !tpgresource.IsEmptyValue(reflect.ValueOf(userDefinedFieldsProp)) && (ok || !reflect.DeepEqual(v, userDefinedFieldsProp)) {
220+
obj["userDefinedFields"] = userDefinedFieldsProp
221+
}
172222
regionProp, err := expandComputeRegionSecurityPolicyRegion(d.Get("region"), d, config)
173223
if err != nil {
174224
return err
@@ -294,6 +344,9 @@ func resourceComputeRegionSecurityPolicyRead(d *schema.ResourceData, meta interf
294344
if err := d.Set("self_link_with_policy_id", flattenComputeRegionSecurityPolicySelfLinkWithPolicyId(res["selfLinkWithId"], d, config)); err != nil {
295345
return fmt.Errorf("Error reading RegionSecurityPolicy: %s", err)
296346
}
347+
if err := d.Set("user_defined_fields", flattenComputeRegionSecurityPolicyUserDefinedFields(res["userDefinedFields"], d, config)); err != nil {
348+
return fmt.Errorf("Error reading RegionSecurityPolicy: %s", err)
349+
}
297350
if err := d.Set("region", flattenComputeRegionSecurityPolicyRegion(res["region"], d, config)); err != nil {
298351
return fmt.Errorf("Error reading RegionSecurityPolicy: %s", err)
299352
}
@@ -335,13 +388,42 @@ func resourceComputeRegionSecurityPolicyUpdate(d *schema.ResourceData, meta inte
335388
} else if v, ok := d.GetOkExists("ddos_protection_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, ddosProtectionConfigProp)) {
336389
obj["ddosProtectionConfig"] = ddosProtectionConfigProp
337390
}
391+
userDefinedFieldsProp, err := expandComputeRegionSecurityPolicyUserDefinedFields(d.Get("user_defined_fields"), d, config)
392+
if err != nil {
393+
return err
394+
} else if v, ok := d.GetOkExists("user_defined_fields"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, userDefinedFieldsProp)) {
395+
obj["userDefinedFields"] = userDefinedFieldsProp
396+
}
338397

339398
url, err := tpgresource.ReplaceVars(d, config, "{{ComputeBasePath}}projects/{{project}}/regions/{{region}}/securityPolicies/{{name}}")
340399
if err != nil {
341400
return err
342401
}
343402

344403
log.Printf("[DEBUG] Updating RegionSecurityPolicy %q: %#v", d.Id(), obj)
404+
updateMask := []string{}
405+
406+
if d.HasChange("description") {
407+
updateMask = append(updateMask, "description")
408+
}
409+
410+
if d.HasChange("fingerprint") {
411+
updateMask = append(updateMask, "fingerprint")
412+
}
413+
414+
if d.HasChange("ddos_protection_config") {
415+
updateMask = append(updateMask, "ddosProtectionConfig")
416+
}
417+
418+
if d.HasChange("user_defined_fields") {
419+
updateMask = append(updateMask, "userDefinedFields")
420+
}
421+
// updateMask is a URL parameter but not present in the schema, so ReplaceVars
422+
// won't set it
423+
url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")})
424+
if err != nil {
425+
return err
426+
}
345427

346428
// err == nil indicates that the billing_project value was found
347429
if bp, err := tpgresource.GetBillingProject(d, config); err == nil {
@@ -494,6 +576,74 @@ func flattenComputeRegionSecurityPolicySelfLinkWithPolicyId(v interface{}, d *sc
494576
return v
495577
}
496578

579+
func flattenComputeRegionSecurityPolicyUserDefinedFields(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
580+
if v == nil {
581+
return v
582+
}
583+
l := v.([]interface{})
584+
transformed := make([]interface{}, 0, len(l))
585+
for _, raw := range l {
586+
original := raw.(map[string]interface{})
587+
if len(original) < 1 {
588+
// Do not include empty json objects coming back from the api
589+
continue
590+
}
591+
transformed = append(transformed, map[string]interface{}{
592+
"name": flattenComputeRegionSecurityPolicyUserDefinedFieldsName(original["name"], d, config),
593+
"base": flattenComputeRegionSecurityPolicyUserDefinedFieldsBase(original["base"], d, config),
594+
"offset": flattenComputeRegionSecurityPolicyUserDefinedFieldsOffset(original["offset"], d, config),
595+
"size": flattenComputeRegionSecurityPolicyUserDefinedFieldsSize(original["size"], d, config),
596+
"mask": flattenComputeRegionSecurityPolicyUserDefinedFieldsMask(original["mask"], d, config),
597+
})
598+
}
599+
return transformed
600+
}
601+
func flattenComputeRegionSecurityPolicyUserDefinedFieldsName(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
602+
return v
603+
}
604+
605+
func flattenComputeRegionSecurityPolicyUserDefinedFieldsBase(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
606+
return v
607+
}
608+
609+
func flattenComputeRegionSecurityPolicyUserDefinedFieldsOffset(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
610+
// Handles the string fixed64 format
611+
if strVal, ok := v.(string); ok {
612+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
613+
return intVal
614+
}
615+
}
616+
617+
// number values are represented as float64
618+
if floatVal, ok := v.(float64); ok {
619+
intVal := int(floatVal)
620+
return intVal
621+
}
622+
623+
return v // let terraform core handle it otherwise
624+
}
625+
626+
func flattenComputeRegionSecurityPolicyUserDefinedFieldsSize(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
627+
// Handles the string fixed64 format
628+
if strVal, ok := v.(string); ok {
629+
if intVal, err := tpgresource.StringToFixed64(strVal); err == nil {
630+
return intVal
631+
}
632+
}
633+
634+
// number values are represented as float64
635+
if floatVal, ok := v.(float64); ok {
636+
intVal := int(floatVal)
637+
return intVal
638+
}
639+
640+
return v // let terraform core handle it otherwise
641+
}
642+
643+
func flattenComputeRegionSecurityPolicyUserDefinedFieldsMask(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
644+
return v
645+
}
646+
497647
func flattenComputeRegionSecurityPolicyRegion(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
498648
if v == nil {
499649
return v
@@ -540,6 +690,76 @@ func expandComputeRegionSecurityPolicyDdosProtectionConfigDdosProtection(v inter
540690
return v, nil
541691
}
542692

693+
func expandComputeRegionSecurityPolicyUserDefinedFields(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
694+
l := v.([]interface{})
695+
req := make([]interface{}, 0, len(l))
696+
for _, raw := range l {
697+
if raw == nil {
698+
continue
699+
}
700+
original := raw.(map[string]interface{})
701+
transformed := make(map[string]interface{})
702+
703+
transformedName, err := expandComputeRegionSecurityPolicyUserDefinedFieldsName(original["name"], d, config)
704+
if err != nil {
705+
return nil, err
706+
} else if val := reflect.ValueOf(transformedName); val.IsValid() && !tpgresource.IsEmptyValue(val) {
707+
transformed["name"] = transformedName
708+
}
709+
710+
transformedBase, err := expandComputeRegionSecurityPolicyUserDefinedFieldsBase(original["base"], d, config)
711+
if err != nil {
712+
return nil, err
713+
} else if val := reflect.ValueOf(transformedBase); val.IsValid() && !tpgresource.IsEmptyValue(val) {
714+
transformed["base"] = transformedBase
715+
}
716+
717+
transformedOffset, err := expandComputeRegionSecurityPolicyUserDefinedFieldsOffset(original["offset"], d, config)
718+
if err != nil {
719+
return nil, err
720+
} else if val := reflect.ValueOf(transformedOffset); val.IsValid() && !tpgresource.IsEmptyValue(val) {
721+
transformed["offset"] = transformedOffset
722+
}
723+
724+
transformedSize, err := expandComputeRegionSecurityPolicyUserDefinedFieldsSize(original["size"], d, config)
725+
if err != nil {
726+
return nil, err
727+
} else if val := reflect.ValueOf(transformedSize); val.IsValid() && !tpgresource.IsEmptyValue(val) {
728+
transformed["size"] = transformedSize
729+
}
730+
731+
transformedMask, err := expandComputeRegionSecurityPolicyUserDefinedFieldsMask(original["mask"], d, config)
732+
if err != nil {
733+
return nil, err
734+
} else if val := reflect.ValueOf(transformedMask); val.IsValid() && !tpgresource.IsEmptyValue(val) {
735+
transformed["mask"] = transformedMask
736+
}
737+
738+
req = append(req, transformed)
739+
}
740+
return req, nil
741+
}
742+
743+
func expandComputeRegionSecurityPolicyUserDefinedFieldsName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
744+
return v, nil
745+
}
746+
747+
func expandComputeRegionSecurityPolicyUserDefinedFieldsBase(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
748+
return v, nil
749+
}
750+
751+
func expandComputeRegionSecurityPolicyUserDefinedFieldsOffset(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
752+
return v, nil
753+
}
754+
755+
func expandComputeRegionSecurityPolicyUserDefinedFieldsSize(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
756+
return v, nil
757+
}
758+
759+
func expandComputeRegionSecurityPolicyUserDefinedFieldsMask(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
760+
return v, nil
761+
}
762+
543763
func expandComputeRegionSecurityPolicyRegion(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
544764
f, err := tpgresource.ParseGlobalFieldValue("regions", v.(string), "project", d, config, true)
545765
if err != nil {

google-beta/services/compute/resource_compute_region_security_policy_generated_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,57 @@ resource "google_compute_region_security_policy" "region-sec-policy-ddos-protect
108108
`, context)
109109
}
110110

111+
func TestAccComputeRegionSecurityPolicy_regionSecurityPolicyWithUserDefinedFieldsExample(t *testing.T) {
112+
t.Parallel()
113+
114+
context := map[string]interface{}{
115+
"random_suffix": acctest.RandString(t, 10),
116+
}
117+
118+
acctest.VcrTest(t, resource.TestCase{
119+
PreCheck: func() { acctest.AccTestPreCheck(t) },
120+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t),
121+
CheckDestroy: testAccCheckComputeRegionSecurityPolicyDestroyProducer(t),
122+
Steps: []resource.TestStep{
123+
{
124+
Config: testAccComputeRegionSecurityPolicy_regionSecurityPolicyWithUserDefinedFieldsExample(context),
125+
},
126+
{
127+
ResourceName: "google_compute_region_security_policy.region-sec-policy-user-defined-fields",
128+
ImportState: true,
129+
ImportStateVerify: true,
130+
ImportStateVerifyIgnore: []string{"region"},
131+
},
132+
},
133+
})
134+
}
135+
136+
func testAccComputeRegionSecurityPolicy_regionSecurityPolicyWithUserDefinedFieldsExample(context map[string]interface{}) string {
137+
return acctest.Nprintf(`
138+
resource "google_compute_region_security_policy" "region-sec-policy-user-defined-fields" {
139+
provider = google-beta
140+
141+
name = "tf-test-my-sec-policy-user-defined-fields%{random_suffix}"
142+
description = "with user defined fields"
143+
type = "CLOUD_ARMOR_NETWORK"
144+
user_defined_fields {
145+
name = "SIG1_AT_0"
146+
base = "UDP"
147+
offset = 8
148+
size = 2
149+
mask = "0x8F00"
150+
}
151+
user_defined_fields {
152+
name = "SIG2_AT_8"
153+
base = "UDP"
154+
offset = 16
155+
size = 4
156+
mask = "0xFFFFFFFF"
157+
}
158+
}
159+
`, context)
160+
}
161+
111162
func testAccCheckComputeRegionSecurityPolicyDestroyProducer(t *testing.T) func(s *terraform.State) error {
112163
return func(s *terraform.State) error {
113164
for name, rs := range s.RootModule().Resources {

0 commit comments

Comments
 (0)