diff --git a/.changelog/9147.txt b/.changelog/9147.txt new file mode 100644 index 00000000000..0f003df7cc0 --- /dev/null +++ b/.changelog/9147.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +iamworkforcepool: promoted field `oidc.jwks_json` in resource `google_iam_workforce_pool` to GA +``` diff --git a/google/services/iamworkforcepool/resource_iam_workforce_pool_provider.go b/google/services/iamworkforcepool/resource_iam_workforce_pool_provider.go index 1d6ca705543..b8ac6ab0b5c 100644 --- a/google/services/iamworkforcepool/resource_iam_workforce_pool_provider.go +++ b/google/services/iamworkforcepool/resource_iam_workforce_pool_provider.go @@ -239,6 +239,33 @@ However, existing tokens still grant access.`, }, }, }, + "jwks_json": { + Type: schema.TypeString, + Optional: true, + Description: `OIDC JWKs in JSON String format. For details on definition of a +JWK, see https:tools.ietf.org/html/rfc7517. If not set, then we +use the 'jwks_uri' from the discovery document fetched from the +.well-known path for the 'issuer_uri'. Currently, RSA and EC asymmetric +keys are supported. The JWK must use following format and include only +the following fields: +''' +{ + "keys": [ + { + "kty": "RSA/EC", + "alg": "", + "use": "sig", + "kid": "", + "n": "", + "e": "", + "x": "", + "y": "", + "crv": "" + } + ] +} +'''`, + }, "web_sso_config": { Type: schema.TypeList, Computed: true, @@ -799,6 +826,8 @@ func flattenIAMWorkforcePoolWorkforcePoolProviderOidc(v interface{}, d *schema.R flattenIAMWorkforcePoolWorkforcePoolProviderOidcClientSecret(original["clientSecret"], d, config) transformed["web_sso_config"] = flattenIAMWorkforcePoolWorkforcePoolProviderOidcWebSsoConfig(original["webSsoConfig"], d, config) + transformed["jwks_json"] = + flattenIAMWorkforcePoolWorkforcePoolProviderOidcJwksJson(original["jwksJson"], d, config) return []interface{}{transformed} } func flattenIAMWorkforcePoolWorkforcePoolProviderOidcIssuerUri(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { @@ -869,6 +898,10 @@ func flattenIAMWorkforcePoolWorkforcePoolProviderOidcWebSsoConfigAdditionalScope return v } +func flattenIAMWorkforcePoolWorkforcePoolProviderOidcJwksJson(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandIAMWorkforcePoolWorkforcePoolProviderDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -956,6 +989,13 @@ func expandIAMWorkforcePoolWorkforcePoolProviderOidc(v interface{}, d tpgresourc transformed["webSsoConfig"] = transformedWebSsoConfig } + transformedJwksJson, err := expandIAMWorkforcePoolWorkforcePoolProviderOidcJwksJson(original["jwks_json"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedJwksJson); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["jwksJson"] = transformedJwksJson + } + return transformed, nil } @@ -1065,6 +1105,10 @@ func expandIAMWorkforcePoolWorkforcePoolProviderOidcWebSsoConfigAdditionalScopes return v, nil } +func expandIAMWorkforcePoolWorkforcePoolProviderOidcJwksJson(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + func resourceIAMWorkforcePoolWorkforcePoolProviderDecoder(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/services/iamworkforcepool/resource_iam_workforce_pool_provider_generated_test.go b/google/services/iamworkforcepool/resource_iam_workforce_pool_provider_generated_test.go index 731165b81f5..8459840b77b 100644 --- a/google/services/iamworkforcepool/resource_iam_workforce_pool_provider_generated_test.go +++ b/google/services/iamworkforcepool/resource_iam_workforce_pool_provider_generated_test.go @@ -252,6 +252,65 @@ resource "google_iam_workforce_pool_provider" "example" { `, context) } +func TestAccIAMWorkforcePoolWorkforcePoolProvider_iamWorkforcePoolProviderOidcUploadKeyExample(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "org_id": envvar.GetTestOrgFromEnv(t), + "random_suffix": acctest.RandString(t, 10), + } + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckIAMWorkforcePoolWorkforcePoolProviderDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMWorkforcePoolWorkforcePoolProvider_iamWorkforcePoolProviderOidcUploadKeyExample(context), + }, + { + ResourceName: "google_iam_workforce_pool_provider.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"location", "workforce_pool_id", "provider_id", "oidc.0.client_secret.0.value.0.plain_text"}, + }, + }, + }) +} + +func testAccIAMWorkforcePoolWorkforcePoolProvider_iamWorkforcePoolProviderOidcUploadKeyExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workforce_pool" "pool" { + workforce_pool_id = "tf-test-example-pool%{random_suffix}" + parent = "organizations/%{org_id}" + location = "global" +} + +resource "google_iam_workforce_pool_provider" "example" { + workforce_pool_id = google_iam_workforce_pool.pool.workforce_pool_id + location = google_iam_workforce_pool.pool.location + provider_id = "tf-test-example-prvdr%{random_suffix}" + attribute_mapping = { + "google.subject" = "assertion.sub" + } + oidc { + issuer_uri = "https://accounts.thirdparty.com" + client_id = "client-id" + client_secret { + value { + plain_text = "client-secret" + } + } + web_sso_config { + response_type = "ID_TOKEN" + assertion_claims_behavior = "ONLY_ID_TOKEN_CLAIMS" + } + jwks_json = "{\"keys\":[{\"kty\":\"RSA\",\"e\":\"AQAB\",\"use\":\"sig\",\"kid\":\"1i-PmZZrF1j2rOUAxkcQaaz3MnOXcwwziuch_XWjvqI\",\"alg\":\"RS256\",\"n\":\"kFpYE2Zm32y--cnUiFLm4cYmFO8tR4-5KU5-aqhRwiHPP0FkgdQZSoSyp_1DO6PruYfluRMviwOpbmM6LH7KemxVdxLKqLDkHSG0XC3dZkACRFNvBBOdFrvJ0ABXv3vVx592lFE0m-Je5-FerRSQCml6E7icNiTSxizEmvDsTIe8mvArjsODDrgWP25bEFwDPBd5cCl3_2gtW6YdaCRewLXdzuB5Wmp_vOu6trTUzEKbnQlWFtDDCPfOpywYXF8dY1Lbwas5iwwIZozwD2_CuTiyXa3T2_4oa119_rQrIC2BAv7q_S1Xoa2lk3q2GZUSVQ5i3gIbJuDHmp-6yh3k4w\"}]}" + } +} +`, context) +} + func testAccCheckIAMWorkforcePoolWorkforcePoolProviderDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/website/docs/r/iam_workforce_pool_provider.html.markdown b/website/docs/r/iam_workforce_pool_provider.html.markdown index cca67c0d177..6230e21c0d5 100644 --- a/website/docs/r/iam_workforce_pool_provider.html.markdown +++ b/website/docs/r/iam_workforce_pool_provider.html.markdown @@ -305,7 +305,7 @@ The following arguments are supported: Structure is [documented below](#nested_web_sso_config). * `jwks_json` - - (Optional, [Beta](https://terraform.io/docs/providers/google/guides/provider_versions.html)) + (Optional) OIDC JWKs in JSON String format. For details on definition of a JWK, see https:tools.ietf.org/html/rfc7517. If not set, then we use the `jwks_uri` from the discovery document fetched from the