diff --git a/.changelog/13814.txt b/.changelog/13814.txt new file mode 100644 index 00000000000..cb77ca0b841 --- /dev/null +++ b/.changelog/13814.txt @@ -0,0 +1,6 @@ +```release-note:enhancement +iambeta: added `mode`, `inline_certificate_issuance_config`, and `inline_trust_config` fields to `google_iam_workload_identity_pool` resource +``` +```release-note:new-resource +`google_iam_workload_identity_pool_iam_*` +``` \ No newline at end of file diff --git a/google-beta/provider/provider_mmv1_resources.go b/google-beta/provider/provider_mmv1_resources.go index 1abee9d2cb0..dbfd95cad55 100644 --- a/google-beta/provider/provider_mmv1_resources.go +++ b/google-beta/provider/provider_mmv1_resources.go @@ -491,6 +491,7 @@ var generatedIAMDatasources = map[string]*schema.Resource{ "google_gke_hub_feature_iam_policy": tpgiamresource.DataSourceIamPolicy(gkehub2.GKEHub2FeatureIamSchema, gkehub2.GKEHub2FeatureIamUpdaterProducer), "google_gke_hub_scope_iam_policy": tpgiamresource.DataSourceIamPolicy(gkehub2.GKEHub2ScopeIamSchema, gkehub2.GKEHub2ScopeIamUpdaterProducer), "google_healthcare_consent_store_iam_policy": tpgiamresource.DataSourceIamPolicy(healthcare.HealthcareConsentStoreIamSchema, healthcare.HealthcareConsentStoreIamUpdaterProducer), + "google_iam_workload_identity_pool_iam_policy": tpgiamresource.DataSourceIamPolicy(iambeta.IAMBetaWorkloadIdentityPoolIamSchema, iambeta.IAMBetaWorkloadIdentityPoolIamUpdaterProducer), "google_iap_app_engine_service_iam_policy": tpgiamresource.DataSourceIamPolicy(iap.IapAppEngineServiceIamSchema, iap.IapAppEngineServiceIamUpdaterProducer), "google_iap_app_engine_version_iam_policy": tpgiamresource.DataSourceIamPolicy(iap.IapAppEngineVersionIamSchema, iap.IapAppEngineVersionIamUpdaterProducer), "google_iap_web_cloud_run_service_iam_policy": tpgiamresource.DataSourceIamPolicy(iap.IapWebCloudRunServiceIamSchema, iap.IapWebCloudRunServiceIamUpdaterProducer), @@ -565,8 +566,8 @@ var handwrittenIAMDatasources = map[string]*schema.Resource{ // Resources // Generated resources: 654 -// Generated IAM resources: 327 -// Total generated resources: 981 +// Generated IAM resources: 330 +// Total generated resources: 984 var generatedResources = map[string]*schema.Resource{ "google_folder_access_approval_settings": accessapproval.ResourceAccessApprovalFolderSettings(), "google_organization_access_approval_settings": accessapproval.ResourceAccessApprovalOrganizationSettings(), @@ -1169,6 +1170,9 @@ var generatedResources = map[string]*schema.Resource{ "google_iam_principal_access_boundary_policy": iam3.ResourceIAM3PrincipalAccessBoundaryPolicy(), "google_iam_projects_policy_binding": iam3.ResourceIAM3ProjectsPolicyBinding(), "google_iam_workload_identity_pool": iambeta.ResourceIAMBetaWorkloadIdentityPool(), + "google_iam_workload_identity_pool_iam_binding": tpgiamresource.ResourceIamBinding(iambeta.IAMBetaWorkloadIdentityPoolIamSchema, iambeta.IAMBetaWorkloadIdentityPoolIamUpdaterProducer, iambeta.IAMBetaWorkloadIdentityPoolIdParseFunc), + "google_iam_workload_identity_pool_iam_member": tpgiamresource.ResourceIamMember(iambeta.IAMBetaWorkloadIdentityPoolIamSchema, iambeta.IAMBetaWorkloadIdentityPoolIamUpdaterProducer, iambeta.IAMBetaWorkloadIdentityPoolIdParseFunc), + "google_iam_workload_identity_pool_iam_policy": tpgiamresource.ResourceIamPolicy(iambeta.IAMBetaWorkloadIdentityPoolIamSchema, iambeta.IAMBetaWorkloadIdentityPoolIamUpdaterProducer, iambeta.IAMBetaWorkloadIdentityPoolIdParseFunc), "google_iam_workload_identity_pool_provider": iambeta.ResourceIAMBetaWorkloadIdentityPoolProvider(), "google_iam_oauth_client": iamworkforcepool.ResourceIAMWorkforcePoolOauthClient(), "google_iam_oauth_client_credential": iamworkforcepool.ResourceIAMWorkforcePoolOauthClientCredential(), diff --git a/google-beta/services/iambeta/iam_iam_workload_identity_pool.go b/google-beta/services/iambeta/iam_iam_workload_identity_pool.go new file mode 100644 index 00000000000..bcae5015ec1 --- /dev/null +++ b/google-beta/services/iambeta/iam_iam_workload_identity_pool.go @@ -0,0 +1,228 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This code is generated by Magic Modules using the following: +// +// Configuration: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/iambeta/WorkloadIdentityPool.yaml +// Template: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/iam_policy.go.tmpl +// +// DO NOT EDIT this file directly. Any changes made to this file will be +// overwritten during the next generation cycle. +// +// ---------------------------------------------------------------------------- + +package iambeta + +import ( + "fmt" + + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "google.golang.org/api/cloudresourcemanager/v1" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgiamresource" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" +) + +var IAMBetaWorkloadIdentityPoolIamSchema = map[string]*schema.Schema{ + "project": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ForceNew: true, + }, + "workload_identity_pool_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + DiffSuppressFunc: tpgresource.CompareSelfLinkOrResourceName, + }, +} + +type IAMBetaWorkloadIdentityPoolIamUpdater struct { + project string + workloadIdentityPoolId string + d tpgresource.TerraformResourceData + Config *transport_tpg.Config +} + +func IAMBetaWorkloadIdentityPoolIamUpdaterProducer(d tpgresource.TerraformResourceData, config *transport_tpg.Config) (tpgiamresource.ResourceIamUpdater, error) { + values := make(map[string]string) + + project, _ := tpgresource.GetProject(d, config) + if project != "" { + if err := d.Set("project", project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + } + values["project"] = project + if v, ok := d.GetOk("workload_identity_pool_id"); ok { + values["workload_identity_pool_id"] = v.(string) + } + + // We may have gotten either a long or short name, so attempt to parse long name if possible + m, err := tpgresource.GetImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/global/workloadIdentityPools/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Get("workload_identity_pool_id").(string)) + if err != nil { + return nil, err + } + + for k, v := range m { + values[k] = v + } + + u := &IAMBetaWorkloadIdentityPoolIamUpdater{ + project: values["project"], + workloadIdentityPoolId: values["workload_identity_pool_id"], + d: d, + Config: config, + } + + if err := d.Set("project", u.project); err != nil { + return nil, fmt.Errorf("Error setting project: %s", err) + } + if err := d.Set("workload_identity_pool_id", u.GetResourceId()); err != nil { + return nil, fmt.Errorf("Error setting workload_identity_pool_id: %s", err) + } + + return u, nil +} + +func IAMBetaWorkloadIdentityPoolIdParseFunc(d *schema.ResourceData, config *transport_tpg.Config) error { + values := make(map[string]string) + + project, _ := tpgresource.GetProject(d, config) + if project != "" { + values["project"] = project + } + + m, err := tpgresource.GetImportIdQualifiers([]string{"projects/(?P[^/]+)/locations/global/workloadIdentityPools/(?P[^/]+)", "(?P[^/]+)/(?P[^/]+)", "(?P[^/]+)"}, d, config, d.Id()) + if err != nil { + return err + } + + for k, v := range m { + values[k] = v + } + + u := &IAMBetaWorkloadIdentityPoolIamUpdater{ + project: values["project"], + workloadIdentityPoolId: values["workload_identity_pool_id"], + d: d, + Config: config, + } + if err := d.Set("workload_identity_pool_id", u.GetResourceId()); err != nil { + return fmt.Errorf("Error setting workload_identity_pool_id: %s", err) + } + d.SetId(u.GetResourceId()) + return nil +} + +func (u *IAMBetaWorkloadIdentityPoolIamUpdater) GetResourceIamPolicy() (*cloudresourcemanager.Policy, error) { + url, err := u.qualifyWorkloadIdentityPoolUrl("getIamPolicy") + if err != nil { + return nil, err + } + + project, err := tpgresource.GetProject(u.d, u.Config) + if err != nil { + return nil, err + } + var obj map[string]interface{} + obj = map[string]interface{}{ + "options": map[string]interface{}{ + "requestedPolicyVersion": tpgiamresource.IamPolicyVersion, + }, + } + + userAgent, err := tpgresource.GenerateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return nil, err + } + + policy, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: u.Config, + Method: "POST", + Project: project, + RawURL: url, + UserAgent: userAgent, + Body: obj, + }) + if err != nil { + return nil, errwrap.Wrapf(fmt.Sprintf("Error retrieving IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + out := &cloudresourcemanager.Policy{} + err = tpgresource.Convert(policy, out) + if err != nil { + return nil, errwrap.Wrapf("Cannot convert a policy to a resource manager policy: {{err}}", err) + } + + return out, nil +} + +func (u *IAMBetaWorkloadIdentityPoolIamUpdater) SetResourceIamPolicy(policy *cloudresourcemanager.Policy) error { + json, err := tpgresource.ConvertToMap(policy) + if err != nil { + return err + } + + obj := make(map[string]interface{}) + obj["policy"] = json + + url, err := u.qualifyWorkloadIdentityPoolUrl("setIamPolicy") + if err != nil { + return err + } + project, err := tpgresource.GetProject(u.d, u.Config) + if err != nil { + return err + } + + userAgent, err := tpgresource.GenerateUserAgentString(u.d, u.Config.UserAgent) + if err != nil { + return err + } + + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: u.Config, + Method: "POST", + Project: project, + RawURL: url, + UserAgent: userAgent, + Body: obj, + Timeout: u.d.Timeout(schema.TimeoutCreate), + }) + if err != nil { + return errwrap.Wrapf(fmt.Sprintf("Error setting IAM policy for %s: {{err}}", u.DescribeResource()), err) + } + + return nil +} + +func (u *IAMBetaWorkloadIdentityPoolIamUpdater) qualifyWorkloadIdentityPoolUrl(methodIdentifier string) (string, error) { + urlTemplate := fmt.Sprintf("{{IAMBetaBasePath}}%s:%s", fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", u.project, u.workloadIdentityPoolId), methodIdentifier) + url, err := tpgresource.ReplaceVars(u.d, u.Config, urlTemplate) + if err != nil { + return "", err + } + return url, nil +} + +func (u *IAMBetaWorkloadIdentityPoolIamUpdater) GetResourceId() string { + return fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", u.project, u.workloadIdentityPoolId) +} + +func (u *IAMBetaWorkloadIdentityPoolIamUpdater) GetMutexKey() string { + return fmt.Sprintf("iam-iambeta-workloadidentitypool-%s", u.GetResourceId()) +} + +func (u *IAMBetaWorkloadIdentityPoolIamUpdater) DescribeResource() string { + return fmt.Sprintf("iambeta workloadidentitypool %q", u.GetResourceId()) +} diff --git a/google-beta/services/iambeta/iam_iam_workload_identity_pool_generated_test.go b/google-beta/services/iambeta/iam_iam_workload_identity_pool_generated_test.go new file mode 100644 index 00000000000..cbdc65f9ff2 --- /dev/null +++ b/google-beta/services/iambeta/iam_iam_workload_identity_pool_generated_test.go @@ -0,0 +1,578 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +// ---------------------------------------------------------------------------- +// +// *** AUTO GENERATED CODE *** Type: MMv1 *** +// +// ---------------------------------------------------------------------------- +// +// This code is generated by Magic Modules using the following: +// +// Configuration: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/iambeta/WorkloadIdentityPool.yaml +// Template: https://github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/examples/base_configs/iam_test_file.go.tmpl +// +// DO NOT EDIT this file directly. Any changes made to this file will be +// overwritten during the next generation cycle. +// +// ---------------------------------------------------------------------------- + +package iambeta_test + +import ( + "fmt" + "strings" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + + "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/envvar" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" +) + +func TestAccIAMBetaWorkloadIdentityPoolIamBindingGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamBinding_basicGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + // Test Iam Binding update + Config: testAccIAMBetaWorkloadIdentityPoolIamBinding_updateGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamMemberGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + // Test Iam Member creation (no update for member, no need to test) + Config: testAccIAMBetaWorkloadIdentityPoolIamMember_basicGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer user:admin@hashicorptest.com", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamPolicyGenerated(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamPolicy_basicGenerated(context), + Check: resource.TestCheckResourceAttrSet("data.google_iam_workload_identity_pool_iam_policy.foo", "policy_data"), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMBetaWorkloadIdentityPoolIamPolicy_emptyBinding(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamBindingGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamBinding_withConditionGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer %s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamBindingGenerated_withAndWithoutCondition(t *testing.T) { + // Multiple fine-grained resources + acctest.SkipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamBinding_withAndWithoutConditionGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_binding.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_binding.foo2", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer %s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_binding.foo3", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer %s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"]), context["condition_title_no_desc"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamMemberGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamMember_withConditionGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer user:admin@hashicorptest.com %s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamMemberGenerated_withAndWithoutCondition(t *testing.T) { + // Multiple fine-grained resources + acctest.SkipIfVcr(t) + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamMember_withAndWithoutConditionGenerated(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_member.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer user:admin@hashicorptest.com", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_member.foo2", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer user:admin@hashicorptest.com %s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"]), context["condition_title"]), + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_member.foo3", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s roles/iam.workloadIdentityPoolViewer user:admin@hashicorptest.com %s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"]), context["condition_title_no_desc"]), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccIAMBetaWorkloadIdentityPoolIamPolicyGenerated_withCondition(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + "role": "roles/iam.workloadIdentityPoolViewer", + "condition_title": "expires_after_2019_12_31", + "condition_expr": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + "condition_desc": "Expiring at midnight of 2019-12-31", + "condition_title_no_desc": "expires_after_2019_12_31-no-description", + "condition_expr_no_desc": `request.time < timestamp(\"2020-01-01T00:00:00Z\")`, + } + + // Test should have 2 bindings: one with a description and one without. Any < chars are converted to a unicode character by the API. + expectedPolicyData := acctest.Nprintf(`{"bindings":[{"condition":{"description":"%{condition_desc}","expression":"%{condition_expr}","title":"%{condition_title}"},"members":["user:admin@hashicorptest.com"],"role":"%{role}"},{"condition":{"expression":"%{condition_expr}","title":"%{condition_title}-no-description"},"members":["user:admin@hashicorptest.com"],"role":"%{role}"}]}`, context) + expectedPolicyData = strings.Replace(expectedPolicyData, "<", "\\u003c", -1) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolIamPolicy_withConditionGenerated(context), + Check: resource.ComposeAggregateTestCheckFunc( + // TODO(SarahFrench) - uncomment once https://github.com/GoogleCloudPlatform/magic-modules/pull/6466 merged + // resource.TestCheckResourceAttr("data.google_iam_policy.foo", "policy_data", expectedPolicyData), + resource.TestCheckResourceAttr("google_iam_workload_identity_pool_iam_policy.foo", "policy_data", expectedPolicyData), + resource.TestCheckResourceAttrWith("data.google_iam_policy.foo", "policy_data", tpgresource.CheckGoogleIamPolicy), + ), + }, + { + ResourceName: "google_iam_workload_identity_pool_iam_policy.foo", + ImportStateId: fmt.Sprintf("projects/%s/locations/global/workloadIdentityPools/%s", envvar.GetTestProjectFromEnv(), fmt.Sprintf("tf-test-example-pool%s", context["random_suffix"])), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccIAMBetaWorkloadIdentityPoolIamMember_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_member" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + member = "user:admin@hashicorptest.com" +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamPolicy_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + } +} + +resource "google_iam_workload_identity_pool_iam_policy" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + policy_data = data.google_iam_policy.foo.policy_data +} + +data "google_iam_workload_identity_pool_iam_policy" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + depends_on = [ + google_iam_workload_identity_pool_iam_policy.foo + ] +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamPolicy_emptyBinding(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +data "google_iam_policy" "foo" { +} + +resource "google_iam_workload_identity_pool_iam_policy" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamBinding_basicGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_binding" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamBinding_updateGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_binding" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + members = ["user:admin@hashicorptest.com", "user:gterraformtest1@gmail.com"] +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamBinding_withConditionGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_binding" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "%{condition_desc}" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamBinding_withAndWithoutConditionGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_binding" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] +} + +resource "google_iam_workload_identity_pool_iam_binding" "foo2" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "%{condition_desc}" + expression = "%{condition_expr}" + } +} + +resource "google_iam_workload_identity_pool_iam_binding" "foo3" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + # Check that lack of description doesn't cause any issues + # Relates to issue : https://github.com/hashicorp/terraform-provider-google/issues/8701 + title = "%{condition_title_no_desc}" + expression = "%{condition_expr_no_desc}" + } +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamMember_withConditionGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_member" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + title = "%{condition_title}" + description = "%{condition_desc}" + expression = "%{condition_expr}" + } +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamMember_withAndWithoutConditionGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_iam_member" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + member = "user:admin@hashicorptest.com" +} + +resource "google_iam_workload_identity_pool_iam_member" "foo2" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + title = "%{condition_title}" + description = "%{condition_desc}" + expression = "%{condition_expr}" + } +} + +resource "google_iam_workload_identity_pool_iam_member" "foo3" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "%{role}" + member = "user:admin@hashicorptest.com" + condition { + # Check that lack of description doesn't cause any issues + # Relates to issue : https://github.com/hashicorp/terraform-provider-google/issues/8701 + title = "%{condition_title_no_desc}" + expression = "%{condition_expr_no_desc}" + } +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolIamPolicy_withConditionGenerated(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +data "google_iam_policy" "foo" { + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + # Check that lack of description doesn't cause any issues + # Relates to issue : https://github.com/hashicorp/terraform-provider-google/issues/8701 + title = "%{condition_title_no_desc}" + expression = "%{condition_expr_no_desc}" + } + } + binding { + role = "%{role}" + members = ["user:admin@hashicorptest.com"] + condition { + title = "%{condition_title}" + description = "%{condition_desc}" + expression = "%{condition_expr}" + } + } +} + +resource "google_iam_workload_identity_pool_iam_policy" "foo" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + policy_data = data.google_iam_policy.foo.policy_data +} +`, context) +} diff --git a/google-beta/services/iambeta/resource_iam_workload_identity_pool.go b/google-beta/services/iambeta/resource_iam_workload_identity_pool.go index 488268ba4e5..3a9586d2257 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool.go +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool.go @@ -33,6 +33,7 @@ import ( "github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource" transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport" + "github.com/hashicorp/terraform-provider-google-beta/google-beta/verify" ) const workloadIdentityPoolIdRegexp = `^[0-9a-z-]+$` @@ -111,6 +112,138 @@ access again.`, Optional: true, Description: `A display name for the pool. Cannot exceed 32 characters.`, }, + "inline_certificate_issuance_config": { + Type: schema.TypeList, + Optional: true, + Description: `Represents configuration for generating mutual TLS (mTLS) certificates for the identities +within this pool. Defines the Certificate Authority (CA) pool resources and configurations +required for issuance and rotation of mTLS workload certificates.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "ca_pools": { + Type: schema.TypeMap, + Required: true, + Description: `A required mapping of a cloud region to the CA pool resource located in that region used +for certificate issuance, adhering to these constraints: + +* **Key format:** A supported cloud region name equivalent to the location identifier in +the corresponding map entry's value. +* **Value format:** A valid CA pool resource path format like: +'projects/{project}/locations/{location}/caPools/{ca_pool}' +* **Region Matching:** Workloads are ONLY issued certificates from CA pools within the +same region. Also the CA pool region (in value) must match the workload's region (key).`, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "key_algorithm": { + Type: schema.TypeString, + Computed: true, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"RSA_2048", "RSA_3072", "RSA_4096", "ECDSA_P256", "ECDSA_P384", ""}), + Description: `Key algorithm to use when generating the key pair. This key pair will be used to create +the certificate. If unspecified, this will default to 'ECDSA_P256'. + +* 'RSA_2048': Specifies RSA with a 2048-bit modulus. +* 'RSA_3072': Specifies RSA with a 3072-bit modulus. +* 'RSA_4096': Specifies RSA with a 4096-bit modulus. +* 'ECDSA_P256': Specifies ECDSA with curve P256. +* 'ECDSA_P384': Specifies ECDSA with curve P384. Possible values: ["RSA_2048", "RSA_3072", "RSA_4096", "ECDSA_P256", "ECDSA_P384"]`, + }, + "lifetime": { + Type: schema.TypeString, + Computed: true, + Optional: true, + Description: `Lifetime of the workload certificates issued by the CA pool in seconds. Must be between +'86400s' (24 hours) to '2592000s' (30 days), ends in the suffix "'s'" (indicating seconds) +and is preceded by the number of seconds. If unspecified, this will be defaulted to +'86400s' (24 hours).`, + }, + "rotation_window_percentage": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `Rotation window percentage indicating when certificate rotation should be initiated based +on remaining lifetime. Must be between '50' - '80'. If unspecified, this will be defaulted +to '50'.`, + }, + }, + }, + }, + "inline_trust_config": { + Type: schema.TypeList, + Optional: true, + Description: `Represents config to add additional trusted trust domains. Defines configuration for extending +trust to additional trust domains. By establishing trust with another domain, the current +domain will recognize and accept certificates issued by entities within the trusted domains. +Note that a trust domain automatically trusts itself, eliminating the need for explicit +configuration.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "additional_trust_bundles": { + Type: schema.TypeSet, + Optional: true, + Description: `Maps specific trust domains (e.g., "example.com") to their corresponding 'TrustStore' +objects, which contain the trusted root certificates for that domain. There can be a +maximum of '10' trust domain entries in this map. + +Note that a trust domain automatically trusts itself and don't need to be specified here. +If however, this 'WorkloadIdentityPool''s trust domain contains any trust anchors in the +'additional_trust_bundles' map, those trust anchors will be *appended to* the Trust Bundle +automatically derived from your 'InlineCertificateIssuanceConfig''s 'ca_pools'.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "trust_domain": { + Type: schema.TypeString, + Required: true, + }, + "trust_anchors": { + Type: schema.TypeList, + Required: true, + Description: `List of Trust Anchors to be used while performing validation against a given +'TrustStore'. The incoming end entity's certificate must be chained up to one of the +trust anchors here.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "pem_certificate": { + Type: schema.TypeString, + Required: true, + Description: `PEM certificate of the PKI used for validation. Must only contain one ca +certificate(either root or intermediate cert).`, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidateEnum([]string{"FEDERATION_ONLY", "TRUST_DOMAIN", ""}), + Description: `The mode for the pool is operating in. Pools with an unspecified mode will operate as if they +are in 'FEDERATION_ONLY' mode. + + +~> **Note** This field cannot be changed after the Workload Identity Pool is created. While +'terraform plan' may show an update if you change this field's value, 'terraform apply' +**will fail with an API error** (such as 'Error 400: Attempted to update an immutable field.'). +To specify a different 'mode', please create a new Workload Identity Pool resource. + +* 'FEDERATION_ONLY': Pools can only be used for federating external workload identities into +Google Cloud. Unless otherwise noted, no structure or format constraints are applied to +workload identities in a 'FEDERATION_ONLY' mode pool, and you may not create any resources +within the pool besides providers. +* 'TRUST_DOMAIN': Pools can be used to assign identities to Google Cloud workloads. All +identities within a 'TRUST_DOMAIN' mode pool must consist of a single namespace and individual +workload identifier. The subject identifier for all identities must conform to the following +format: 'ns//sa/'. +'google_iam_workload_identity_pool_provider's cannot be created within 'TRUST_DOMAIN' +mode pools. Possible values: ["FEDERATION_ONLY", "TRUST_DOMAIN"]`, + }, "name": { Type: schema.TypeString, Computed: true, @@ -121,11 +254,11 @@ access again.`, Type: schema.TypeString, Computed: true, Description: `The state of the pool. -* STATE_UNSPECIFIED: State unspecified. -* ACTIVE: The pool is active, and may be used in Google Cloud policies. -* DELETED: The pool is soft-deleted. Soft-deleted pools are permanently deleted after +* 'STATE_UNSPECIFIED': State unspecified. +* 'ACTIVE': The pool is active, and may be used in Google Cloud policies. +* 'DELETED': The pool is soft-deleted. Soft-deleted pools are permanently deleted after approximately 30 days. You can restore a soft-deleted pool using - UndeleteWorkloadIdentityPool. You cannot reuse the ID of a soft-deleted pool until it is + 'UndeleteWorkloadIdentityPool'. You cannot reuse the ID of a soft-deleted pool until it is permanently deleted. While a pool is deleted, you cannot use it to exchange tokens, or use existing tokens to access resources. If the pool is undeleted, existing tokens grant access again.`, @@ -167,6 +300,24 @@ func resourceIAMBetaWorkloadIdentityPoolCreate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("disabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(disabledProp)) && (ok || !reflect.DeepEqual(v, disabledProp)) { obj["disabled"] = disabledProp } + modeProp, err := expandIAMBetaWorkloadIdentityPoolMode(d.Get("mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("mode"); !tpgresource.IsEmptyValue(reflect.ValueOf(modeProp)) && (ok || !reflect.DeepEqual(v, modeProp)) { + obj["mode"] = modeProp + } + inlineCertificateIssuanceConfigProp, err := expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfig(d.Get("inline_certificate_issuance_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("inline_certificate_issuance_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(inlineCertificateIssuanceConfigProp)) && (ok || !reflect.DeepEqual(v, inlineCertificateIssuanceConfigProp)) { + obj["inlineCertificateIssuanceConfig"] = inlineCertificateIssuanceConfigProp + } + inlineTrustConfigProp, err := expandIAMBetaWorkloadIdentityPoolInlineTrustConfig(d.Get("inline_trust_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("inline_trust_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(inlineTrustConfigProp)) && (ok || !reflect.DeepEqual(v, inlineTrustConfigProp)) { + obj["inlineTrustConfig"] = inlineTrustConfigProp + } url, err := tpgresource.ReplaceVars(d, config, "{{IAMBetaBasePath}}projects/{{project}}/locations/global/workloadIdentityPools?workloadIdentityPoolId={{workload_identity_pool_id}}") if err != nil { @@ -293,6 +444,15 @@ func resourceIAMBetaWorkloadIdentityPoolRead(d *schema.ResourceData, meta interf if err := d.Set("disabled", flattenIAMBetaWorkloadIdentityPoolDisabled(res["disabled"], d, config)); err != nil { return fmt.Errorf("Error reading WorkloadIdentityPool: %s", err) } + if err := d.Set("mode", flattenIAMBetaWorkloadIdentityPoolMode(res["mode"], d, config)); err != nil { + return fmt.Errorf("Error reading WorkloadIdentityPool: %s", err) + } + if err := d.Set("inline_certificate_issuance_config", flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfig(res["inlineCertificateIssuanceConfig"], d, config)); err != nil { + return fmt.Errorf("Error reading WorkloadIdentityPool: %s", err) + } + if err := d.Set("inline_trust_config", flattenIAMBetaWorkloadIdentityPoolInlineTrustConfig(res["inlineTrustConfig"], d, config)); err != nil { + return fmt.Errorf("Error reading WorkloadIdentityPool: %s", err) + } return nil } @@ -331,6 +491,24 @@ func resourceIAMBetaWorkloadIdentityPoolUpdate(d *schema.ResourceData, meta inte } else if v, ok := d.GetOkExists("disabled"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, disabledProp)) { obj["disabled"] = disabledProp } + modeProp, err := expandIAMBetaWorkloadIdentityPoolMode(d.Get("mode"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("mode"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, modeProp)) { + obj["mode"] = modeProp + } + inlineCertificateIssuanceConfigProp, err := expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfig(d.Get("inline_certificate_issuance_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("inline_certificate_issuance_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, inlineCertificateIssuanceConfigProp)) { + obj["inlineCertificateIssuanceConfig"] = inlineCertificateIssuanceConfigProp + } + inlineTrustConfigProp, err := expandIAMBetaWorkloadIdentityPoolInlineTrustConfig(d.Get("inline_trust_config"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("inline_trust_config"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, inlineTrustConfigProp)) { + obj["inlineTrustConfig"] = inlineTrustConfigProp + } url, err := tpgresource.ReplaceVars(d, config, "{{IAMBetaBasePath}}projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}}") if err != nil { @@ -352,6 +530,18 @@ func resourceIAMBetaWorkloadIdentityPoolUpdate(d *schema.ResourceData, meta inte if d.HasChange("disabled") { updateMask = append(updateMask, "disabled") } + + if d.HasChange("mode") { + updateMask = append(updateMask, "mode") + } + + if d.HasChange("inline_certificate_issuance_config") { + updateMask = append(updateMask, "inlineCertificateIssuanceConfig") + } + + if d.HasChange("inline_trust_config") { + updateMask = append(updateMask, "inlineTrustConfig") + } // updateMask is a URL parameter but not present in the schema, so ReplaceVars // won't set it url, err = transport_tpg.AddQueryParams(url, map[string]string{"updateMask": strings.Join(updateMask, ",")}) @@ -491,6 +681,108 @@ func flattenIAMBetaWorkloadIdentityPoolDisabled(v interface{}, d *schema.Resourc return v } +func flattenIAMBetaWorkloadIdentityPoolMode(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfig(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["ca_pools"] = + flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigCaPools(original["caPools"], d, config) + transformed["lifetime"] = + flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigLifetime(original["lifetime"], d, config) + transformed["rotation_window_percentage"] = + flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigRotationWindowPercentage(original["rotationWindowPercentage"], d, config) + transformed["key_algorithm"] = + flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigKeyAlgorithm(original["keyAlgorithm"], d, config) + return []interface{}{transformed} +} +func flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigCaPools(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigLifetime(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigRotationWindowPercentage(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := tpgresource.StringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigKeyAlgorithm(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIAMBetaWorkloadIdentityPoolInlineTrustConfig(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["additional_trust_bundles"] = + flattenIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundles(original["additionalTrustBundles"], d, config) + return []interface{}{transformed} +} +func flattenIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundles(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + if v == nil { + return v + } + l := v.(map[string]interface{}) + transformed := make([]interface{}, 0, len(l)) + for k, raw := range l { + original := raw.(map[string]interface{}) + transformed = append(transformed, map[string]interface{}{ + "trust_domain": k, + "trust_anchors": flattenIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchors(original["trustAnchors"], d, config), + }) + } + return transformed +} +func flattenIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchors(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{}{ + "pem_certificate": flattenIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchorsPemCertificate(original["pemCertificate"], d, config), + }) + } + return transformed +} +func flattenIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchorsPemCertificate(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandIAMBetaWorkloadIdentityPoolDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -503,6 +795,143 @@ func expandIAMBetaWorkloadIdentityPoolDisabled(v interface{}, d tpgresource.Terr return v, nil } +func expandIAMBetaWorkloadIdentityPoolMode(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfig(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{}) + + transformedCaPools, err := expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigCaPools(original["ca_pools"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedCaPools); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["caPools"] = transformedCaPools + } + + transformedLifetime, err := expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigLifetime(original["lifetime"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedLifetime); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["lifetime"] = transformedLifetime + } + + transformedRotationWindowPercentage, err := expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigRotationWindowPercentage(original["rotation_window_percentage"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedRotationWindowPercentage); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["rotationWindowPercentage"] = transformedRotationWindowPercentage + } + + transformedKeyAlgorithm, err := expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigKeyAlgorithm(original["key_algorithm"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedKeyAlgorithm); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["keyAlgorithm"] = transformedKeyAlgorithm + } + + return transformed, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigCaPools(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]string, error) { + if v == nil { + return map[string]string{}, nil + } + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + return m, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigLifetime(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigRotationWindowPercentage(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineCertificateIssuanceConfigKeyAlgorithm(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineTrustConfig(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{}) + + transformedAdditionalTrustBundles, err := expandIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundles(original["additional_trust_bundles"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedAdditionalTrustBundles); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["additionalTrustBundles"] = transformedAdditionalTrustBundles + } + + return transformed, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundles(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (map[string]interface{}, error) { + if v == nil { + return map[string]interface{}{}, nil + } + m := make(map[string]interface{}) + for _, raw := range v.(*schema.Set).List() { + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedTrustAnchors, err := expandIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchors(original["trust_anchors"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTrustAnchors); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["trustAnchors"] = transformedTrustAnchors + } + + transformedTrustDomain, err := tpgresource.ExpandString(original["trust_domain"], d, config) + if err != nil { + return nil, err + } + m[transformedTrustDomain] = transformed + } + return m, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchors(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{}) + + transformedPemCertificate, err := expandIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchorsPemCertificate(original["pem_certificate"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPemCertificate); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["pemCertificate"] = transformedPemCertificate + } + + req = append(req, transformed) + } + return req, nil +} + +func expandIAMBetaWorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundlesTrustAnchorsPemCertificate(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + func resourceIAMBetaWorkloadIdentityPoolDecoder(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/iambeta/resource_iam_workload_identity_pool_generated_meta.yaml b/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_meta.yaml index bfaf90bd0dc..3d5273631a3 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_meta.yaml +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_meta.yaml @@ -8,6 +8,12 @@ fields: - field: 'description' - field: 'disabled' - field: 'display_name' + - field: 'inline_certificate_issuance_config.ca_pools' + - field: 'inline_certificate_issuance_config.key_algorithm' + - field: 'inline_certificate_issuance_config.lifetime' + - field: 'inline_certificate_issuance_config.rotation_window_percentage' + - field: 'inline_trust_config.additional_trust_bundles.trust_store.trust_anchors.pem_certificate' + - field: 'mode' - field: 'name' - field: 'state' - field: 'workload_identity_pool_id' diff --git a/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_test.go b/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_test.go index 1061005dc0c..dd7ce0ec42f 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_test.go +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool_generated_test.go @@ -63,7 +63,7 @@ resource "google_iam_workload_identity_pool" "example" { `, context) } -func TestAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullExample(t *testing.T) { +func TestAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullFederationOnlyModeExample(t *testing.T) { t.Parallel() context := map[string]interface{}{ @@ -72,11 +72,53 @@ func TestAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullExample(t *te acctest.VcrTest(t, resource.TestCase{ PreCheck: func() { acctest.AccTestPreCheck(t) }, - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + ExternalProviders: map[string]resource.ExternalProvider{ + "random": {}, + }, + CheckDestroy: testAccCheckIAMBetaWorkloadIdentityPoolDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullFederationOnlyModeExample(context), + }, + { + ResourceName: "google_iam_workload_identity_pool.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workload_identity_pool_id"}, + }, + }, + }) +} + +func testAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullFederationOnlyModeExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "example" { + provider = google-beta + + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" + display_name = "Name of the pool" + description = "Identity pool operates in FEDERATION_ONLY mode" + disabled = true + mode = "FEDERATION_ONLY" +} +`, context) +} + +func TestAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullTrustDomainModeExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), CheckDestroy: testAccCheckIAMBetaWorkloadIdentityPoolDestroyProducer(t), Steps: []resource.TestStep{ { - Config: testAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullExample(context), + Config: testAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullTrustDomainModeExample(context), }, { ResourceName: "google_iam_workload_identity_pool.example", @@ -88,13 +130,45 @@ func TestAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullExample(t *te }) } -func testAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullExample(context map[string]interface{}) string { +func testAccIAMBetaWorkloadIdentityPool_iamWorkloadIdentityPoolFullTrustDomainModeExample(context map[string]interface{}) string { return acctest.Nprintf(` resource "google_iam_workload_identity_pool" "example" { + provider = google-beta + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" - display_name = "Name of pool" - description = "Identity pool for automated test" + display_name = "Name of the pool" + description = "Identity pool operates in TRUST_DOMAIN mode" disabled = true + mode = "TRUST_DOMAIN" + inline_certificate_issuance_config { + ca_pools = { + "us-central1" : "projects/project-bar/locations/us-central1/caPools/ca-pool-bar" + "asia-east2" : "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo" + } + lifetime = "86400s" + rotation_window_percentage = 50 + key_algorithm = "ECDSA_P256" + } + inline_trust_config { + additional_trust_bundles { + trust_domain = "example.com" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_1.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_2.pem") + } + } + additional_trust_bundles { + trust_domain = "example.net" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_3.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_4.pem") + } + } + } } `, context) } diff --git a/google-beta/services/iambeta/resource_iam_workload_identity_pool_test.go b/google-beta/services/iambeta/resource_iam_workload_identity_pool_test.go index 17f8f98ad21..1ed091895f4 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool_test.go +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool_test.go @@ -4,6 +4,7 @@ package iambeta_test import ( "fmt" + "github.com/hashicorp/terraform-plugin-testing/plancheck" "github.com/hashicorp/terraform-provider-google-beta/google-beta/acctest" "testing" @@ -70,6 +71,54 @@ func TestAccIAMBetaWorkloadIdentityPool_minimal(t *testing.T) { }) } +func TestAccIAMBetaWorkloadIdentityPool_beta_update(t *testing.T) { + t.Parallel() + + randomSuffix := acctest.RandString(t, 10) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + CheckDestroy: testAccCheckIAMBetaWorkloadIdentityPoolDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPool_beta_full(randomSuffix), + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMBetaWorkloadIdentityPool_beta_update(randomSuffix), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_iam_workload_identity_pool.my_pool", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMBetaWorkloadIdentityPool_beta_minimum(randomSuffix), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction("google_iam_workload_identity_pool.my_pool", plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: "google_iam_workload_identity_pool.my_pool", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccIAMBetaWorkloadIdentityPool_full(suffix string) string { return fmt.Sprintf(` resource "google_iam_workload_identity_pool" "my_pool" { @@ -99,3 +148,88 @@ resource "google_iam_workload_identity_pool" "my_pool" { } `, suffix) } + +func testAccIAMBetaWorkloadIdentityPool_beta_full(suffix string) string { + return fmt.Sprintf(` +resource "google_iam_workload_identity_pool" "my_pool" { + provider = google-beta + + workload_identity_pool_id = "my-pool-%s" + display_name = "Name of the pool" + description = "Identity pool operates in TRUST_DOMAIN mode" + disabled = true + mode = "TRUST_DOMAIN" + inline_certificate_issuance_config { + ca_pools = { + "us-central1" : "projects/project-bar/locations/us-central1/caPools/ca-pool-bar" + "asia-east2" : "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo" + } + lifetime = "86400s" + rotation_window_percentage = 50 + key_algorithm = "ECDSA_P256" + } + inline_trust_config { + additional_trust_bundles { + trust_domain = "ca-pool-foo.global.project-foo.workload.id.goog" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_1.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_2.pem") + } + } + additional_trust_bundles { + trust_domain = "ca-pool-bar.global.project-bar.workload.id.goog" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_3.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_4.pem") + } + } + } +} +`, suffix) +} + +func testAccIAMBetaWorkloadIdentityPool_beta_update(suffix string) string { + return fmt.Sprintf(` +resource "google_iam_workload_identity_pool" "my_pool" { + provider = google-beta + + workload_identity_pool_id = "my-pool-%s" + display_name = "Updated name of the pool" + description = "Updated identity pool operates in TRUST_DOMAIN mode" + disabled = false + mode = "TRUST_DOMAIN" + inline_certificate_issuance_config { + ca_pools = { + "us-central2" : "projects/project-bar/locations/us-central2/caPools/ca-pool-bar" + "asia-east1" : "projects/project-foo/locations/asia-east1/caPools/ca-pool-foo" + } + lifetime = "36000s" + rotation_window_percentage = 75 + key_algorithm = "RSA_4096" + } + inline_trust_config { + additional_trust_bundles { + trust_domain = "ca-pool-baz.global.project-baz.workload.id.goog" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_updated.pem") + } + } + } +} +`, suffix) +} + +func testAccIAMBetaWorkloadIdentityPool_beta_minimum(suffix string) string { + return fmt.Sprintf(` +resource "google_iam_workload_identity_pool" "my_pool" { + provider = google-beta + + workload_identity_pool_id = "my-pool-%s" + mode = "TRUST_DOMAIN" +} +`, suffix) +} diff --git a/google-beta/services/iambeta/test-fixtures/trust_anchor_1.pem b/google-beta/services/iambeta/test-fixtures/trust_anchor_1.pem new file mode 100644 index 00000000000..0c7e92db772 --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/trust_anchor_1.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIJALDL1dNMR+H8MA0GCSqGSIb3DQEBCwUAMIGeMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxlMRkwFwYDVQQKDBBHb29nbGUgVGVzdCBDb3JwMSAwHgYDVQQLDBdQcm9kdWN0aW9uIFdlYiBTZXJ2aWNlczEpMCcGA1UEAwwgdXMtd2VzdDIucHJvZC53ZWJhcHAuZXhhbXBsZS5jb20wHhcNMjUwNDI5MjMxMTAyWhcNMzUwNDI3MjMxMTAyWjCBnjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCVN1bm55dmFsZTEZMBcGA1UECgwQR29vZ2xlIFRlc3QgQ29ycDEgMB4GA1UECwwXUHJvZHVjdGlvbiBXZWIgU2VydmljZXMxKTAnBgNVBAMMIHVzLXdlc3QyLnByb2Qud2ViYXBwLmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1YFuo6mMlv+2e9r0LROY3bMwKUyUpaD1Jlf6fVFcTDXTHFYAU8uqjA6bxZDDaIfXIuzUbvXfnVsX7U5yWjDfYf0oRV9QDv/TbagdzBNvIIjIs1kxskO6wBrTmJNkWP3rlnlQhEnTai5X/uARZShajTbKU9yfQFPQj9aG0pptuqwWZQ7DGCpybfuFBQ296Zznul1Sunu090SE7InTsoJtthhUdPZ4krk6EH7bV/59+vjJjOF2rsAFEf9CmN4pLdK0+c003s6fZc/pkja40jwyKgRtRzh9SrDPgnF3Qy/hDGTG+BBGkvQRyBJ4EqtbuE05IUg1Ek58QiF3ET4nB9lqQIDAQABozUwMzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAFv+inLwh8s5XOcM8GVSUwvxGei1WTSntt/ia2AUQa5iM1MIGLpu7EUYZId3Zmc4YCpfzXinnf8aCmWfNXhCXbrYVBZNgUTo3dBYyHR4lSQqVygmxFJ4Hwx8esP1+8W0yG+t7nmmwvMQaLElDl9I8B19VZP6IQwddYOmD/0eFdcrbVh00zvUZPNiuGRvfwTxPphaRDEd/VUWRkTLegRzL5WtJlCBJoP62M9EtHjoYjzUUrRarapgPMZJpO7DRHJwsLUNwHCHvyM+B2gDVmawLCvcxzMZUIBaxoGpyuOI9zbOK2wdGl2fLU48mm5qQQiw7toMcnG/I6Offj4Mu4m90bw== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/google-beta/services/iambeta/test-fixtures/trust_anchor_2.pem b/google-beta/services/iambeta/test-fixtures/trust_anchor_2.pem new file mode 100644 index 00000000000..0775e904699 --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/trust_anchor_2.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIID8jCCAtqgAwIBAgIJAPMKxdVc8n0fMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHQXJpem9uYTEQMA4GA1UEBwwHUGhvZW5peDEZMBcGA1UECgwQR29vZ2xlIFRlc3QgQ29ycDEgMB4GA1UECwwXUHJvZHVjdGlvbiBXZWIgU2VydmljZXMxLDAqBgNVBAMMI3VzLWNlbnRyYWwxLnByb2Qud2ViYXBwLmV4YW1wbGUuY29tMB4XDTI1MDQyOTIzMTUwOFoXDTM1MDQyNzIzMTUwOFowgZwxCzAJBgNVBAYTAlVTMRAwDgYDVQQIDAdBcml6b25hMRAwDgYDVQQHDAdQaG9lbml4MRkwFwYDVQQKDBBHb29nbGUgVGVzdCBDb3JwMSAwHgYDVQQLDBdQcm9kdWN0aW9uIFdlYiBTZXJ2aWNlczEsMCoGA1UEAwwjdXMtY2VudHJhbDEucHJvZC53ZWJhcHAuZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCxzfupfYd1r0DPwAPoD7YvqEmgOhZA3TAbtsPEjo7YeOj93gvTEXpAo7x9X2AAAdTKrgPiVlVKMKuLNEXXTQPOBaLkt08w92FnC2MS9AuihfrLNOei5ImEKCKkzsWquRU1spbRzMnVKW1i6AmZSsElZvxB6F6fW89+sclBMkII0FZPpsiC5q44OvYPgCOXBh4FE6lQddh/EnfAmQfJkPgjTWA/jTzCqKMe+fTU/x29psgEaB/Fa1fQ2P4wWEzzhlxEDEKudBgtRc9VjYECnYK9O72DlzN2K/Gv7M37ipCK2AF96/cPv3R13lk4LbHhSma7xj9VXjjoG3h5jpPJ5tuZAgMBAAGjNTAzMA8GA1UdEwEB/wQFMAMBAf8wCwYDVR0PBAQDAgIEMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUAA4IBAQAllMFpvcMb4DqK6Jukjlw473EvP22MzzF8+kfLWr4i/7KJQDou6sVbaKmSl2SNHCZNanIHANT9JvEr3UqvpujfOOg43M4O0o8vvfZgzcvQHBE1qgRkIPu3TVX/so9TCIvyOL1y0f15AEaRAdY5lMC1G5tjjZqkpJ4OsmVch9zK1SljteRsAJuNKpAyfiAV60YCR1e1gOYADd9kv17imHP89WFwmAL/c6pk0jne8w7Y7A/F122TlAyp+P+gne+EOXQwvBDCwMM4lsb3jS2js9XjKSvlNcRAw1B7cl2qmV79Qg48MlQaad7Ac//2fIlFGOwkWQBmHrVd59wxYzBJk+4o +-----END CERTIFICATE----- \ No newline at end of file diff --git a/google-beta/services/iambeta/test-fixtures/trust_anchor_3.pem b/google-beta/services/iambeta/test-fixtures/trust_anchor_3.pem new file mode 100644 index 00000000000..165d362c24b --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/trust_anchor_3.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIJAM98d8EGv17jMA0GCSqGSIb3DQEBCwUAMIGjMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxlMRkwFwYDVQQKDBBHb29nbGUgVGVzdCBDb3JwMRwwGgYDVQQLDBNTdGFnaW5nIEVudmlyb25tZW50MTIwMAYDVQQDDCl1cy13ZXN0Mi5zdGFnaW5nLWFwaS5pbnRlcm5hbC5leGFtcGxlLm5ldDAeFw0yNTA0MjkyMzI1MTJaFw0zNTA0MjcyMzI1MTJaMIGjMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJU3Vubnl2YWxlMRkwFwYDVQQKDBBHb29nbGUgVGVzdCBDb3JwMRwwGgYDVQQLDBNTdGFnaW5nIEVudmlyb25tZW50MTIwMAYDVQQDDCl1cy13ZXN0Mi5zdGFnaW5nLWFwaS5pbnRlcm5hbC5leGFtcGxlLm5ldDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMLunz2AHYl4MYAlrZvSpRycgggsS+oOx/rJHAgb8jxuJSqGWb2aCnlKD5oC/P+qdthra7DRHR8zHGnrzCHKmsWwsaWqMpMh6VoQP0IyXvpQuhMBnjg7YiaaZ5+vegTIOqW1wWgUPPejVicROiWN7bbTaesoW+VwecvMvyGnlQWCLnSMUKzqUhvKA1nUWd+bPALDCvNtvFKUUA4gfhGRJBh/7aj+/OAIk3TcO1Io4peusvDpIAnVdTbiF3I9F7wHuyDs/nCt4+T/59khQoxOpqBHsmRqDUJbz1ZH/c9/Qmh5B+vPLvAN30K0LDx9l1B3xEy6aw7Rcf1I6MYSR384n5MCAwEAAaM1MDMwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAgQwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggEBAKVIWlkF/5aEVgY1jdREuIoxS0hexH3C5vqLG6jIiGkR3t89MAE60f0+aaR+cGvCnDJiYU0E+c4jDbvv3gIkhh4kvu3yhyFFTX583Zk4NldocwXDubR079AlE16pDnHdKUPdc2Tsxb1g+CWumPF2cjNi14P7eEQ3KdQOO5nV5tEpybsruGIspUZrH6hnc2q7dWRq+Ix6dfJYHIOnyLhkpfIRJ/6rVq6moizGuUAIuRgPrw9U8mSGEE349ZqC5x/sHzWpIgUdIaWLYbwe3PH+mxT4PlWRBmrmBe4BnJ+tl0P1TBTKNRjC2xUvRQGHss7VWbJkfZQhALw54aq1kKk96ns= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/google-beta/services/iambeta/test-fixtures/trust_anchor_4.pem b/google-beta/services/iambeta/test-fixtures/trust_anchor_4.pem new file mode 100644 index 00000000000..34fe5fa2d8e --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/trust_anchor_4.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIID/DCCAuSgAwIBAgIJAMOZdoK0Z53fMA0GCSqGSIb3DQEBCwUAMIGhMQswCQYDVQQGEwJVUzEQMA4GA1UECAwHQXJpem9uYTEQMA4GA1UEBwwHUGhvZW5peDEZMBcGA1UECgwQR29vZ2xlIFRlc3QgQ29ycDEcMBoGA1UECwwTU3RhZ2luZyBFbnZpcm9ubWVudDE1MDMGA1UEAwwsdXMtY2VudHJhbDEuc3RhZ2luZy1hcGkuaW50ZXJuYWwuZXhhbXBsZS5uZXQwHhcNMjUwNDI5MjMyNDMxWhcNMzUwNDI3MjMyNDMxWjCBoTELMAkGA1UEBhMCVVMxEDAOBgNVBAgMB0FyaXpvbmExEDAOBgNVBAcMB1Bob2VuaXgxGTAXBgNVBAoMEEdvb2dsZSBUZXN0IENvcnAxHDAaBgNVBAsME1N0YWdpbmcgRW52aXJvbm1lbnQxNTAzBgNVBAMMLHVzLWNlbnRyYWwxLnN0YWdpbmctYXBpLmludGVybmFsLmV4YW1wbGUubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA5EJGDTTfLz8yLXMqEUuocPJR5rGVF/JvMnmhU36bPRNxuaMt2uBNJQjoVTgsPjR77s9+nxQlls1ad6RPYGCqCXr43qrTYHM5grHcn0uwNgF7lmpTA2p56yQDO0dTko784o9O0eOFsmbtuXkVrYGYYZkoACzRayP7P/kIvfevtFXCP+acNNfMufLJ1ptm9vQrT91McnBM1qf35956M2MAZvVsVQxhfis8bN+qEOunMXOkvqhtYBLNicQV0dVb1osFwNmnEGrBgkrt7ov/1SXi1hoZY0QrUMSFwhSi+Iq7NUsnoP6SQ0MbNOr2thc7tRuDH72TT987zNrmBF9foj1Z2wIDAQABozUwMzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEA3siZEVRWCDzo2qpBMQpkPSTBVgcwIFbbGi0ZmdCatOn6nUPCvfSCIjcPcRVo8lUol6j7yHYDzdLj1ANdwE3IKwSJ4BRd5KrGULc+nCD1RB6Gj6VMHQ0TNgs3Ac36pcxWk6qf+2FDhmFfNu2PuUkSFlQyFbNy48w7Bzxzcy65PrGk8nqRrG2aqiYj3SUAlSSkFvWzK9CYy+ze5glTsP2IjaGaZmx4thThYhdCMI80RfzDFAyZqgJDNU9iVYw2uh/dSHwDwpOdPDfXUYLlLGE0dGIGHb/sMu13rLeT0FEKVABbG4hJPG5+Ajw7jrNwS5CDtXSjBLyLcsFST17R7ehVhg== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/website/docs/d/iam_workload_identity_pool_iam_policy.html.markdown b/website/docs/d/iam_workload_identity_pool_iam_policy.html.markdown new file mode 100644 index 00000000000..21ba2f5c1d6 --- /dev/null +++ b/website/docs/d/iam_workload_identity_pool_iam_policy.html.markdown @@ -0,0 +1,55 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This code is generated by Magic Modules using the following: +# +# Configuration: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/iambeta/WorkloadIdentityPool.yaml +# Template: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/datasource_iam.html.markdown.tmpl +# +# DO NOT EDIT this file directly. Any changes made to this file will be +# overwritten during the next generation cycle. +# +# ---------------------------------------------------------------------------- +subcategory: "Cloud IAM" +description: |- + A datasource to retrieve the IAM policy state for Cloud IAM WorkloadIdentityPool +--- + + +# google_iam_workload_identity_pool_iam_policy + +Retrieves the current IAM policy data for workloadidentitypool +~> **Warning:** This datasource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. + + +## Example Usage + + +```hcl +data "google_iam_workload_identity_pool_iam_policy" "policy" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the project will be parsed from the identifier of the parent resource. If no project is provided in the parent identifier and no project is specified, the provider project is used. + +## Attributes Reference + +The attributes are exported: + +* `etag` - (Computed) The etag of the IAM policy. + +* `policy_data` - (Required only by `google_iam_workload_identity_pool_iam_policy`) The policy data generated by + a `google_iam_policy` data source. diff --git a/website/docs/r/iam_workload_identity_pool.html.markdown b/website/docs/r/iam_workload_identity_pool.html.markdown index 1556d0c8567..82ba10f137f 100644 --- a/website/docs/r/iam_workload_identity_pool.html.markdown +++ b/website/docs/r/iam_workload_identity_pool.html.markdown @@ -29,6 +29,8 @@ To get more information about WorkloadIdentityPool, see: * [API documentation](https://cloud.google.com/iam/docs/reference/rest/v1/projects.locations.workloadIdentityPools) * How-to Guides + * [Configure managed workload identity authentication for Compute Engine](https://cloud.google.com/iam/docs/create-managed-workload-identities) + * [Configure managed workload identity authentication for GKE](https://cloud.google.com/iam/docs/create-managed-workload-identities-gke) * [Managing workload identity pools](https://cloud.google.com/iam/docs/manage-workload-identity-pools-providers#pools)
@@ -45,19 +47,70 @@ resource "google_iam_workload_identity_pool" "example" { } ``` -## Example Usage - Iam Workload Identity Pool Full +## Example Usage - Iam Workload Identity Pool Full Federation Only Mode ```hcl resource "google_iam_workload_identity_pool" "example" { + provider = google-beta + workload_identity_pool_id = "example-pool" - display_name = "Name of pool" - description = "Identity pool for automated test" + display_name = "Name of the pool" + description = "Identity pool operates in FEDERATION_ONLY mode" disabled = true + mode = "FEDERATION_ONLY" +} +``` + +## Example Usage - Iam Workload Identity Pool Full Trust Domain Mode + + +```hcl +resource "google_iam_workload_identity_pool" "example" { + provider = google-beta + + workload_identity_pool_id = "example-pool" + display_name = "Name of the pool" + description = "Identity pool operates in TRUST_DOMAIN mode" + disabled = true + mode = "TRUST_DOMAIN" + inline_certificate_issuance_config { + ca_pools = { + "us-central1" : "projects/project-bar/locations/us-central1/caPools/ca-pool-bar" + "asia-east2" : "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo" + } + lifetime = "86400s" + rotation_window_percentage = 50 + key_algorithm = "ECDSA_P256" + } + inline_trust_config { + additional_trust_bundles { + trust_domain = "example.com" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_1.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_2.pem") + } + } + additional_trust_bundles { + trust_domain = "example.net" + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_3.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_4.pem") + } + } + } } ``` @@ -90,10 +143,117 @@ The following arguments are supported: existing tokens to access resources. If the pool is re-enabled, existing tokens grant access again. +* `mode` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + The mode for the pool is operating in. Pools with an unspecified mode will operate as if they + are in `FEDERATION_ONLY` mode. + + ~> **Note** This field cannot be changed after the Workload Identity Pool is created. While + `terraform plan` may show an update if you change this field's value, `terraform apply` + **will fail with an API error** (such as `Error 400: Attempted to update an immutable field.`). + To specify a different `mode`, please create a new Workload Identity Pool resource. + * `FEDERATION_ONLY`: Pools can only be used for federating external workload identities into + Google Cloud. Unless otherwise noted, no structure or format constraints are applied to + workload identities in a `FEDERATION_ONLY` mode pool, and you may not create any resources + within the pool besides providers. + * `TRUST_DOMAIN`: Pools can be used to assign identities to Google Cloud workloads. All + identities within a `TRUST_DOMAIN` mode pool must consist of a single namespace and individual + workload identifier. The subject identifier for all identities must conform to the following + format: `ns//sa/`. + `google_iam_workload_identity_pool_provider`s cannot be created within `TRUST_DOMAIN` + mode pools. + Possible values are: `FEDERATION_ONLY`, `TRUST_DOMAIN`. + +* `inline_certificate_issuance_config` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + Represents configuration for generating mutual TLS (mTLS) certificates for the identities + within this pool. Defines the Certificate Authority (CA) pool resources and configurations + required for issuance and rotation of mTLS workload certificates. + Structure is [documented below](#nested_inline_certificate_issuance_config). + +* `inline_trust_config` - + (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + Represents config to add additional trusted trust domains. Defines configuration for extending + trust to additional trust domains. By establishing trust with another domain, the current + domain will recognize and accept certificates issued by entities within the trusted domains. + Note that a trust domain automatically trusts itself, eliminating the need for explicit + configuration. + Structure is [documented below](#nested_inline_trust_config). + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. +The `inline_certificate_issuance_config` block supports: + +* `ca_pools` - + (Required) + A required mapping of a cloud region to the CA pool resource located in that region used + for certificate issuance, adhering to these constraints: + * **Key format:** A supported cloud region name equivalent to the location identifier in + the corresponding map entry's value. + * **Value format:** A valid CA pool resource path format like: + `projects/{project}/locations/{location}/caPools/{ca_pool}` + * **Region Matching:** Workloads are ONLY issued certificates from CA pools within the + same region. Also the CA pool region (in value) must match the workload's region (key). + +* `lifetime` - + (Optional) + Lifetime of the workload certificates issued by the CA pool in seconds. Must be between + `86400s` (24 hours) to `2592000s` (30 days), ends in the suffix "`s`" (indicating seconds) + and is preceded by the number of seconds. If unspecified, this will be defaulted to + `86400s` (24 hours). + +* `rotation_window_percentage` - + (Optional) + Rotation window percentage indicating when certificate rotation should be initiated based + on remaining lifetime. Must be between `50` - `80`. If unspecified, this will be defaulted + to `50`. + +* `key_algorithm` - + (Optional) + Key algorithm to use when generating the key pair. This key pair will be used to create + the certificate. If unspecified, this will default to `ECDSA_P256`. + * `RSA_2048`: Specifies RSA with a 2048-bit modulus. + * `RSA_3072`: Specifies RSA with a 3072-bit modulus. + * `RSA_4096`: Specifies RSA with a 4096-bit modulus. + * `ECDSA_P256`: Specifies ECDSA with curve P256. + * `ECDSA_P384`: Specifies ECDSA with curve P384. + Possible values are: `RSA_2048`, `RSA_3072`, `RSA_4096`, `ECDSA_P256`, `ECDSA_P384`. + +The `inline_trust_config` block supports: + +* `additional_trust_bundles` - + (Optional) + Maps specific trust domains (e.g., "example.com") to their corresponding `TrustStore` + objects, which contain the trusted root certificates for that domain. There can be a + maximum of `10` trust domain entries in this map. + Note that a trust domain automatically trusts itself and don't need to be specified here. + If however, this `WorkloadIdentityPool`'s trust domain contains any trust anchors in the + `additional_trust_bundles` map, those trust anchors will be *appended to* the Trust Bundle + automatically derived from your `InlineCertificateIssuanceConfig`'s `ca_pools`. + Structure is [documented below](#nested_inline_trust_config_additional_trust_bundles). + + +The `additional_trust_bundles` block supports: + +* `trust_domain` - (Required) The identifier for this object. Format specified above. + +* `trust_anchors` - + (Required) + List of Trust Anchors to be used while performing validation against a given + `TrustStore`. The incoming end entity's certificate must be chained up to one of the + trust anchors here. + Structure is [documented below](#nested_inline_trust_config_additional_trust_bundles_trust_store_trust_anchors). + + +The `trust_anchors` block supports: + +* `pem_certificate` - + (Required) + PEM certificate of the PKI used for validation. Must only contain one ca + certificate(either root or intermediate cert). + ## Attributes Reference In addition to the arguments listed above, the following computed attributes are exported: @@ -102,11 +262,11 @@ In addition to the arguments listed above, the following computed attributes are * `state` - The state of the pool. - * STATE_UNSPECIFIED: State unspecified. - * ACTIVE: The pool is active, and may be used in Google Cloud policies. - * DELETED: The pool is soft-deleted. Soft-deleted pools are permanently deleted after + * `STATE_UNSPECIFIED`: State unspecified. + * `ACTIVE`: The pool is active, and may be used in Google Cloud policies. + * `DELETED`: The pool is soft-deleted. Soft-deleted pools are permanently deleted after approximately 30 days. You can restore a soft-deleted pool using - UndeleteWorkloadIdentityPool. You cannot reuse the ID of a soft-deleted pool until it is + `UndeleteWorkloadIdentityPool`. You cannot reuse the ID of a soft-deleted pool until it is permanently deleted. While a pool is deleted, you cannot use it to exchange tokens, or use existing tokens to access resources. If the pool is undeleted, existing tokens grant access again. diff --git a/website/docs/r/iam_workload_identity_pool_iam.html.markdown b/website/docs/r/iam_workload_identity_pool_iam.html.markdown new file mode 100644 index 00000000000..1d522eded2f --- /dev/null +++ b/website/docs/r/iam_workload_identity_pool_iam.html.markdown @@ -0,0 +1,226 @@ +--- +# ---------------------------------------------------------------------------- +# +# *** AUTO GENERATED CODE *** Type: MMv1 *** +# +# ---------------------------------------------------------------------------- +# +# This code is generated by Magic Modules using the following: +# +# Configuration: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/products/iambeta/WorkloadIdentityPool.yaml +# Template: https:#github.com/GoogleCloudPlatform/magic-modules/tree/main/mmv1/templates/terraform/resource_iam.html.markdown.tmpl +# +# DO NOT EDIT this file directly. Any changes made to this file will be +# overwritten during the next generation cycle. +# +# ---------------------------------------------------------------------------- +subcategory: "Cloud IAM" +description: |- + Collection of resources to manage IAM policy for Cloud IAM WorkloadIdentityPool +--- + +# IAM policy for Cloud IAM WorkloadIdentityPool +Three different resources help you manage your IAM policy for Cloud IAM WorkloadIdentityPool. Each of these resources serves a different use case: + +* `google_iam_workload_identity_pool_iam_policy`: Authoritative. Sets the IAM policy for the workloadidentitypool and replaces any existing policy already attached. +* `google_iam_workload_identity_pool_iam_binding`: Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the workloadidentitypool are preserved. +* `google_iam_workload_identity_pool_iam_member`: Non-authoritative. Updates the IAM policy to grant a role to a new member. Other members for the role for the workloadidentitypool are preserved. + +A data source can be used to retrieve policy data in advent you do not need creation + +* `google_iam_workload_identity_pool_iam_policy`: Retrieves the IAM policy for the workloadidentitypool + +~> **Note:** `google_iam_workload_identity_pool_iam_policy` **cannot** be used in conjunction with `google_iam_workload_identity_pool_iam_binding` and `google_iam_workload_identity_pool_iam_member` or they will fight over what your policy should be. + +~> **Note:** `google_iam_workload_identity_pool_iam_binding` resources **can be** used in conjunction with `google_iam_workload_identity_pool_iam_member` resources **only if** they do not grant privilege to the same role. + +~> **Note:** This resource supports IAM Conditions but they have some known limitations which can be found [here](https://cloud.google.com/iam/docs/conditions-overview#limitations). Please review this article if you are having issues with IAM Conditions. + +~> **Warning:** This resource is in beta, and should be used with the terraform-provider-google-beta provider. +See [Provider Versions](https://terraform.io/docs/providers/google/guides/provider_versions.html) for more details on beta resources. + +## google_iam_workload_identity_pool_iam_policy + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/iam.workloadIdentityPoolViewer" + members = [ + "user:jane@example.com", + ] + } +} + +resource "google_iam_workload_identity_pool_iam_policy" "policy" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + policy_data = data.google_iam_policy.admin.policy_data +} +``` + +With IAM Conditions: + +```hcl +data "google_iam_policy" "admin" { + binding { + role = "roles/iam.workloadIdentityPoolViewer" + members = [ + "user:jane@example.com", + ] + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } + } +} + +resource "google_iam_workload_identity_pool_iam_policy" "policy" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + policy_data = data.google_iam_policy.admin.policy_data +} +``` +## google_iam_workload_identity_pool_iam_binding + +```hcl +resource "google_iam_workload_identity_pool_iam_binding" "binding" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "roles/iam.workloadIdentityPoolViewer" + members = [ + "user:jane@example.com", + ] +} +``` + +With IAM Conditions: + +```hcl +resource "google_iam_workload_identity_pool_iam_binding" "binding" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "roles/iam.workloadIdentityPoolViewer" + members = [ + "user:jane@example.com", + ] + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } +} +``` +## google_iam_workload_identity_pool_iam_member + +```hcl +resource "google_iam_workload_identity_pool_iam_member" "member" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "roles/iam.workloadIdentityPoolViewer" + member = "user:jane@example.com" +} +``` + +With IAM Conditions: + +```hcl +resource "google_iam_workload_identity_pool_iam_member" "member" { + project = google_iam_workload_identity_pool.example.project + workload_identity_pool_id = google_iam_workload_identity_pool.example.workload_identity_pool_id + role = "roles/iam.workloadIdentityPoolViewer" + member = "user:jane@example.com" + + condition { + title = "expires_after_2019_12_31" + description = "Expiring at midnight of 2019-12-31" + expression = "request.time < timestamp(\"2020-01-01T00:00:00Z\")" + } +} +``` + +## Argument Reference + +The following arguments are supported: + + +* `project` - (Optional) The ID of the project in which the resource belongs. + If it is not provided, the project will be parsed from the identifier of the parent resource. If no project is provided in the parent identifier and no project is specified, the provider project is used. + +* `member/members` - (Required) Identities that will be granted the privilege in `role`. + Each entry can have one of the following values: + * **allUsers**: A special identifier that represents anyone who is on the internet; with or without a Google account. + * **allAuthenticatedUsers**: A special identifier that represents anyone who is authenticated with a Google account or a service account. + * **user:{emailid}**: An email address that represents a specific Google account. For example, alice@gmail.com or joe@example.com. + * **serviceAccount:{emailid}**: An email address that represents a service account. For example, my-other-app@appspot.gserviceaccount.com. + * **group:{emailid}**: An email address that represents a Google group. For example, admins@example.com. + * **domain:{domain}**: A G Suite domain (primary, instead of alias) name that represents all the users of that domain. For example, google.com or example.com. + * **projectOwner:projectid**: Owners of the given project. For example, "projectOwner:my-example-project" + * **projectEditor:projectid**: Editors of the given project. For example, "projectEditor:my-example-project" + * **projectViewer:projectid**: Viewers of the given project. For example, "projectViewer:my-example-project" + +* `role` - (Required) The role that should be applied. Only one + `google_iam_workload_identity_pool_iam_binding` can be used per role. Note that custom roles must be of the format + `[projects|organizations]/{parent-name}/roles/{role-name}`. + +* `policy_data` - (Required only by `google_iam_workload_identity_pool_iam_policy`) The policy data generated by + a `google_iam_policy` data source. + +* `condition` - (Optional) An [IAM Condition](https://cloud.google.com/iam/docs/conditions-overview) for a given binding. + Structure is documented below. + +--- + +The `condition` block supports: + +* `expression` - (Required) Textual representation of an expression in Common Expression Language syntax. + +* `title` - (Required) A title for the expression, i.e. a short string describing its purpose. + +* `description` - (Optional) An optional description of the expression. This is a longer text which describes the expression, e.g. when hovered over it in a UI. + +~> **Warning:** Terraform considers the `role` and condition contents (`title`+`description`+`expression`) as the + identifier for the binding. This means that if any part of the condition is changed out-of-band, Terraform will + consider it to be an entirely different resource and will treat it as such. +## Attributes Reference + +In addition to the arguments listed above, the following computed attributes are +exported: + +* `etag` - (Computed) The etag of the IAM policy. + +## Import + +For all import syntaxes, the "resource in question" can take any of the following forms: + +* projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}} +* {{project}}/{{workload_identity_pool_id}} +* {{workload_identity_pool_id}} + +Any variables not passed in the import command will be taken from the provider configuration. + +Cloud IAM workloadidentitypool IAM resources can be imported using the resource identifiers, role, and member. + +IAM member imports use space-delimited identifiers: the resource in question, the role, and the member identity, e.g. +``` +$ terraform import google_iam_workload_identity_pool_iam_member.editor "projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}} roles/iam.workloadIdentityPoolViewer user:jane@example.com" +``` + +IAM binding imports use space-delimited identifiers: the resource in question and the role, e.g. +``` +$ terraform import google_iam_workload_identity_pool_iam_binding.editor "projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}} roles/iam.workloadIdentityPoolViewer" +``` + +IAM policy imports use the identifier of the resource in question, e.g. +``` +$ terraform import google_iam_workload_identity_pool_iam_policy.editor projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}} +``` + +-> **Custom Roles** If you're importing a IAM resource with a custom role, make sure to use the + full name of the custom role, e.g. `[projects/my-project|organizations/my-org]/roles/my-custom-role`. + +## User Project Overrides + +This resource supports [User Project Overrides](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference#user_project_override).