Skip to content

Commit 99beb07

Browse files
VPC SC dry-run mode (#3353) (#1940)
* VPC SC dry-run * unset spec on acceptance test Signed-off-by: Modular Magician <[email protected]>
1 parent 2086f82 commit 99beb07

File tree

4 files changed

+436
-5
lines changed

4 files changed

+436
-5
lines changed

.changelog/3353.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
accesscontextmanager: added `spec` and `use_explicit_dry_run_spec` to `google_access_context_manager_service_perimeter` to test perimeter configurations in dry-run mode.
3+
```

google-beta/resource_access_context_manager_service_perimeter.go

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,87 @@ with a common perimeter, but should not be able to share data among
9292
themselves.`,
9393
Default: "PERIMETER_TYPE_REGULAR",
9494
},
95+
"spec": {
96+
Type: schema.TypeList,
97+
Optional: true,
98+
Description: `Proposed (or dry run) ServicePerimeter configuration.
99+
This configuration allows to specify and test ServicePerimeter configuration
100+
without enforcing actual access restrictions. Only allowed to be set when
101+
the 'useExplicitDryRunSpec' flag is set.`,
102+
MaxItems: 1,
103+
Elem: &schema.Resource{
104+
Schema: map[string]*schema.Schema{
105+
"access_levels": {
106+
Type: schema.TypeList,
107+
Optional: true,
108+
Description: `A list of AccessLevel resource names that allow resources within
109+
the ServicePerimeter to be accessed from the internet.
110+
AccessLevels listed must be in the same policy as this
111+
ServicePerimeter. Referencing a nonexistent AccessLevel is a
112+
syntax error. If no AccessLevel names are listed, resources within
113+
the perimeter can only be accessed via GCP calls with request
114+
origins within the perimeter. For Service Perimeter Bridge, must
115+
be empty.
116+
117+
Format: accessPolicies/{policy_id}/accessLevels/{access_level_name}`,
118+
Elem: &schema.Schema{
119+
Type: schema.TypeString,
120+
},
121+
AtLeastOneOf: []string{"status.0.resources", "status.0.access_levels", "status.0.restricted_services"},
122+
},
123+
"resources": {
124+
Type: schema.TypeList,
125+
Optional: true,
126+
Description: `A list of GCP resources that are inside of the service perimeter.
127+
Currently only projects are allowed.
128+
Format: projects/{project_number}`,
129+
Elem: &schema.Schema{
130+
Type: schema.TypeString,
131+
},
132+
AtLeastOneOf: []string{"status.0.resources", "status.0.access_levels", "status.0.restricted_services"},
133+
},
134+
"restricted_services": {
135+
Type: schema.TypeList,
136+
Optional: true,
137+
Description: `GCP services that are subject to the Service Perimeter
138+
restrictions. Must contain a list of services. For example, if
139+
'storage.googleapis.com' is specified, access to the storage
140+
buckets inside the perimeter must meet the perimeter's access
141+
restrictions.`,
142+
Elem: &schema.Schema{
143+
Type: schema.TypeString,
144+
},
145+
AtLeastOneOf: []string{"status.0.resources", "status.0.access_levels", "status.0.restricted_services"},
146+
},
147+
"vpc_accessible_services": {
148+
Type: schema.TypeList,
149+
Optional: true,
150+
Description: `Specifies how APIs are allowed to communicate within the Service
151+
Perimeter.`,
152+
MaxItems: 1,
153+
Elem: &schema.Resource{
154+
Schema: map[string]*schema.Schema{
155+
"allowed_services": {
156+
Type: schema.TypeList,
157+
Optional: true,
158+
Description: `The list of APIs usable within the Service Perimeter.
159+
Must be empty unless 'enableRestriction' is True.`,
160+
Elem: &schema.Schema{
161+
Type: schema.TypeString,
162+
},
163+
},
164+
"enable_restriction": {
165+
Type: schema.TypeBool,
166+
Optional: true,
167+
Description: `Whether to restrict API calls within the Service Perimeter to the
168+
list of APIs specified in 'allowedServices'.`,
169+
},
170+
},
171+
},
172+
},
173+
},
174+
},
175+
},
95176
"status": {
96177
Type: schema.TypeList,
97178
Optional: true,
@@ -174,6 +255,19 @@ list of APIs specified in 'allowedServices'.`,
174255
},
175256
},
176257
},
258+
"use_explicit_dry_run_spec": {
259+
Type: schema.TypeBool,
260+
Optional: true,
261+
Description: `Use explicit dry run spec flag. Ordinarily, a dry-run spec implicitly exists
262+
for all Service Perimeters, and that spec is identical to the status for those
263+
Service Perimeters. When this flag is set, it inhibits the generation of the
264+
implicit spec, thereby allowing the user to explicitly provide a
265+
configuration ("spec") to use in a dry-run version of the Service Perimeter.
266+
This allows the user to test changes to the enforced config ("status") without
267+
actually enforcing them. This testing is done through analyzing the differences
268+
between currently enforced and suggested restrictions. useExplicitDryRunSpec must
269+
bet set to True if any of the fields in the spec are set to non-default values.`,
270+
},
177271
"create_time": {
178272
Type: schema.TypeString,
179273
Computed: true,
@@ -216,6 +310,18 @@ func resourceAccessContextManagerServicePerimeterCreate(d *schema.ResourceData,
216310
} else if v, ok := d.GetOkExists("status"); !isEmptyValue(reflect.ValueOf(statusProp)) && (ok || !reflect.DeepEqual(v, statusProp)) {
217311
obj["status"] = statusProp
218312
}
313+
specProp, err := expandAccessContextManagerServicePerimeterSpec(d.Get("spec"), d, config)
314+
if err != nil {
315+
return err
316+
} else if v, ok := d.GetOkExists("spec"); !isEmptyValue(reflect.ValueOf(specProp)) && (ok || !reflect.DeepEqual(v, specProp)) {
317+
obj["spec"] = specProp
318+
}
319+
useExplicitDryRunSpecProp, err := expandAccessContextManagerServicePerimeterUseExplicitDryRunSpec(d.Get("use_explicit_dry_run_spec"), d, config)
320+
if err != nil {
321+
return err
322+
} else if v, ok := d.GetOkExists("use_explicit_dry_run_spec"); !isEmptyValue(reflect.ValueOf(useExplicitDryRunSpecProp)) && (ok || !reflect.DeepEqual(v, useExplicitDryRunSpecProp)) {
323+
obj["useExplicitDryRunSpec"] = useExplicitDryRunSpecProp
324+
}
219325
parentProp, err := expandAccessContextManagerServicePerimeterParent(d.Get("parent"), d, config)
220326
if err != nil {
221327
return err
@@ -318,6 +424,12 @@ func resourceAccessContextManagerServicePerimeterRead(d *schema.ResourceData, me
318424
if err := d.Set("status", flattenAccessContextManagerServicePerimeterStatus(res["status"], d, config)); err != nil {
319425
return fmt.Errorf("Error reading ServicePerimeter: %s", err)
320426
}
427+
if err := d.Set("spec", flattenAccessContextManagerServicePerimeterSpec(res["spec"], d, config)); err != nil {
428+
return fmt.Errorf("Error reading ServicePerimeter: %s", err)
429+
}
430+
if err := d.Set("use_explicit_dry_run_spec", flattenAccessContextManagerServicePerimeterUseExplicitDryRunSpec(res["useExplicitDryRunSpec"], d, config)); err != nil {
431+
return fmt.Errorf("Error reading ServicePerimeter: %s", err)
432+
}
321433
if err := d.Set("name", flattenAccessContextManagerServicePerimeterName(res["name"], d, config)); err != nil {
322434
return fmt.Errorf("Error reading ServicePerimeter: %s", err)
323435
}
@@ -347,6 +459,18 @@ func resourceAccessContextManagerServicePerimeterUpdate(d *schema.ResourceData,
347459
} else if v, ok := d.GetOkExists("status"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, statusProp)) {
348460
obj["status"] = statusProp
349461
}
462+
specProp, err := expandAccessContextManagerServicePerimeterSpec(d.Get("spec"), d, config)
463+
if err != nil {
464+
return err
465+
} else if v, ok := d.GetOkExists("spec"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, specProp)) {
466+
obj["spec"] = specProp
467+
}
468+
useExplicitDryRunSpecProp, err := expandAccessContextManagerServicePerimeterUseExplicitDryRunSpec(d.Get("use_explicit_dry_run_spec"), d, config)
469+
if err != nil {
470+
return err
471+
} else if v, ok := d.GetOkExists("use_explicit_dry_run_spec"); !isEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, useExplicitDryRunSpecProp)) {
472+
obj["useExplicitDryRunSpec"] = useExplicitDryRunSpecProp
473+
}
350474

351475
obj, err = resourceAccessContextManagerServicePerimeterEncoder(d, meta, obj)
352476
if err != nil {
@@ -379,6 +503,14 @@ func resourceAccessContextManagerServicePerimeterUpdate(d *schema.ResourceData,
379503
if d.HasChange("status") {
380504
updateMask = append(updateMask, "status")
381505
}
506+
507+
if d.HasChange("spec") {
508+
updateMask = append(updateMask, "spec")
509+
}
510+
511+
if d.HasChange("use_explicit_dry_run_spec") {
512+
updateMask = append(updateMask, "useExplicitDryRunSpec")
513+
}
382514
// updateMask is a URL parameter but not present in the schema, so replaceVars
383515
// won't set it
384516
url, err = addQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")})
@@ -536,6 +668,64 @@ func flattenAccessContextManagerServicePerimeterStatusVPCAccessibleServicesAllow
536668
return schema.NewSet(schema.HashString, v.([]interface{}))
537669
}
538670

671+
func flattenAccessContextManagerServicePerimeterSpec(v interface{}, d *schema.ResourceData, config *Config) interface{} {
672+
if v == nil {
673+
return nil
674+
}
675+
original := v.(map[string]interface{})
676+
if len(original) == 0 {
677+
return nil
678+
}
679+
transformed := make(map[string]interface{})
680+
transformed["resources"] =
681+
flattenAccessContextManagerServicePerimeterSpecResources(original["resources"], d, config)
682+
transformed["access_levels"] =
683+
flattenAccessContextManagerServicePerimeterSpecAccessLevels(original["accessLevels"], d, config)
684+
transformed["restricted_services"] =
685+
flattenAccessContextManagerServicePerimeterSpecRestrictedServices(original["restrictedServices"], d, config)
686+
transformed["vpc_accessible_services"] =
687+
flattenAccessContextManagerServicePerimeterSpecVPCAccessibleServices(original["vpcAccessibleServices"], d, config)
688+
return []interface{}{transformed}
689+
}
690+
func flattenAccessContextManagerServicePerimeterSpecResources(v interface{}, d *schema.ResourceData, config *Config) interface{} {
691+
return v
692+
}
693+
694+
func flattenAccessContextManagerServicePerimeterSpecAccessLevels(v interface{}, d *schema.ResourceData, config *Config) interface{} {
695+
return v
696+
}
697+
698+
func flattenAccessContextManagerServicePerimeterSpecRestrictedServices(v interface{}, d *schema.ResourceData, config *Config) interface{} {
699+
return v
700+
}
701+
702+
func flattenAccessContextManagerServicePerimeterSpecVPCAccessibleServices(v interface{}, d *schema.ResourceData, config *Config) interface{} {
703+
if v == nil {
704+
return nil
705+
}
706+
original := v.(map[string]interface{})
707+
if len(original) == 0 {
708+
return nil
709+
}
710+
transformed := make(map[string]interface{})
711+
transformed["enable_restriction"] =
712+
flattenAccessContextManagerServicePerimeterSpecVPCAccessibleServicesEnableRestriction(original["enableRestriction"], d, config)
713+
transformed["allowed_services"] =
714+
flattenAccessContextManagerServicePerimeterSpecVPCAccessibleServicesAllowedServices(original["allowedServices"], d, config)
715+
return []interface{}{transformed}
716+
}
717+
func flattenAccessContextManagerServicePerimeterSpecVPCAccessibleServicesEnableRestriction(v interface{}, d *schema.ResourceData, config *Config) interface{} {
718+
return v
719+
}
720+
721+
func flattenAccessContextManagerServicePerimeterSpecVPCAccessibleServicesAllowedServices(v interface{}, d *schema.ResourceData, config *Config) interface{} {
722+
return v
723+
}
724+
725+
func flattenAccessContextManagerServicePerimeterUseExplicitDryRunSpec(v interface{}, d *schema.ResourceData, config *Config) interface{} {
726+
return v
727+
}
728+
539729
func flattenAccessContextManagerServicePerimeterName(v interface{}, d *schema.ResourceData, config *Config) interface{} {
540730
return v
541731
}
@@ -640,6 +830,96 @@ func expandAccessContextManagerServicePerimeterStatusVPCAccessibleServicesAllowe
640830
return v, nil
641831
}
642832

833+
func expandAccessContextManagerServicePerimeterSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
834+
l := v.([]interface{})
835+
if len(l) == 0 || l[0] == nil {
836+
return nil, nil
837+
}
838+
raw := l[0]
839+
original := raw.(map[string]interface{})
840+
transformed := make(map[string]interface{})
841+
842+
transformedResources, err := expandAccessContextManagerServicePerimeterSpecResources(original["resources"], d, config)
843+
if err != nil {
844+
return nil, err
845+
} else if val := reflect.ValueOf(transformedResources); val.IsValid() && !isEmptyValue(val) {
846+
transformed["resources"] = transformedResources
847+
}
848+
849+
transformedAccessLevels, err := expandAccessContextManagerServicePerimeterSpecAccessLevels(original["access_levels"], d, config)
850+
if err != nil {
851+
return nil, err
852+
} else if val := reflect.ValueOf(transformedAccessLevels); val.IsValid() && !isEmptyValue(val) {
853+
transformed["accessLevels"] = transformedAccessLevels
854+
}
855+
856+
transformedRestrictedServices, err := expandAccessContextManagerServicePerimeterSpecRestrictedServices(original["restricted_services"], d, config)
857+
if err != nil {
858+
return nil, err
859+
} else if val := reflect.ValueOf(transformedRestrictedServices); val.IsValid() && !isEmptyValue(val) {
860+
transformed["restrictedServices"] = transformedRestrictedServices
861+
}
862+
863+
transformedVPCAccessibleServices, err := expandAccessContextManagerServicePerimeterSpecVPCAccessibleServices(original["vpc_accessible_services"], d, config)
864+
if err != nil {
865+
return nil, err
866+
} else if val := reflect.ValueOf(transformedVPCAccessibleServices); val.IsValid() && !isEmptyValue(val) {
867+
transformed["vpcAccessibleServices"] = transformedVPCAccessibleServices
868+
}
869+
870+
return transformed, nil
871+
}
872+
873+
func expandAccessContextManagerServicePerimeterSpecResources(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
874+
return v, nil
875+
}
876+
877+
func expandAccessContextManagerServicePerimeterSpecAccessLevels(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
878+
return v, nil
879+
}
880+
881+
func expandAccessContextManagerServicePerimeterSpecRestrictedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
882+
return v, nil
883+
}
884+
885+
func expandAccessContextManagerServicePerimeterSpecVPCAccessibleServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
886+
l := v.([]interface{})
887+
if len(l) == 0 || l[0] == nil {
888+
return nil, nil
889+
}
890+
raw := l[0]
891+
original := raw.(map[string]interface{})
892+
transformed := make(map[string]interface{})
893+
894+
transformedEnableRestriction, err := expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesEnableRestriction(original["enable_restriction"], d, config)
895+
if err != nil {
896+
return nil, err
897+
} else if val := reflect.ValueOf(transformedEnableRestriction); val.IsValid() && !isEmptyValue(val) {
898+
transformed["enableRestriction"] = transformedEnableRestriction
899+
}
900+
901+
transformedAllowedServices, err := expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesAllowedServices(original["allowed_services"], d, config)
902+
if err != nil {
903+
return nil, err
904+
} else if val := reflect.ValueOf(transformedAllowedServices); val.IsValid() && !isEmptyValue(val) {
905+
transformed["allowedServices"] = transformedAllowedServices
906+
}
907+
908+
return transformed, nil
909+
}
910+
911+
func expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesEnableRestriction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
912+
return v, nil
913+
}
914+
915+
func expandAccessContextManagerServicePerimeterSpecVPCAccessibleServicesAllowedServices(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
916+
return v, nil
917+
}
918+
919+
func expandAccessContextManagerServicePerimeterUseExplicitDryRunSpec(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
920+
return v, nil
921+
}
922+
643923
func expandAccessContextManagerServicePerimeterParent(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
644924
return v, nil
645925
}

0 commit comments

Comments
 (0)