From 1b32a98c22867e4b7e2cfa41e86fa2b1ec502029 Mon Sep 17 00:00:00 2001 From: Modular Magician Date: Tue, 21 Nov 2023 21:17:21 +0000 Subject: [PATCH] Add access restrictions field for google_iam_workforce_pool resource (#9490) [upstream:05e14a25287adfa933db8be44f4da737dfe38197] Signed-off-by: Modular Magician --- .changelog/9490.txt | 3 + .../resource_iam_workforce_pool.go | 140 ++++++++++++++++++ ...ource_iam_workforce_pool_generated_test.go | 20 ++- .../resource_iam_workforce_pool_test.go | 42 +++++- .../docs/r/iam_workforce_pool.html.markdown | 47 +++++- 5 files changed, 230 insertions(+), 22 deletions(-) create mode 100644 .changelog/9490.txt diff --git a/.changelog/9490.txt b/.changelog/9490.txt new file mode 100644 index 0000000000..4adb72ac3a --- /dev/null +++ b/.changelog/9490.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +iam: added `allowedServices`, `disableProgrammaticSignin` fields to `google_iam_workforce_pool` resource +``` diff --git a/google-beta/services/iamworkforcepool/resource_iam_workforce_pool.go b/google-beta/services/iamworkforcepool/resource_iam_workforce_pool.go index ace10a80dc..34733fb2ca 100644 --- a/google-beta/services/iamworkforcepool/resource_iam_workforce_pool.go +++ b/google-beta/services/iamworkforcepool/resource_iam_workforce_pool.go @@ -91,6 +91,40 @@ func ResourceIAMWorkforcePoolWorkforcePool() *schema.Resource { digits, or hyphens. It must start with a letter, and cannot have a trailing hyphen. The prefix 'gcp-' is reserved for use by Google, and may not be specified.`, }, + "access_restrictions": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Description: `Configure access restrictions on the workforce pool users. This is an optional field. If specified web +sign-in can be restricted to given set of services or programmatic sign-in can be disabled for pool users.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allowed_services": { + Type: schema.TypeList, + Optional: true, + Description: `Services allowed for web sign-in with the workforce pool. +If not set by default there are no restrictions.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain": { + Type: schema.TypeString, + Optional: true, + Description: `Domain name of the service. +Example: console.cloud.google`, + }, + }, + }, + }, + "disable_programmatic_signin": { + Type: schema.TypeBool, + Optional: true, + Description: `Disable programmatic sign-in by disabling token issue via the Security Token API endpoint. +See [Security Token Service API](https://cloud.google.com/iam/docs/reference/sts/rest).`, + }, + }, + }, + }, "description": { Type: schema.TypeString, Optional: true, @@ -180,6 +214,12 @@ func resourceIAMWorkforcePoolWorkforcePoolCreate(d *schema.ResourceData, meta in } else if v, ok := d.GetOkExists("session_duration"); !tpgresource.IsEmptyValue(reflect.ValueOf(sessionDurationProp)) && (ok || !reflect.DeepEqual(v, sessionDurationProp)) { obj["sessionDuration"] = sessionDurationProp } + accessRestrictionsProp, err := expandIAMWorkforcePoolWorkforcePoolAccessRestrictions(d.Get("access_restrictions"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("access_restrictions"); !tpgresource.IsEmptyValue(reflect.ValueOf(accessRestrictionsProp)) && (ok || !reflect.DeepEqual(v, accessRestrictionsProp)) { + obj["accessRestrictions"] = accessRestrictionsProp + } url, err := tpgresource.ReplaceVars(d, config, "{{IAMWorkforcePoolBasePath}}locations/{{location}}/workforcePools?workforcePoolId={{workforce_pool_id}}") if err != nil { @@ -292,6 +332,9 @@ func resourceIAMWorkforcePoolWorkforcePoolRead(d *schema.ResourceData, meta inte if err := d.Set("session_duration", flattenIAMWorkforcePoolWorkforcePoolSessionDuration(res["sessionDuration"], d, config)); err != nil { return fmt.Errorf("Error reading WorkforcePool: %s", err) } + if err := d.Set("access_restrictions", flattenIAMWorkforcePoolWorkforcePoolAccessRestrictions(res["accessRestrictions"], d, config)); err != nil { + return fmt.Errorf("Error reading WorkforcePool: %s", err) + } return nil } @@ -490,6 +533,47 @@ func flattenIAMWorkforcePoolWorkforcePoolSessionDuration(v interface{}, d *schem return v } +func flattenIAMWorkforcePoolWorkforcePoolAccessRestrictions(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + if len(original) == 0 { + return nil + } + transformed := make(map[string]interface{}) + transformed["allowed_services"] = + flattenIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServices(original["allowedServices"], d, config) + transformed["disable_programmatic_signin"] = + flattenIAMWorkforcePoolWorkforcePoolAccessRestrictionsDisableProgrammaticSignin(original["disableProgrammaticSignin"], d, config) + return []interface{}{transformed} +} +func flattenIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServices(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.([]interface{}) + transformed := make([]interface{}, 0, len(l)) + for _, raw := range l { + original := raw.(map[string]interface{}) + if len(original) < 1 { + // Do not include empty json objects coming back from the api + continue + } + transformed = append(transformed, map[string]interface{}{ + "domain": flattenIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServicesDomain(original["domain"], d, config), + }) + } + return transformed +} +func flattenIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServicesDomain(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIAMWorkforcePoolWorkforcePoolAccessRestrictionsDisableProgrammaticSignin(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandIAMWorkforcePoolWorkforcePoolParent(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -510,6 +594,62 @@ func expandIAMWorkforcePoolWorkforcePoolSessionDuration(v interface{}, d tpgreso return v, nil } +func expandIAMWorkforcePoolWorkforcePoolAccessRestrictions(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 || l[0] == nil { + return nil, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedAllowedServices, err := expandIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServices(original["allowed_services"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAllowedServices); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["allowedServices"] = transformedAllowedServices + } + + transformedDisableProgrammaticSignin, err := expandIAMWorkforcePoolWorkforcePoolAccessRestrictionsDisableProgrammaticSignin(original["disable_programmatic_signin"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDisableProgrammaticSignin); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["disableProgrammaticSignin"] = transformedDisableProgrammaticSignin + } + + return transformed, nil +} + +func expandIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServices(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + l := v.([]interface{}) + req := make([]interface{}, 0, len(l)) + for _, raw := range l { + if raw == nil { + continue + } + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedDomain, err := expandIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServicesDomain(original["domain"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedDomain); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["domain"] = transformedDomain + } + + req = append(req, transformed) + } + return req, nil +} + +func expandIAMWorkforcePoolWorkforcePoolAccessRestrictionsAllowedServicesDomain(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIAMWorkforcePoolWorkforcePoolAccessRestrictionsDisableProgrammaticSignin(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + func resourceIAMWorkforcePoolWorkforcePoolDecoder(d *schema.ResourceData, meta interface{}, res map[string]interface{}) (map[string]interface{}, error) { if v := res["state"]; v == "DELETED" { return nil, nil diff --git a/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_generated_test.go b/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_generated_test.go index f5bea2803d..a563227ae3 100644 --- a/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_generated_test.go +++ b/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_generated_test.go @@ -96,13 +96,19 @@ func TestAccIAMWorkforcePoolWorkforcePool_iamWorkforcePoolFullExample(t *testing func testAccIAMWorkforcePoolWorkforcePool_iamWorkforcePoolFullExample(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_workforce_pool" "example" { - workforce_pool_id = "tf-test-example-pool%{random_suffix}" - parent = "organizations/%{org_id}" - location = "global" - display_name = "Display name" - description = "A sample workforce pool." - disabled = false - session_duration = "7200s" + workforce_pool_id = "tf-test-example-pool%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" + display_name = "Display name" + description = "A sample workforce pool." + disabled = false + session_duration = "7200s" + access_restrictions { + allowed_services { + domain = "backstory.chronicle.security" + } + disable_programmatic_signin = false + } } `, context) } diff --git a/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_test.go b/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_test.go index 1ada1c161b..814ffe9d54 100644 --- a/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_test.go +++ b/google-beta/services/iamworkforcepool/resource_iam_workforce_pool_test.go @@ -31,7 +31,7 @@ func TestAccIAMWorkforcePoolWorkforcePool_full(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccIAMWorkforcePoolWorkforcePool_update(context), + Config: testAccIAMWorkforcePoolWorkforcePool_full_update(context), }, { ResourceName: "google_iam_workforce_pool.my_pool", @@ -64,7 +64,7 @@ func TestAccIAMWorkforcePoolWorkforcePool_minimal(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccIAMWorkforcePoolWorkforcePool_update(context), + Config: testAccIAMWorkforcePoolWorkforcePool_minimal_update(context), }, { ResourceName: "google_iam_workforce_pool.my_pool", @@ -77,29 +77,55 @@ func TestAccIAMWorkforcePoolWorkforcePool_minimal(t *testing.T) { func testAccIAMWorkforcePoolWorkforcePool_full(context map[string]interface{}) string { return acctest.Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" + display_name = "Display name" + description = "A sample workforce pool." + disabled = false + session_duration = "7200s" + access_restrictions { + allowed_services { + domain = "backstory.chronicle.security" + } + disable_programmatic_signin = false + } +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePool_minimal(context map[string]interface{}) string { + return acctest.Nprintf(` resource "google_iam_workforce_pool" "my_pool" { workforce_pool_id = "my-pool-%{random_suffix}" parent = "organizations/%{org_id}" location = "global" - display_name = "Display name" - description = "A sample workforce pool." - disabled = false - session_duration = "7200s" } `, context) } -func testAccIAMWorkforcePoolWorkforcePool_minimal(context map[string]interface{}) string { +func testAccIAMWorkforcePoolWorkforcePool_full_update(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_workforce_pool" "my_pool" { workforce_pool_id = "my-pool-%{random_suffix}" parent = "organizations/%{org_id}" location = "global" + display_name = "New display name" + description = "A sample workforce pool with updated description." + disabled = true + session_duration = "3600s" + access_restrictions { + allowed_services { + domain = "backstory.chronicle.security" + } + disable_programmatic_signin = false + } } `, context) } -func testAccIAMWorkforcePoolWorkforcePool_update(context map[string]interface{}) string { +func testAccIAMWorkforcePoolWorkforcePool_minimal_update(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_workforce_pool" "my_pool" { workforce_pool_id = "my-pool-%{random_suffix}" diff --git a/website/docs/r/iam_workforce_pool.html.markdown b/website/docs/r/iam_workforce_pool.html.markdown index cdfcdc4ab3..6732f3e39a 100644 --- a/website/docs/r/iam_workforce_pool.html.markdown +++ b/website/docs/r/iam_workforce_pool.html.markdown @@ -47,13 +47,19 @@ resource "google_iam_workforce_pool" "example" { ```hcl resource "google_iam_workforce_pool" "example" { - workforce_pool_id = "example-pool" - parent = "organizations/123456789" - location = "global" - display_name = "Display name" - description = "A sample workforce pool." - disabled = false - session_duration = "7200s" + workforce_pool_id = "example-pool" + parent = "organizations/123456789" + location = "global" + display_name = "Display name" + description = "A sample workforce pool." + disabled = false + session_duration = "7200s" + access_restrictions { + allowed_services { + domain = "backstory.chronicle.security" + } + disable_programmatic_signin = false + } } ``` @@ -101,6 +107,33 @@ The following arguments are supported: If `sessionDuration` is not configured, minted credentials have a default duration of one hour (3600s). A duration in seconds with up to nine fractional digits, ending with '`s`'. Example: "`3.5s`". +* `access_restrictions` - + (Optional) + Configure access restrictions on the workforce pool users. This is an optional field. If specified web + sign-in can be restricted to given set of services or programmatic sign-in can be disabled for pool users. + Structure is [documented below](#nested_access_restrictions). + + +The `access_restrictions` block supports: + +* `allowed_services` - + (Optional) + Services allowed for web sign-in with the workforce pool. + If not set by default there are no restrictions. + Structure is [documented below](#nested_allowed_services). + +* `disable_programmatic_signin` - + (Optional) + Disable programmatic sign-in by disabling token issue via the Security Token API endpoint. + See [Security Token Service API](https://cloud.google.com/iam/docs/reference/sts/rest). + + +The `allowed_services` block supports: + +* `domain` - + (Optional) + Domain name of the service. + Example: console.cloud.google ## Attributes Reference