From 3f040a119f63d1a4792a093801596499c2323ab6 Mon Sep 17 00:00:00 2001 From: bohengy <108434983+bohengy@users.noreply.github.com> Date: Mon, 28 Nov 2022 14:36:04 -0800 Subject: [PATCH] Add new resource WorkforcePoolProvider (#6810) * test * Empty entity bug fixed * First attempt * First attempt * completed adding workforce pool provider * fix bugs --- .ruby-version | 1 + mmv1/products/iamworkforcepool/api.yaml | 192 +++++++++++ mmv1/products/iamworkforcepool/terraform.yaml | 47 +++ .../iam_workforce_pool_provider.go.erb | 18 ++ .../iam_workforce_pool.go.erb | 2 +- ..._workforce_pool_provider_oidc_basic.tf.erb | 22 ++ ...m_workforce_pool_provider_oidc_full.tf.erb | 26 ++ ..._workforce_pool_provider_saml_basic.tf.erb | 21 ++ ...m_workforce_pool_provider_saml_full.tf.erb | 25 ++ ...ool_workforce_pool_provider_id_test.go.erb | 35 +++ ...e_pool_workforce_pool_provider_test.go.erb | 297 ++++++++++++++++++ 11 files changed, 685 insertions(+), 1 deletion(-) create mode 100644 .ruby-version create mode 100644 mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb create mode 100644 mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb create mode 100644 mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb create mode 100644 mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 000000000000..e70b4523ae7f --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.6.0 diff --git a/mmv1/products/iamworkforcepool/api.yaml b/mmv1/products/iamworkforcepool/api.yaml index a278c7a5c487..ec1978ce96b2 100644 --- a/mmv1/products/iamworkforcepool/api.yaml +++ b/mmv1/products/iamworkforcepool/api.yaml @@ -126,3 +126,195 @@ objects: If `sessionDuration` is not configured, minted credentials have a default duration of one hour (3600s). A duration in seconds with up to nine fractional digits, ending with '`s`'. Example: "`3.5s`". default_value: '3600s' + - !ruby/object:Api::Resource + name: 'WorkforcePoolProvider' + base_url: locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers + self_link: locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers/{{provider_id}} + create_url: locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers?workforcePoolProviderId={{provider_id}} + update_verb: :PATCH + update_mask: true + min_version: beta + description: | + A configuration for an external identity provider. + ~> **Note:** Ask your Google Cloud account team to request access to workforce identity + federation for your billing/quota project. The account team notifies you when the project is + granted access. + references: !ruby/object:Api::Resource::ReferenceLinks + guides: + 'Configure a provider within the workforce pool': + 'https://cloud.google.com/iam/docs/manage-workforce-identity-pools-providers#configure_a_provider_within_the_workforce_pool' + api: 'https://cloud.google.com/iam/docs/reference/rest/v1/locations.workforcePools.providers' + properties: + - !ruby/object:Api::Type::String + name: 'location' + description: The location for the resource. + required: true + input: true + url_param_only: true + - !ruby/object:Api::Type::String + name: 'workforcePoolId' + description: | + The ID to use for the pool, which becomes the final component of the resource name. + The IDs must be a globally unique string of 6 to 63 lowercase letters, digits, or hyphens. + It must start with a letter, and cannot have a trailing hyphen. + The prefix `gcp-` is reserved for use by Google, and may not be specified. + required: true + input: true + url_param_only: true + - !ruby/object:Api::Type::String + name: 'providerId' + description: | + The ID for the provider, which becomes the final component of the resource name. + This value must be 4-32 characters, and may contain the characters [a-z0-9-]. + The prefix `gcp-` is reserved for use by Google, and may not be specified. + required: true + input: true + url_param_only: true + - !ruby/object:Api::Type::String + name: 'name' + description: | + Output only. The resource name of the provider. + Format: `locations/{location}/workforcePools/{workforcePoolId}/providers/{providerId}` + output: true + - !ruby/object:Api::Type::String + name: 'displayName' + description: A user-specified display name for the provider. Cannot exceed 32 characters. + - !ruby/object:Api::Type::String + name: 'description' + description: A user-specified description of the provider. Cannot exceed 256 characters. + - !ruby/object:Api::Type::Enum + name: 'state' + description: | + The current state of the provider. + * STATE_UNSPECIFIED: State unspecified. + * ACTIVE: The provider is active and may be used to validate authentication credentials. + * DELETED: The provider is soft-deleted. Soft-deleted providers are permanently + deleted after approximately 30 days. You can restore a soft-deleted provider using + [providers.undelete](https://cloud.google.com/iam/docs/reference/rest/v1/locations.workforcePools.providers/undelete#google.iam.admin.v1.WorkforcePools.UndeleteWorkforcePoolProvider). + output: true + values: + - :STATE_UNSPECIFIED + - :ACTIVE + - :DELETED + - !ruby/object:Api::Type::Boolean + name: 'disabled' + description: | + Whether the provider is disabled. You cannot use a disabled provider to exchange tokens. + However, existing tokens still grant access. + - !ruby/object:Api::Type::KeyValuePairs + name: 'attributeMapping' + description: | + Maps attributes from the authentication credentials issued by an external identity provider + to Google Cloud attributes, such as `subject` and `segment`. + + Each key must be a string specifying the Google Cloud IAM attribute to map to. + + The following keys are supported: + * `google.subject`: The principal IAM is authenticating. You can reference this value in IAM bindings. + This is also the subject that appears in Cloud Logging logs. This is a required field and + the mapped subject cannot exceed 127 bytes. + * `google.groups`: Groups the authenticating user belongs to. You can grant groups access to + resources using an IAM `principalSet` binding; access applies to all members of the group. + * `google.display_name`: The name of the authenticated user. This is an optional field and + the mapped display name cannot exceed 100 bytes. If not set, `google.subject` will be displayed instead. + This attribute cannot be referenced in IAM bindings. + * `google.profile_photo`: The URL that specifies the authenticated user's thumbnail photo. + This is an optional field. When set, the image will be visible as the user's profile picture. + If not set, a generic user icon will be displayed instead. + This attribute cannot be referenced in IAM bindings. + + You can also provide custom attributes by specifying `attribute.{custom_attribute}`, where {custom_attribute} + is the name of the custom attribute to be mapped. You can define a maximum of 50 custom attributes. + The maximum length of a mapped attribute key is 100 characters, and the key may only contain the characters [a-z0-9_]. + + You can reference these attributes in IAM policies to define fine-grained access for a workforce pool + to Google Cloud resources. For example: + * `google.subject`: + `principal://iam.googleapis.com/locations/{location}/workforcePools/{pool}/subject/{value}` + * `google.groups`: + `principalSet://iam.googleapis.com/locations/{location}/workforcePools/{pool}/group/{value}` + * `attribute.{custom_attribute}`: + `principalSet://iam.googleapis.com/locations/{location}/workforcePools/{pool}/attribute.{custom_attribute}/{value}` + + Each value must be a [Common Expression Language](https://opensource.google/projects/cel) + function that maps an identity provider credential to the normalized attribute specified + by the corresponding map key. + + You can use the `assertion` keyword in the expression to access a JSON representation of + the authentication credential issued by the provider. + + The maximum length of an attribute mapping expression is 2048 characters. When evaluated, + the total size of all mapped attributes must not exceed 8KB. + + For OIDC providers, you must supply a custom mapping that includes the `google.subject` attribute. + For example, the following maps the sub claim of the incoming credential to the `subject` attribute + on a Google token: + ``` + {"google.subject": "assertion.sub"} + ``` + + An object containing a list of `"key": value` pairs. + Example: `{ "name": "wrench", "mass": "1.3kg", "count": "3" }`. + - !ruby/object:Api::Type::String + name: 'attributeCondition' + description: | + A [Common Expression Language](https://opensource.google/projects/cel) expression, in + plain text, to restrict what otherwise valid authentication credentials issued by the + provider should not be accepted. + + The expression must output a boolean representing whether to allow the federation. + + The following keywords may be referenced in the expressions: + * `assertion`: JSON representing the authentication credential issued by the provider. + * `google`: The Google attributes mapped from the assertion in the `attribute_mappings`. + `google.profile_photo` and `google.display_name` are not supported. + * `attribute`: The custom attributes mapped from the assertion in the `attribute_mappings`. + + The maximum length of the attribute condition expression is 4096 characters. + If unspecified, all valid authentication credentials will be accepted. + + The following example shows how to only allow credentials with a mapped `google.groups` value of `admins`: + ``` + "'admins' in google.groups" + ``` + - !ruby/object:Api::Type::NestedObject + name: 'saml' + description: Represents a SAML identity provider. + exactly_one_of: + - saml + - oidc + properties: + - !ruby/object:Api::Type::String + name: idpMetadataXml + description: | + SAML Identity provider configuration metadata xml doc. + The xml document should comply with [SAML 2.0 specification](https://docs.oasis-open.org/security/saml/v2.0/saml-metadata-2.0-os.pdf). + The max size of the acceptable xml document will be bounded to 128k characters. + + The metadata xml document should satisfy the following constraints: + 1) Must contain an Identity Provider Entity ID. + 2) Must contain at least one non-expired signing key certificate. + 3) For each signing key: + a) Valid from should be no more than 7 days from now. + b) Valid to should be no more than 10 years in the future. + 4) Up to 3 IdP signing keys are allowed in the metadata xml. + + When updating the provider's metadata xml, at least one non-expired signing key + must overlap with the existing metadata. This requirement is skipped if there are + no non-expired signing keys present in the existing metadata. + required: true + - !ruby/object:Api::Type::NestedObject + name: 'oidc' + description: Represents an OpenId Connect 1.0 identity provider. + exactly_one_of: + - saml + - oidc + properties: + - !ruby/object:Api::Type::String + name: issuerUri + description: The OIDC issuer URI. Must be a valid URI using the 'https' scheme. + required: true + - !ruby/object:Api::Type::String + name: clientId + description: The client ID. Must match the audience claim of the JWT issued by the identity provider. + required: true diff --git a/mmv1/products/iamworkforcepool/terraform.yaml b/mmv1/products/iamworkforcepool/terraform.yaml index 6a1abb8d71b3..4a6c4b261cce 100644 --- a/mmv1/products/iamworkforcepool/terraform.yaml +++ b/mmv1/products/iamworkforcepool/terraform.yaml @@ -42,6 +42,53 @@ overrides: !ruby/object:Overrides::ResourceOverrides workforcePoolId: !ruby/object:Overrides::Terraform::PropertyOverride validation: !ruby/object:Provider::Terraform::Validation function: 'validateWorkforcePoolId' + WorkforcePoolProvider: !ruby/object:Overrides::Terraform::ResourceOverride + autogen_async: true + import_format: ["locations/{{location}}/workforcePools/{{workforce_pool_id}}/providers/{{provider_id}}"] + examples: + - !ruby/object:Provider::Terraform::Examples + name: "iam_workforce_pool_provider_saml_basic" + min_version: beta + primary_resource_id: "example" + vars: + workforce_pool_id: "example-pool" + provider_id: "example-prvdr" + test_env_vars: + org_id: :ORG_ID + - !ruby/object:Provider::Terraform::Examples + name: "iam_workforce_pool_provider_saml_full" + min_version: beta + primary_resource_id: "example" + vars: + workforce_pool_id: "example-pool" + provider_id: "example-prvdr" + test_env_vars: + org_id: :ORG_ID + - !ruby/object:Provider::Terraform::Examples + name: "iam_workforce_pool_provider_oidc_basic" + min_version: beta + primary_resource_id: "example" + vars: + workforce_pool_id: "example-pool" + provider_id: "example-prvdr" + test_env_vars: + org_id: :ORG_ID + - !ruby/object:Provider::Terraform::Examples + name: "iam_workforce_pool_provider_oidc_full" + min_version: beta + primary_resource_id: "example" + vars: + workforce_pool_id: "example-pool" + provider_id: "example-prvdr" + test_env_vars: + org_id: :ORG_ID + custom_code: !ruby/object:Provider::Terraform::CustomCode + constants: templates/terraform/constants/iam_workforce_pool_provider.go.erb + decoder: templates/terraform/decoders/treat_deleted_state_as_gone.go.erb + properties: + providerId: !ruby/object:Overrides::Terraform::PropertyOverride + validation: !ruby/object:Provider::Terraform::Validation + function: 'validateWorkforcePoolProviderId' # This is for copying files over files: !ruby/object:Provider::Config::Files # These files have templating (ERB) code that will be run. diff --git a/mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb b/mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb new file mode 100644 index 000000000000..90d5bb40fa0b --- /dev/null +++ b/mmv1/templates/terraform/constants/iam_workforce_pool_provider.go.erb @@ -0,0 +1,18 @@ +const workforcePoolProviderIdRegexp = `^[a-z0-9-]{4,32}$` + +func validateWorkforcePoolProviderId(v interface{}, k string) (ws []string, errors []error) { + value := v.(string) + + if strings.HasPrefix(value, "gcp-") { + errors = append(errors, fmt.Errorf( + "%q \"%q\" can not start with \"gcp-\". " + + "The prefix `gcp-` is reserved for use by Google, and may not be specified.", k, value)) + } + + if !regexp.MustCompile(workforcePoolProviderIdRegexp).MatchString(value) { + errors = append(errors, fmt.Errorf( + "Workforce Pool Provider Id \"%q\" must be 4-32 characters, and may contain the characters [a-z0-9-].", value)) + } + + return +} diff --git a/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb b/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb index bd8df83df5b2..f371936e9462 100644 --- a/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb +++ b/mmv1/templates/terraform/custom_check_destroy/iam_workforce_pool.go.erb @@ -1,6 +1,6 @@ config := googleProviderConfig(t) -url, err := replaceVarsForTest(config, rs, "{{IAMBetaBasePath}}locations/{{location}}/workforcePools/{{workforce_pool_id}}") +url, err := replaceVarsForTest(config, rs, "{{IAMWorkforcePoolBasePath}}locations/{{location}}/workforcePools/{{workforce_pool_id}}") if err != nil { return err } diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb new file mode 100644 index 000000000000..72cdae69a79a --- /dev/null +++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_basic.tf.erb @@ -0,0 +1,22 @@ +resource "google_iam_workforce_pool" "pool" { + provider = google-beta + + workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>" + parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id + location = google_iam_workforce_pool.pool.location + provider_id = "<%= ctx[:vars]["provider_id"] %>" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + oidc { + issuer_uri = "https://accounts.google.com" + client_id = "client-id" + } +} diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb new file mode 100644 index 000000000000..6ff38b004534 --- /dev/null +++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_oidc_full.tf.erb @@ -0,0 +1,26 @@ +resource "google_iam_workforce_pool" "pool" { + provider = google-beta + + workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>" + parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id + location = google_iam_workforce_pool.pool.location + provider_id = "<%= ctx[:vars]["provider_id"] %>" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + oidc { + issuer_uri = "https://accounts.google.com" + client_id = "client-id" + } + display_name = "Display name" + description = "A sample OIDC workforce pool provider." + disabled = false + attribute_condition = "true" +} diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb new file mode 100644 index 000000000000..c8853aea29ed --- /dev/null +++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_basic.tf.erb @@ -0,0 +1,21 @@ +resource "google_iam_workforce_pool" "pool" { + provider = google-beta + + workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>" + parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id + location = google_iam_workforce_pool.pool.location + provider_id = "<%= ctx[:vars]["provider_id"] %>" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + saml { + idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv" + } +} diff --git a/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb new file mode 100644 index 000000000000..724f895c994d --- /dev/null +++ b/mmv1/templates/terraform/examples/iam_workforce_pool_provider_saml_full.tf.erb @@ -0,0 +1,25 @@ +resource "google_iam_workforce_pool" "pool" { + provider = google-beta + + workforce_pool_id = "<%= ctx[:vars]["workforce_pool_id"] %>" + parent = "organizations/<%= ctx[:test_env_vars]["org_id"] %>" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + + workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id + location = google_iam_workforce_pool.pool.location + provider_id = "<%= ctx[:vars]["provider_id"] %>" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + saml { + idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv" + } + display_name = "Display name" + description = "A sample SAML workforce pool provider." + disabled = false + attribute_condition = "true" +} diff --git a/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb new file mode 100644 index 000000000000..e10391536ba3 --- /dev/null +++ b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_id_test.go.erb @@ -0,0 +1,35 @@ +<% autogen_exception -%> +package google + +<% unless version == 'ga' -%> + +import ( + "strings" + "testing" +) + +func TestValidateIAMWorkforcePoolWorkforcePoolProviderId(t *testing.T) { + x := []StringValidationTestCase{ + // No errors + {TestName: "with numbers", Value: "foobar123"}, + {TestName: "short", Value: "foo-"}, + {TestName: "long", Value: strings.Repeat("f", 32)}, + {TestName: "has a hyphen", Value: "foo-bar"}, + + // With errors + {TestName: "empty", Value: "", ExpectError: true}, + {TestName: "starts with a gcp-", Value: "gcp-foobar", ExpectError: true}, + {TestName: "with uppercase", Value: "fooBar", ExpectError: true}, + {TestName: "has an slash", Value: "foo/bar", ExpectError: true}, + {TestName: "has an backslash", Value: "foo\bar", ExpectError: true}, + {TestName: "too short", Value: "foo", ExpectError: true}, + {TestName: "too long", Value: strings.Repeat("f", 33), ExpectError: true}, + } + + es := testStringValidationCases(x, validateWorkforcePoolProviderId) + if len(es) > 0 { + t.Errorf("Failed to validate WorkforcePoolProvider names: %v", es) + } +} + +<% end -%> diff --git a/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb new file mode 100644 index 000000000000..4055dc45d6b5 --- /dev/null +++ b/mmv1/third_party/terraform/tests/resource_iam_workforce_pool_workforce_pool_provider_test.go.erb @@ -0,0 +1,297 @@ +<% autogen_exception -%> +package google + +<% unless version == 'ga' -%> + +import ( + "fmt" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "testing" +) + +func TestAccIAMWorkforcePoolWorkforcePoolProvider_oidc(t *testing.T) { + t.Parallel() + + random_suffix := randString(t, 10) + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": random_suffix, + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIAMWorkforcePoolWorkforcePoolDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_full(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.my_provider", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_update(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.my_provider", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_basic(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.my_provider", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_destroy(context), + Check: resource.ComposeTestCheckFunc( + testAccCheckIAMWorkforcePoolWorkforcePoolProviderAccess(t, random_suffix), + ), + }, + }, + }) +} + +func TestAccIAMWorkforcePoolWorkforcePoolProvider_saml(t *testing.T) { + t.Parallel() + + random_suffix := randString(t, 10) + context := map[string]interface{}{ + "org_id": getTestOrgFromEnv(t), + "random_suffix": random_suffix, + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckIAMWorkforcePoolWorkforcePoolDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_saml_full(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.my_provider", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_saml_update(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.my_provider", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_saml_basic(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.my_provider", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_destroy(context), + Check: resource.ComposeTestCheckFunc( + testAccCheckIAMWorkforcePoolWorkforcePoolProviderAccess(t, random_suffix), + ), + }, + }, + }) +} + +func testAccCheckIAMWorkforcePoolWorkforcePoolProviderAccess(t *testing.T, random_suffix string) resource.TestCheckFunc { + return func(s *terraform.State) error { + pool_resource_name := "google_iam_workforce_pool.my_pool" + pool_rs, ok := s.RootModule().Resources[pool_resource_name] + if !ok { + return fmt.Errorf("Resource %s Not found", pool_resource_name) + } + config := googleProviderConfig(t) + + pool_url, err := replaceVarsForTest(config, pool_rs, "{{IAMWorkforcePoolBasePath}}locations/{{location}}/workforcePools/{{workforce_pool_id}}") + if err != nil { + return err + } + + url := fmt.Sprintf("%s/providers/my-provider-%s", pool_url, random_suffix) + res, err := sendRequest(config, "GET", "", url, config.userAgent, nil) + if err != nil { + return nil + } + + if v := res["state"]; v == "DELETED" { + return nil + } + + return fmt.Errorf("IAMWorkforcePoolProvider still exists at %s", url) + } +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_full(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "my_provider" { + workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id + location = google_iam_workforce_pool.my_pool.location + provider_id = "my-provider-%{random_suffix}" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + oidc { + issuer_uri = "https://accounts.google.com" + client_id = "client-id" + } + display_name = "Display name" + description = "A sample OIDC workforce pool provider." + disabled = false + attribute_condition = "true" +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_update(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "my_provider" { + workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id + location = google_iam_workforce_pool.my_pool.location + provider_id = "my-provider-%{random_suffix}" + attribute_mapping = { + "google.subject" = "false" + } + oidc { + issuer_uri = "https://test.google.com" + client_id = "new-client-id" + } + display_name = "New Display name" + description = "A sample OIDC workforce pool provider with updated description." + disabled = true + attribute_condition = "false" +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_oidc_basic(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "my_provider" { + workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id + location = google_iam_workforce_pool.my_pool.location + provider_id = "my-provider-%{random_suffix}" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + oidc { + issuer_uri = "https://accounts.google.com" + client_id = "client-id" + } +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_saml_full(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "my_provider" { + workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id + location = google_iam_workforce_pool.my_pool.location + provider_id = "my-provider-%{random_suffix}" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + saml { + idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv" + } + display_name = "Display name" + description = "A sample SAML workforce pool provider." + disabled = false + attribute_condition = "true" +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_saml_update(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "my_provider" { + workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id + location = google_iam_workforce_pool.my_pool.location + provider_id = "my-provider-%{random_suffix}" + attribute_mapping = { + "google.subject": "false" + } + saml { + idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv" + } + display_name = "New Display name" + description = "A sample SAML workforce pool provider with updated description." + disabled = true + attribute_condition = "false" +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_saml_basic(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "my_provider" { + workforce_pool_id = google_iam_workforce_pool.my_pool.workforce_pool_id + location = google_iam_workforce_pool.my_pool.location + provider_id = "my-provider-%{random_suffix}" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + saml { + idp_metadata_xml = " MIIDpDCCAoygAwIBAgIGAX7/5qPhMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi00NTg0MjExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMjIwMjE2MDAxOTEyWhcNMzIwMjE2MDAyMDEyWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNDU4NDIxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxrBl7GKz52cRpxF9xCsirnRuMxnhFBaUrsHqAQrLqWmdlpNYZTVg+T9iQ+aq/iE68L+BRZcZniKIvW58wqqS0ltXVvIkXuDSvnvnkkI5yMIVErR20K8jSOKQm1FmK+fgAJ4koshFiu9oLiqu0Ejc0DuL3/XRsb4RuxjktKTb1khgBBtb+7idEk0sFR0RPefAweXImJkDHDm7SxjDwGJUubbqpdTxasPr0W+AHI1VUzsUsTiHAoyb0XDkYqHfDzhj/ZdIEl4zHQ3bEZvlD984ztAnmX2SuFLLKfXeAAGHei8MMixJvwxYkkPeYZ/5h8WgBZPP4heS2CPjwYExt29L8QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQARjJFz++a9Z5IQGFzsZMrX2EDR5ML4xxUiQkbhld1S1PljOLcYFARDmUC2YYHOueU4ee8Jid9nPGEUebV/4Jok+b+oQh+dWMgiWjSLI7h5q4OYZ3VJtdlVwgMFt2iz+/4yBKMUZ50g3Qgg36vE34us+eKitg759JgCNsibxn0qtJgSPm0sgP2L6yTaLnoEUbXBRxCwynTSkp9ZijZqEzbhN0e2dWv7Rx/nfpohpDP6vEiFImKFHpDSv3M/5de1ytQzPFrZBYt9WlzlYwE1aD9FHCxdd+rWgYMVVoRaRmndpV/Rq3QUuDuFJtaoX11bC7ExkOpg9KstZzA63i3VcfYv" + } +} +`, context) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_destroy(context map[string]interface{}) string { + return Nprintf(` +resource "google_iam_workforce_pool" "my_pool" { + workforce_pool_id = "my-pool-%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} +`, context) +} +<% end -%>