diff --git a/.changelog/11493.txt b/.changelog/11493.txt new file mode 100644 index 0000000000..d962f8a55c --- /dev/null +++ b/.changelog/11493.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +iambeta: added `x509` field to `google_iam_workload_identity_pool_provider ` resource +``` \ No newline at end of file diff --git a/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider.go b/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider.go index 6ff0293a95..c478f99816 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider.go +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider.go @@ -202,7 +202,7 @@ For OIDC providers, the following rules apply: }, }, }, - ExactlyOneOf: []string{"aws", "oidc", "saml"}, + ExactlyOneOf: []string{"aws", "oidc", "saml", "x509"}, }, "description": { Type: schema.TypeString, @@ -280,7 +280,7 @@ the following fields: }, }, }, - ExactlyOneOf: []string{"aws", "oidc", "saml"}, + ExactlyOneOf: []string{"aws", "oidc", "saml", "x509"}, }, "saml": { Type: schema.TypeList, @@ -296,7 +296,67 @@ the following fields: }, }, }, - ExactlyOneOf: []string{"aws", "oidc", "saml"}, + ExactlyOneOf: []string{"aws", "oidc", "saml", "x509"}, + }, + "x509": { + Type: schema.TypeList, + Optional: true, + Description: `An X.509-type identity provider represents a CA. It is trusted to assert a +client identity if the client has a certificate that chains up to this CA.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "trust_store": { + Type: schema.TypeList, + Required: true, + Description: `A Trust store, use this trust store as a wrapper to config the trust +anchor and optional intermediate cas to help build the trust chain for +the incoming end entity certificate. Follow the x509 guidelines to +define those PEM encoded certs. Only 1 trust store is currently +supported.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "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, + Optional: true, + Description: `PEM certificate of the PKI used for validation. Must only contain one +ca certificate(either root or intermediate cert).`, + }, + }, + }, + }, + "intermediate_cas": { + Type: schema.TypeList, + Optional: true, + Description: `Set of intermediate CA certificates used for building the trust chain to +trust anchor. +IMPORTANT: Intermediate CAs are only supported when configuring x509 federation.`, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "pem_certificate": { + Type: schema.TypeString, + Optional: true, + Description: `PEM certificate of the PKI used for validation. Must only contain one +ca certificate(either root or intermediate cert).`, + }, + }, + }, + }, + }, + }, + }, + }, + }, + ExactlyOneOf: []string{"aws", "oidc", "saml", "x509"}, }, "name": { Type: schema.TypeString, @@ -382,6 +442,12 @@ func resourceIAMBetaWorkloadIdentityPoolProviderCreate(d *schema.ResourceData, m } else if v, ok := d.GetOkExists("saml"); !tpgresource.IsEmptyValue(reflect.ValueOf(samlProp)) && (ok || !reflect.DeepEqual(v, samlProp)) { obj["saml"] = samlProp } + x509Prop, err := expandIAMBetaWorkloadIdentityPoolProviderX509(d.Get("x509"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("x509"); !tpgresource.IsEmptyValue(reflect.ValueOf(x509Prop)) && (ok || !reflect.DeepEqual(v, x509Prop)) { + obj["x509"] = x509Prop + } url, err := tpgresource.ReplaceVars(d, config, "{{IAMBetaBasePath}}projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}}/providers?workloadIdentityPoolProviderId={{workload_identity_pool_provider_id}}") if err != nil { @@ -523,6 +589,9 @@ func resourceIAMBetaWorkloadIdentityPoolProviderRead(d *schema.ResourceData, met if err := d.Set("saml", flattenIAMBetaWorkloadIdentityPoolProviderSaml(res["saml"], d, config)); err != nil { return fmt.Errorf("Error reading WorkloadIdentityPoolProvider: %s", err) } + if err := d.Set("x509", flattenIAMBetaWorkloadIdentityPoolProviderX509(res["x509"], d, config)); err != nil { + return fmt.Errorf("Error reading WorkloadIdentityPoolProvider: %s", err) + } return nil } @@ -591,6 +660,12 @@ func resourceIAMBetaWorkloadIdentityPoolProviderUpdate(d *schema.ResourceData, m } else if v, ok := d.GetOkExists("saml"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, samlProp)) { obj["saml"] = samlProp } + x509Prop, err := expandIAMBetaWorkloadIdentityPoolProviderX509(d.Get("x509"), d, config) + if err != nil { + return err + } else if v, ok := d.GetOkExists("x509"); !tpgresource.IsEmptyValue(reflect.ValueOf(v)) && (ok || !reflect.DeepEqual(v, x509Prop)) { + obj["x509"] = x509Prop + } url, err := tpgresource.ReplaceVars(d, config, "{{IAMBetaBasePath}}projects/{{project}}/locations/global/workloadIdentityPools/{{workload_identity_pool_id}}/providers/{{workload_identity_pool_provider_id}}") if err != nil { @@ -634,6 +709,10 @@ func resourceIAMBetaWorkloadIdentityPoolProviderUpdate(d *schema.ResourceData, m if d.HasChange("saml") { updateMask = append(updateMask, "saml") } + + if d.HasChange("x509") { + updateMask = append(updateMask, "x509") + } // 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, ",")}) @@ -844,6 +923,78 @@ func flattenIAMBetaWorkloadIdentityPoolProviderSamlIdpMetadataXml(v interface{}, return v } +func flattenIAMBetaWorkloadIdentityPoolProviderX509(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["trust_store"] = + flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStore(original["trustStore"], d, config) + return []interface{}{transformed} +} +func flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStore(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["trust_anchors"] = + flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchors(original["trustAnchors"], d, config) + transformed["intermediate_cas"] = + flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCas(original["intermediateCas"], d, config) + return []interface{}{transformed} +} +func flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchors(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": flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchorsPemCertificate(original["pemCertificate"], d, config), + }) + } + return transformed +} +func flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchorsPemCertificate(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + +func flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCas(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": flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCasPemCertificate(original["pemCertificate"], d, config), + }) + } + return transformed +} +func flattenIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCasPemCertificate(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} { + return v +} + func expandIAMBetaWorkloadIdentityPoolProviderDisplayName(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { return v, nil } @@ -962,6 +1113,103 @@ func expandIAMBetaWorkloadIdentityPoolProviderSamlIdpMetadataXml(v interface{}, return v, nil } +func expandIAMBetaWorkloadIdentityPoolProviderX509(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{}) + + transformedTrustStore, err := expandIAMBetaWorkloadIdentityPoolProviderX509TrustStore(original["trust_store"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedTrustStore); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["trustStore"] = transformedTrustStore + } + + return transformed, nil +} + +func expandIAMBetaWorkloadIdentityPoolProviderX509TrustStore(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{}) + + transformedTrustAnchors, err := expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchors(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 + } + + transformedIntermediateCas, err := expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCas(original["intermediate_cas"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedIntermediateCas); val.IsValid() && !tpgresource.IsEmptyValue(val) { + transformed["intermediateCas"] = transformedIntermediateCas + } + + return transformed, nil +} + +func expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchors(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 := expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchorsPemCertificate(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 expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreTrustAnchorsPemCertificate(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + +func expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCas(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 := expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCasPemCertificate(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 expandIAMBetaWorkloadIdentityPoolProviderX509TrustStoreIntermediateCasPemCertificate(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) { + return v, nil +} + func resourceIAMBetaWorkloadIdentityPoolProviderDecoder(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_provider_generated_test.go b/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_generated_test.go index 4d941ceffd..be01dae62b 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_generated_test.go +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_generated_test.go @@ -373,6 +373,108 @@ EOT `, context) } +func TestAccIAMBetaWorkloadIdentityPoolProvider_iamWorkloadIdentityPoolProviderX509BasicExample(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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckIAMBetaWorkloadIdentityPoolProviderDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolProvider_iamWorkloadIdentityPoolProviderX509BasicExample(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_provider.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workload_identity_pool_id", "workload_identity_pool_provider_id"}, + }, + }, + }) +} + +func testAccIAMBetaWorkloadIdentityPoolProvider_iamWorkloadIdentityPoolProviderX509BasicExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "pool" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_provider" "example" { + workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id + workload_identity_pool_provider_id = "tf-test-example-prvdr%{random_suffix}" + attribute_mapping = { + "google.subject" = "assertion.subject.dn.cn" + } + x509 { + trust_store { + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor.pem") + } + } + } +} +`, context) +} + +func TestAccIAMBetaWorkloadIdentityPoolProvider_iamWorkloadIdentityPoolProviderX509FullExample(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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckIAMBetaWorkloadIdentityPoolProviderDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolProvider_iamWorkloadIdentityPoolProviderX509FullExample(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_provider.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workload_identity_pool_id", "workload_identity_pool_provider_id"}, + }, + }, + }) +} + +func testAccIAMBetaWorkloadIdentityPoolProvider_iamWorkloadIdentityPoolProviderX509FullExample(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "pool" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_provider" "example" { + workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id + workload_identity_pool_provider_id = "tf-test-example-prvdr%{random_suffix}" + display_name = "Name of provider" + description = "X.509 identity pool provider for automated test" + disabled = true + attribute_mapping = { + "google.subject" = "assertion.subject.dn.cn" + } + x509 { + trust_store { + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor.pem") + } + intermediate_cas { + pem_certificate = file("test-fixtures/intermediate_ca.pem") + } + } + } +} +`, context) +} + func testAccCheckIAMBetaWorkloadIdentityPoolProviderDestroyProducer(t *testing.T) func(s *terraform.State) error { return func(s *terraform.State) error { for name, rs := range s.RootModule().Resources { diff --git a/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_test.go b/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_test.go index 4809383c46..96b75315ea 100644 --- a/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_test.go +++ b/google-beta/services/iambeta/resource_iam_workload_identity_pool_provider_test.go @@ -239,3 +239,95 @@ resource "google_iam_workload_identity_pool_provider" "my_provider" { } `, context) } + +func TestAccIAMBetaWorkloadIdentityPoolProvider_x509(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.ProtoV5ProviderFactories(t), + CheckDestroy: testAccCheckIAMBetaWorkloadIdentityPoolProviderDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccIAMBetaWorkloadIdentityPoolProvider_x509_full(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_provider.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workload_identity_pool_id", "workload_identity_pool_provider_id"}, + }, + { + Config: testAccIAMBetaWorkloadIdentityPoolProvider_x509_update(context), + }, + { + ResourceName: "google_iam_workload_identity_pool_provider.example", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"workload_identity_pool_id", "workload_identity_pool_provider_id"}, + }, + }, + }) +} + +func testAccIAMBetaWorkloadIdentityPoolProvider_x509_full(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "pool" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_provider" "example" { + workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id + workload_identity_pool_provider_id = "tf-test-example-prvdr%{random_suffix}" + display_name = "Name of provider" + description = "X.509 identity pool provider for automated test" + disabled = true + attribute_mapping = { + "google.subject" = "assertion.subject.dn.cn" + } + x509 { + trust_store { + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor.pem") + } + intermediate_cas { + pem_certificate = file("test-fixtures/intermediate_ca.pem") + } + } + } +} +`, context) +} + +func testAccIAMBetaWorkloadIdentityPoolProvider_x509_update(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_iam_workload_identity_pool" "pool" { + workload_identity_pool_id = "tf-test-example-pool%{random_suffix}" +} + +resource "google_iam_workload_identity_pool_provider" "example" { + workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id + workload_identity_pool_provider_id = "tf-test-example-prvdr%{random_suffix}" + display_name = "Name of provider" + description = "X.509 identity pool provider for automated test" + disabled = true + attribute_mapping = { + "google.subject" = "assertion.subject.dn.cn" + } + x509 { + trust_store { + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor_updated.pem") + } + trust_anchors { + pem_certificate = file("test-fixtures/intermediate_ca.pem") + } + } + } +} +`, context) +} diff --git a/google-beta/services/iambeta/test-fixtures/intermediate_ca.pem b/google-beta/services/iambeta/test-fixtures/intermediate_ca.pem new file mode 100644 index 0000000000..e6c091b0c0 --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/intermediate_ca.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIDvjCCAqagAwIBAgIIXHIdYNfGCLMwDQYJKoZIhvcNAQELBQAwXDEXMBUGA1UEChMOR29vZ2xlIFRFU1RJTkcxHDAaBgNVBAsTE0dvb2dsZSBURVNUSU5HIHVuaXQxIzAhBgNVBAMMGkdvb2dsZSAqKlRlc3RpbmcqKiBSb290IENBMCAXDTIwMDEwMTAwMDAwMFoYDzIxMzAwMTAxMDAwMDAwWjBkMRcwFQYDVQQKEw5Hb29nbGUgVEVTVElORzEcMBoGA1UECxMTR29vZ2xlIFRFU1RJTkcgdW5pdDErMCkGA1UEAwwiR29vZ2xlICoqVGVzdGluZyoqIEludGVybWVkaWF0ZSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALVSyoOVAMfOYf10VxNwmRs/afgbkYJ5gPXzn3aetEtFrcqDiG8LdgniLhHcp3c/O1U0EKANMLWyMlHP0KC4wjMrYXS8doQ7B6kGXj070hRSHN7acF0ImSRw3i9idiiSgOIJzlbYXeh8NLqDAYESyWFht7RRdbCJx1v2U9T8F5QVeT96Dw3exSKQAIdL2J8ol9kgJNINimd7GxOQ3f1+vDOBiAtAj4zWCjjqdNqh5ivyrTu28J/umM35wtHS6iX6GvnwqTsRy8zS/KeN+Dq6PEk/j04mrOG3w82SFp+IvTNH6S/DxRyiE5yoAfgfunKotV34JVr/INH2RsEgbWtwK5ECAwEAAaN6MHgwDgYDVR0PAQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMBAf8EBTADAQH/MBkGA1UdDgQSBBB0QukRw23faHpDoa0xl+L+MBsGA1UdIwQUMBKAEMRB36Doz2ZXloHKRyZ8hN0wDQYJKoZIhvcNAQELBQADggEBAIPBiuirnZbv4JWDiAIXvCE5pbwej0aKFWEDV2Z8lY0RFPt1CXrDJJL91MXHZ1yviUSJINJErJn7wyGV2bm/N7DUpRE0g9IMgEank64UUl+OyQTXd0LIsjlqWA6Sj/hDZUdw6mi9a98ENUr6CiECtOxpGF9kj4G4WcnyvPP/phs1b8cAfQ+tPurrDRBAdeoQIj756QL7fvMijKNdG5KeCURu9L4BZmCeuy/3v2C2XjiFZHx4cZDOHJizrx04GqzV5PSXw5OYZiXfn5WPGMsyh7ufkQJKJcpv2t3M0gyc1omD0xWkxCl4dTdVef9HrboJnZkUrma509fpVL6F8I2Jkt8= +-----END CERTIFICATE----- \ No newline at end of file diff --git a/google-beta/services/iambeta/test-fixtures/trust_anchor.pem b/google-beta/services/iambeta/test-fixtures/trust_anchor.pem new file mode 100644 index 0000000000..76d69c7b08 --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/trust_anchor.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIIMu9pvsFWIUcwDQYJKoZIhvcNAQELBQAwXDEXMBUGA1UEChMOR29vZ2xlIFRFU1RJTkcxHDAaBgNVBAsTE0dvb2dsZSBURVNUSU5HIHVuaXQxIzAhBgNVBAMMGkdvb2dsZSAqKlRlc3RpbmcqKiBSb290IENBMCAXDTIwMDEwMTAwMDAwMFoYDzIxMzAwMTAxMDAwMDAwWjBcMRcwFQYDVQQKEw5Hb29nbGUgVEVTVElORzEcMBoGA1UECxMTR29vZ2xlIFRFU1RJTkcgdW5pdDEjMCEGA1UEAwwaR29vZ2xlICoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHqdf17AA4iwl+HGtTD/qJJv9XZTjzjHiaRYWuGQ3iddf1LhYklLqHvpqOCBlhkg6NIZmoDPKicEi8pfGSzp6btcElyrr1ekECk5jEBcdl6tX/gTSYv7v1h9DkSJDHBAnoSsVW0/PNwI+YGEE2kizGMeg1moXlTHEB+yeGCik/+4eVRas/+wrlrTE5lMFMq8WhdnBx6udcc/BEauvlTybHaN3rJUVpVrJWeVoPGGtXR6MJrdbVScn9GYOLP6sXMPTr+pTY6ebrjs7K/wTVQqLJ1zArCvAEH8FvuAhiI19yM1uBRAds/fJbSUvFsEiIlDC4y7DAK7yWHUAjQIBV1xhDAgMBAAGjejB4MA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQxEHfoOjPZleWgcpHJnyE3TAbBgNVHSMEFDASgBDEQd+g6M9mV5aBykcmfITdMA0GCSqGSIb3DQEBCwUAA4IBAQBcECwxgaK4ZgYO7guayK5QRpTb3Y6zpkmSOkj9h1+HF5Ch/o5FiweJi8k28h9Mfz//gKU2cXXWfXuY81CFEBstjw7jYt3+d4owS5sYKu5WswGj4jsQXRrt0tO0+0UngP560eggFCyLChG75lp54r92hTPk4fY4varURZH7X0jg9W7MO6E6/HmKdMIxanuWdkbpPe6kj5I7SNvVhqsncoga8iZJ6QK/rsC2LTax4dxUUSkP5vmwwiYbgXYbk9JcXI+OyVcMvVxN/akI9/JgYHOol6NdChTBwU0yjNb9B5TrgtP1/fs+LugINrN1R1hgVHDVlE4mwHej+5XL6m9xAxkc +-----END CERTIFICATE----- \ No newline at end of file diff --git a/google-beta/services/iambeta/test-fixtures/trust_anchor_updated.pem b/google-beta/services/iambeta/test-fixtures/trust_anchor_updated.pem new file mode 100644 index 0000000000..ad85340983 --- /dev/null +++ b/google-beta/services/iambeta/test-fixtures/trust_anchor_updated.pem @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIJAJbcoF4dvsxvMA0GCSqGSIb3DQEBCwUAMFwxFzAVBgNVBAoTDkdvb2dsZSBURVNUSU5HMRwwGgYDVQQLExNHb29nbGUgVEVTVElORyB1bml0MSMwIQYDVQQDDBpHb29nbGUgKipUZXN0aW5nKiogUm9vdCBDQTAgFw0yMDAxMDEwMDAwMDBaGA8yMTMwMDEwMTAwMDAwMFowXDEXMBUGA1UEChMOR29vZ2xlIFRFU1RJTkcxHDAaBgNVBAsTE0dvb2dsZSBURVNUSU5HIHVuaXQxIzAhBgNVBAMMGkdvb2dsZSAqKlRlc3RpbmcqKiBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzVxH5w07E7O649oZHElZEyMGpYW1rS/yU58AYp9UgDjgNZchDCByn96uUdKiwzQRyFg+Nu/DifcpKbB8rzQtJoDqqpdPqmd2uxw13UNGeScsFGFoqIdOeU/l+SCAB1GvNHpMNoeFFzH9Ly1fFWRHXa/Upw1WYtKxMKM8pVLqodowTKuVMQHVMpVILhb1nlpZvsFR5i2LhG1U4jxVOVGC7OHTsUHNlFo547kM5MNnArl6vPx2LOZgA+2JeOM0zbiMk4DK+ks5eaXXapy5QMQ16PUIlq1oTgAYMRXk31TrmdMwu79FeIz3vHXgJnGhdmLqse3rE05cWuoEsuao01NpYwIDAQABo3oweDAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIEEMRB36Doz2ZXloHKRyZ8hN0wGwYDVR0jBBQwEoAQxEHfoOjPZleWgcpHJnyE3TANBgkqhkiG9w0BAQsFAAOCAQEAiim4OoNHHskwK1etk1Xswb+pB1OweUFD9iSHvkgnTw+RLuep+OYsKciz5GeZIWiKkWZMnJYTd41bX29fdIdcd1b3MjFVQ8jqKVkblb1NjYWLIwZshimtbIEZTDb/sxalQiwSH/SE2fi/8E8P8jxbntCeOyDw1/lce3tkYrJHlTNDZLNnr5Od+stpYi8EaPSnilEgLIMTsBwyaxUp8yWbxT8+M0JhJYmpHnSkC0vc2aLTYmgyv7URl14XIK2aumSISAuaCXYGj0hx8Wz0YNn1uydnZw7kmzn4ncZqfwoJuHJl/5kWq0nycgcieUNg65VxEhqHTnC6NXKjyBZKVXQaxQ== +-----END CERTIFICATE----- \ No newline at end of file diff --git a/website/docs/r/iam_workload_identity_pool_provider.html.markdown b/website/docs/r/iam_workload_identity_pool_provider.html.markdown index 7f9c7b4159..48a31dcf73 100644 --- a/website/docs/r/iam_workload_identity_pool_provider.html.markdown +++ b/website/docs/r/iam_workload_identity_pool_provider.html.markdown @@ -231,6 +231,68 @@ EOT } } ``` +
+ + Open in Cloud Shell + +
+## Example Usage - Iam Workload Identity Pool Provider X509 Basic + + +```hcl +resource "google_iam_workload_identity_pool" "pool" { + workload_identity_pool_id = "example-pool" +} + +resource "google_iam_workload_identity_pool_provider" "example" { + workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id + workload_identity_pool_provider_id = "example-prvdr" + attribute_mapping = { + "google.subject" = "assertion.subject.dn.cn" + } + x509 { + trust_store { + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor.pem") + } + } + } +} +``` +
+ + Open in Cloud Shell + +
+## Example Usage - Iam Workload Identity Pool Provider X509 Full + + +```hcl +resource "google_iam_workload_identity_pool" "pool" { + workload_identity_pool_id = "example-pool" +} + +resource "google_iam_workload_identity_pool_provider" "example" { + workload_identity_pool_id = google_iam_workload_identity_pool.pool.workload_identity_pool_id + workload_identity_pool_provider_id = "example-prvdr" + display_name = "Name of provider" + description = "X.509 identity pool provider for automated test" + disabled = true + attribute_mapping = { + "google.subject" = "assertion.subject.dn.cn" + } + x509 { + trust_store { + trust_anchors { + pem_certificate = file("test-fixtures/trust_anchor.pem") + } + intermediate_cas { + pem_certificate = file("test-fixtures/intermediate_ca.pem") + } + } + } +} +``` ## Argument Reference @@ -353,6 +415,12 @@ The following arguments are supported: An SAML 2.0 identity provider. Not compatible with the property oidc or aws. Structure is [documented below](#nested_saml). +* `x509` - + (Optional) + An X.509-type identity provider represents a CA. It is trusted to assert a + client identity if the client has a certificate that chains up to this CA. + Structure is [documented below](#nested_x509). + * `project` - (Optional) The ID of the project in which the resource belongs. If it is not provided, the provider project is used. @@ -415,6 +483,49 @@ The following arguments are supported: (Required) SAML Identity provider configuration metadata xml doc. +The `x509` block supports: + +* `trust_store` - + (Required) + A Trust store, use this trust store as a wrapper to config the trust + anchor and optional intermediate cas to help build the trust chain for + the incoming end entity certificate. Follow the x509 guidelines to + define those PEM encoded certs. Only 1 trust store is currently + supported. + Structure is [documented below](#nested_trust_store). + + +The `trust_store` block supports: + +* `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_trust_anchors). + +* `intermediate_cas` - + (Optional) + Set of intermediate CA certificates used for building the trust chain to + trust anchor. + IMPORTANT: Intermediate CAs are only supported when configuring x509 federation. + Structure is [documented below](#nested_intermediate_cas). + + +The `trust_anchors` block supports: + +* `pem_certificate` - + (Optional) + PEM certificate of the PKI used for validation. Must only contain one + ca certificate(either root or intermediate cert). + +The `intermediate_cas` block supports: + +* `pem_certificate` - + (Optional) + 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: