Repository: rancher/terraform-provider-rancher2

Issue:
[release/v13] feat: support generic OIDC provider (#1644)
Backport #1644 to release/v13 for #1646 

from PR:
> ## Issue:
> Resolves [rancher/rancher#51059](https://github.com/rancher/rancher/issues/51059)
> 
> ## Problem
> Currently, the Rancher2 Terraform provider does not support the configuration of a Generic OIDC authentication provider. This prevents users from automating the integration of OIDC-compliant identity providers (such as self-hosted GitLab, etc.) through Infrastructure as Code (IaC). All configuration for this provider must be done manually through the Rancher UI or direct API calls.
> 
> ## Solution
> This PR introduces a new resource, `rancher2_auth_config_generic_oidc`, to manage the Generic OIDC authentication provider in Rancher. The resource targets the `genericoidc` auth provider in the Rancher API.
> 
> The new resource allows users to:
> 
> * Enable and disable the Generic OIDC provider.
> * Configure all necessary OIDC client options, including `client_id`, `client_secret`, and endpoint URLs.
> * Specify the required `scopes` and the `groups_field` to correctly parse group memberships from the OIDC token.
> * Explicitly enable group processing via the `group_search_enabled` flag, which is a crucial requirement for the `genericoidc` provider to correctly identify group principals.
> 
> This implementation allows for a complete, automated setup of Generic OIDC authentication, as demonstrated in the example below using GitLab as the identity provider.
> 
> Example Configuration:
> 
> ```hcl
> resource "rancher2_auth_config_generic_oidc" "gitlab" {
>   enabled              = true
>   client_id            = "your-gitlab-client-id"
>   client_secret        = "your-gitlab-client-secret"
>   issuer               = "https://gitlab.yourcompany.com"
>   rancher_url          = "https://rancher.yourcompany.com/verify-auth"
>   
>   # Explicitly define endpoints for robustness
>   auth_endpoint        = "https://gitlab.yourcompany.com/oauth/authorize"
>   token_endpoint       = "https://gitlab.yourcompany.com/oauth/token"
>   userinfo_endpoint    = "https://gitlab.yourcompany.com/oauth/userinfo"
>   jwks_url             = "https://gitlab.yourcompany.com/oauth/discovery/keys"
> 
>   # Scopes required to get user and group info from GitLab
>   scopes               = "openid profile email read_api"
>   
>   # OIDC claim for group membership
>   groups_field         = "groups"
> 
>   # This flag is required to instruct Rancher to process group claims
>   group_search_enabled = true
> }
> 
> # Bind a GitLab group to the Rancher admin role
> resource "rancher2_global_role_binding" "gitlab_admin_binding" {
>   name               = "gitlab-admins"
>   global_role_id     = "admin" # The name is case-sensitive
>   group_principal_id = "genericoidc_group://rancher-admins"
>   depends_on         = [rancher2_auth_config_generic_oidc.gitlab]
> }
> ```
> 
> ## Testing
> The repro steps in the GitHub issue are valid as they describe the lack of the resource. Testing for this PR involves verifying the functionality of the new `rancher2_auth_config_generic_oidc` resource.
> 
> ## Engineering Testing
> ### Manual Testing
> Manually tested the full lifecycle (create, update, destroy) of the `rancher2_auth_config_generic_oidc` resource against a live Rancher v2.12 instance using a local Docker-based GitLab CE instance as the OIDC provider.
> 
> * **Create:** Successfully enabled and configured OIDC with GitLab. Verified that users from GitLab could log into Rancher.
> * **Role Binding:** Successfully created a `rancher2_global_role_binding` to map a GitLab group to the Rancher "Admin" role. Verified that a user logging in as part of that group received the correct administrative permissions.
> * **Update:** Successfully modified the `scopes` and `groups_field` of the OIDC configuration and confirmed the changes were applied in Rancher.
> * **Destroy:** Successfully disabled the OIDC provider by running `terraform destroy`. Verified that the login method was removed from Rancher's login screen.
> 
> ### Automated Testing
> * **Unit Tests:** Added `structure_auth_config_generic_oidc_test.go` to provide comprehensive unit tests for the `flatten` and `expand` functions, ensuring correct mapping between the Terraform schema and the Rancher API model.
> * **Acceptance Tests:** Added `resource_rancher2_auth_config_generic_oidc_test.go`, which includes a new acceptance test (`TestAccRancher2AuthConfigGenericOIDC_basic`). This test performs a full create-update-destroy lifecycle against a live Rancher API, verifying that all configurable fields are set and updated correctly.
> 
> ## QA Testing Considerations
> * QA should test with a standard OIDC provider (like Keycloak or a public GitLab/Okta instance) to ensure compatibility.
> * **Fresh Install:** Test creating the `rancher2_auth_config_generic_oidc` resource from scratch. Verify that a user from the OIDC provider can log in. Test that a `rancher2_global_role_binding` correctly grants permissions to an OIDC group.
> * **Upgrade Scenario:** While this is a new resource, QA should ensure that applying this configuration does not negatively impact any other existing auth providers that might be configured.
> * **Key fields to test:**
>   
>   * `enabled` (toggling between `true` and `false`).
>   * `group_search_enabled = true` is critical for group mapping to work.
>   * `access_mode = "restricted"` with `allowed_principal_ids` to ensure only specific users/groups can log in.
> 
> ### Regressions Considerations
> * The risk of regression is very low. This change adds a new, self-contained resource and only modifies the `provider.go` file to register it. It does not alter any existing auth provider logic. The underlying Go client for Rancher is unchanged. The primary area to watch would be ensuring that the provider initialization and API client creation are not inadvertently affected, but the changes are minimal and well-scoped. Probability of regression is estimated to be less than 1%.



Hints from issue comments:
@matttrach: getting backport ready@matttrach: backport merged, getting RC ready@matttrach: [v13.0.0-rc1](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc1) is ready for QA to test.@matttrach: @JonCrowther @raulcabello, would you assign someone from your team to validate?@samjustus: @matttrach @dasarinaidu is assigned to the rancher issue to test it - do we need to assign him here too? @github-actions: New Release Candidate Available for Validation: [v13.0.0-rc.12](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc.12)

@github-actions: New Release Candidate Available for Validation: [v13.0.0-rc.13](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc.13)

@github-actions: New Release Candidate Available for Validation: [v13.0.0-rc.14](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc.14)

@github-actions: New Release Candidate Available for Validation: [v13.0.0-rc.15](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc.15)

@github-actions: New Release Candidate Available for Validation: [v13.0.0-rc.16](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc.16)

@github-actions: New Release Candidate Available for Validation: [v13.0.0-rc.17](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.0.0-rc.17)

@github-actions: New Release Candidate Available for Validation: [v13.1.3-rc.1](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.1.3-rc.1)

@github-actions: New Release Candidate Available for Validation: [v13.1.3-rc.2](https://github.com/rancher/terraform-provider-rancher2/releases/tag/v13.1.3-rc.2)

@matttrach: This has passed testing per https://github.com/rancher/rancher/issues/51059 

Solution patch:
diff --git a/docs/resources/auth_config_generic_oidc.md b/docs/resources/auth_config_generic_oidc.md
new file mode 100644
index 00000000..b66e916e
--- /dev/null
+++ b/docs/resources/auth_config_generic_oidc.md
@@ -0,0 +1,69 @@
+---
+page_title: "rancher2_auth_config_generic_oidc Resource"
+---
+
+# rancher2\_auth\_config\_generic\_oidc Resource
+
+Provides a Rancher v2 Auth Config Generic OIDC resource. This can be used to configure and enable the Generic OIDC authentication provider for Rancher v2.
+
+In addition to the built-in local auth, only one external auth config provider can be enabled at a time.
+
+## Example Usage
+
+This example configures Rancher to use GitLab as a Generic OIDC provider.
+
+```hcl
+resource "rancher2_auth_config_generic_oidc" "generic_oidc" {
+  name          = "genericoidc"
+  client_id     = "<GITLAB_APPLICATION_ID>"
+  client_secret = "<GITLAB_CLIENT_SECRET>"
+  issuer        = "https://gitlab.com"
+  rancher_url   = "https://<RANCHER_URL>/verify-auth"
+
+  # OIDC claim mapping
+  scopes               = "openid profile email read_api"
+  groups_field         = "groups"
+  
+  # For the 'genericoidc' provider, group processing must be explicitly enabled.
+  group_search_enabled = true
+}
+```
+
+## Argument Reference
+
+The following arguments are supported:
+
+* `client_id` - (Required/Sensitive) The OIDC Client ID.
+* `client_secret` - (Required/Sensitive) The OIDC Client Secret.
+* `issuer` - (Required) The OIDC issuer URL.
+* `rancher_url` - (Required) The URL of the Rancher server. This is used as the redirect URI for the OIDC provider.
+* `access_mode` - (Optional) Access mode for auth. `required`, `restricted`, `unrestricted` are supported. Default `unrestricted` (string)
+* `allowed_principal_ids` - (Optional) Allowed principal IDs for auth. Required if `access_mode` is `required` or `restricted`. Ex: `genericoidc_user://<USER_ID>` `genericoidc_group://<GROUP_ID>` (list)
+* `auth_endpoint` - (Optional/Computed) The OIDC Auth Endpoint URL.
+* `certificate` - (Optional/Sensitive) A PEM-encoded CA certificate for the OIDC provider.
+* `enabled` - (Optional) Enable the auth config provider. Default `true` (bool)
+* `groups_field` - (Optional/Computed) The name of the OIDC claim to use for the user's group memberships. Default `groups` (string)
+* `group_search_enabled` - (Optional) Enable group search. Default `false` (bool)
+* `jwks_url` - (Optional/Computed) The OIDC JWKS URL.
+* `private_key` - (Optional/Sensitive) A PEM-encoded private key for the OIDC provider.
+* `scopes` - (Optional/Computed) The OIDC scopes to request. Defaults to `openid profile email` (string)
+* `token_endpoint` - (Optional/Computed) The OIDC Token Endpoint URL.
+* `userinfo_endpoint` - (Optional/Computed) The OIDC User Info Endpoint URL.
+* `annotations` - (Optional/Computed) Annotations of the resource (map)
+* `labels` - (Optional/Computed) Labels of the resource (map)
+
+## Attributes Reference
+
+The following attributes are exported:
+
+* `id` - (Computed) The ID of the resource (string)
+* `name` - (Computed) The name of the resource (string)
+* `type` - (Computed) The type of the resource (string)
+
+## Import
+
+Generic OIDC auth config can be imported using its name.
+
+```
+$ terraform import rancher2_auth_config_generic_oidc.generic_oidc genericoidc
+```
diff --git a/rancher2/config.go b/rancher2/config.go
index e0b31197..78297995 100644
--- a/rancher2/config.go
+++ b/rancher2/config.go
@@ -1256,6 +1256,8 @@ func getAuthConfigObject(kind string) (interface{}, error) {
 		return &managementClient.GithubConfig{}, nil
 	case managementClient.KeyCloakConfigType:
 		return &managementClient.KeyCloakConfig{}, nil
+	case managementClient.GenericOIDCConfigType:
+		return &managementClient.GenericOIDCConfig{}, nil
 	case managementClient.OKTAConfigType:
 		return &managementClient.OKTAConfig{}, nil
 	case managementClient.OpenLdapConfigType:
diff --git a/rancher2/provider.go b/rancher2/provider.go
index 1cbee1d7..4979c056 100644
--- a/rancher2/provider.go
+++ b/rancher2/provider.go
@@ -115,6 +115,7 @@ func Provider() terraform.ResourceProvider {
 			"rancher2_auth_config_github":                            resourceRancher2AuthConfigGithub(),
 			"rancher2_auth_config_keycloak":                          resourceRancher2AuthConfigKeyCloak(),
 			"rancher2_auth_config_okta":                              resourceRancher2AuthConfigOKTA(),
+			"rancher2_auth_config_generic_oidc":                      resourceRancher2AuthConfigGenericOIDC(),
 			"rancher2_auth_config_openldap":                          resourceRancher2AuthConfigOpenLdap(),
 			"rancher2_auth_config_ping":                              resourceRancher2AuthConfigPing(),
 			"rancher2_bootstrap":                                     resourceRancher2Bootstrap(),
diff --git a/rancher2/resource_rancher2_auth_config_generic_oidc.go b/rancher2/resource_rancher2_auth_config_generic_oidc.go
new file mode 100644
index 00000000..4cdffdb3
--- /dev/null
+++ b/rancher2/resource_rancher2_auth_config_generic_oidc.go
@@ -0,0 +1,119 @@
+package rancher2
+
+import (
+	"fmt"
+	"log"
+
+	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+	managementClient "github.com/rancher/rancher/pkg/client/generated/management/v3"
+)
+
+func resourceRancher2AuthConfigGenericOIDC() *schema.Resource {
+	return &schema.Resource{
+		Create: resourceRancher2AuthConfigGenericOIDCCreate,
+		Read:   resourceRancher2AuthConfigGenericOIDCRead,
+		Update: resourceRancher2AuthConfigGenericOIDCUpdate,
+		Delete: resourceRancher2AuthConfigGenericOIDCDelete,
+
+		Schema: authConfigGenericOIDCFields(),
+	}
+}
+
+func resourceRancher2AuthConfigGenericOIDCCreate(d *schema.ResourceData, meta interface{}) error {
+	client, err := meta.(*Config).ManagementClient()
+	if err != nil {
+		return err
+	}
+
+	auth, err := client.AuthConfig.ByID(AuthConfigGenericOIDCName)
+	if err != nil {
+		return fmt.Errorf("[ERROR] Failed to get Auth Config %s: %s", AuthConfigGenericOIDCName, err)
+	}
+
+	log.Printf("[INFO] Creating Auth Config %s", AuthConfigGenericOIDCName)
+
+	authOIDC, err := expandAuthConfigGenericOIDC(d)
+	if err != nil {
+		return fmt.Errorf("[ERROR] Failed expanding Auth Config %s: %s", AuthConfigGenericOIDCName, err)
+	}
+
+	// Checking if other auth config is enabled
+	if authOIDC.Enabled {
+		err = meta.(*Config).CheckAuthConfigEnabled(AuthConfigGenericOIDCName)
+		if err != nil {
+			return fmt.Errorf("[ERROR] Checking to enable Auth Config %s: %s", AuthConfigGenericOIDCName, err)
+		}
+	}
+
+	newAuth := &managementClient.OIDCConfig{}
+	err = meta.(*Config).UpdateAuthConfig(auth.Links["self"], authOIDC, newAuth)
+	if err != nil {
+		return fmt.Errorf("[ERROR] Updating Auth Config %s: %s", AuthConfigGenericOIDCName, err)
+	}
+
+	return resourceRancher2AuthConfigGenericOIDCRead(d, meta)
+}
+
+func resourceRancher2AuthConfigGenericOIDCRead(d *schema.ResourceData, meta interface{}) error {
+	log.Printf("[INFO] Refreshing Auth Config %s", AuthConfigGenericOIDCName)
+	client, err := meta.(*Config).ManagementClient()
+	if err != nil {
+		return err
+	}
+
+	auth, err := client.AuthConfig.ByID(AuthConfigGenericOIDCName)
+	if err != nil {
+		if IsNotFound(err) {
+			log.Printf("[INFO] Auth Config %s not found.", AuthConfigGenericOIDCName)
+			d.SetId("")
+			return nil
+		}
+		return err
+	}
+
+	authOIDC, err := meta.(*Config).GetAuthConfig(auth)
+	if err != nil {
+		return err
+	}
+
+	err = flattenAuthConfigGenericOIDC(d, authOIDC.(*managementClient.OIDCConfig))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func resourceRancher2AuthConfigGenericOIDCUpdate(d *schema.ResourceData, meta interface{}) error {
+	log.Printf("[INFO] Updating Auth Config %s", AuthConfigGenericOIDCName)
+	return resourceRancher2AuthConfigGenericOIDCCreate(d, meta)
+}
+
+func resourceRancher2AuthConfigGenericOIDCDelete(d *schema.ResourceData, meta interface{}) error {
+	log.Printf("[INFO] Disabling Auth Config %s", AuthConfigGenericOIDCName)
+
+	client, err := meta.(*Config).ManagementClient()
+	if err != nil {
+		return err
+	}
+
+	auth, err := client.AuthConfig.ByID(AuthConfigGenericOIDCName)
+	if err != nil {
+		if IsNotFound(err) {
+			log.Printf("[INFO] Auth Config %s not found.", AuthConfigGenericOIDCName)
+			d.SetId("")
+			return nil
+		}
+		return err
+	}
+
+	if auth.Enabled == true {
+		err = client.Post(auth.Actions["disable"], nil, nil)
+		if err != nil {
+			return fmt.Errorf("[ERROR] Disabling Auth Config %s: %s", AuthConfigGenericOIDCName, err)
+		}
+	}
+
+	d.SetId("")
+	return nil
+}
diff --git a/rancher2/schema_auth_config_generic_oidc.go b/rancher2/schema_auth_config_generic_oidc.go
new file mode 100644
index 00000000..d689270b
--- /dev/null
+++ b/rancher2/schema_auth_config_generic_oidc.go
@@ -0,0 +1,98 @@
+package rancher2
+
+import (
+	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+)
+
+const AuthConfigGenericOIDCName = "genericoidc"
+
+//Schemas
+
+func authConfigGenericOIDCFields() map[string]*schema.Schema {
+	s := map[string]*schema.Schema{
+		"client_id": {
+			Type:        schema.TypeString,
+			Required:    true,
+			Sensitive:   true,
+			Description: "The OIDC Client ID.",
+		},
+		"client_secret": {
+			Type:        schema.TypeString,
+			Required:    true,
+			Sensitive:   true,
+			Description: "The OIDC Client Secret.",
+		},
+		"issuer": {
+			Type:        schema.TypeString,
+			Required:    true,
+			Description: "The OIDC issuer URL.",
+		},
+		"rancher_url": {
+			Type:        schema.TypeString,
+			Required:    true,
+			Description: "The URL of the Rancher server. This is used as the redirect URI for the OIDC provider.",
+		},
+		"auth_endpoint": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Computed:    true,
+			Description: "The OIDC Auth Endpoint URL.",
+		},
+		"token_endpoint": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Computed:    true,
+			Description: "The OIDC Token Endpoint URL.",
+		},
+		"userinfo_endpoint": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Computed:    true,
+			Description: "The OIDC User Info Endpoint URL.",
+		},
+		"jwks_url": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Computed:    true,
+			Description: "The OIDC JWKS URL.",
+		},
+		"scopes": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Computed:    true,
+			Description: "The OIDC scopes to request. Defaults to `openid profile email`.",
+		},
+		"group_search_enabled": {
+			Type:        schema.TypeBool,
+			Optional:    true,
+			Default:     false,
+			Description: "Enable group search.",
+		},
+		"groups_field": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Computed:    true,
+			Description: "The name of the OIDC claim to use for the user's group memberships.",
+		},
+		"certificate": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Sensitive:   true,
+			StateFunc:   TrimSpace,
+			Description: "A PEM-encoded CA certificate for the OIDC provider.",
+		},
+		"private_key": {
+			Type:        schema.TypeString,
+			Optional:    true,
+			Sensitive:   true,
+			StateFunc:   TrimSpace,
+			Description: "A PEM-encoded private key for the OIDC provider.",
+		},
+	}
+
+	for k, v := range authConfigFields() {
+		s[k] = v
+	}
+
+	return s
+}
diff --git a/rancher2/structure_auth_config_generic_oidc.go b/rancher2/structure_auth_config_generic_oidc.go
new file mode 100644
index 00000000..adea94fb
--- /dev/null
+++ b/rancher2/structure_auth_config_generic_oidc.go
@@ -0,0 +1,140 @@
+package rancher2
+
+import (
+	"fmt"
+
+	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+	managementClient "github.com/rancher/rancher/pkg/client/generated/management/v3"
+)
+
+// Flatteners
+
+func flattenAuthConfigGenericOIDC(d *schema.ResourceData, in *managementClient.OIDCConfig) error {
+	d.SetId(AuthConfigGenericOIDCName)
+	d.Set("name", AuthConfigGenericOIDCName)
+	d.Set("type", managementClient.GenericOIDCConfigType)
+	d.Set("access_mode", in.AccessMode)
+
+	err := d.Set("allowed_principal_ids", toArrayInterface(in.AllowedPrincipalIDs))
+	if err != nil {
+		return err
+	}
+
+	d.Set("enabled", in.Enabled)
+
+	err = d.Set("annotations", toMapInterface(in.Annotations))
+	if err != nil {
+		return err
+	}
+	err = d.Set("labels", toMapInterface(in.Labels))
+	if err != nil {
+		return err
+	}
+
+	d.Set("client_id", in.ClientID)
+	d.Set("issuer", in.Issuer)
+	d.Set("rancher_url", in.RancherURL)
+	d.Set("auth_endpoint", in.AuthEndpoint)
+	d.Set("token_endpoint", in.TokenEndpoint)
+	d.Set("userinfo_endpoint", in.UserInfoEndpoint)
+	d.Set("jwks_url", in.JWKSUrl)
+	d.Set("scopes", in.Scopes)
+	if in.GroupSearchEnabled != nil {
+		d.Set("group_search_enabled", *in.GroupSearchEnabled)
+	}
+	d.Set("groups_field", in.GroupsClaim)
+	d.Set("certificate", in.Certificate)
+	d.Set("private_key", in.PrivateKey)
+
+	return nil
+}
+
+// Expanders
+
+func expandAuthConfigGenericOIDC(in *schema.ResourceData) (*managementClient.OIDCConfig, error) {
+	obj := &managementClient.OIDCConfig{}
+	if in == nil {
+		return nil, fmt.Errorf("expanding %s Auth Config: Input ResourceData is nil", AuthConfigGenericOIDCName)
+	}
+
+	obj.Name = AuthConfigGenericOIDCName
+	obj.Type = managementClient.GenericOIDCConfigType
+
+	if v, ok := in.Get("access_mode").(string); ok && len(v) > 0 {
+		obj.AccessMode = v
+	}
+
+	if v, ok := in.Get("allowed_principal_ids").([]interface{}); ok && len(v) > 0 {
+		obj.AllowedPrincipalIDs = toArrayString(v)
+	}
+
+	if (obj.AccessMode == "required" || obj.AccessMode == "restricted") && len(obj.AllowedPrincipalIDs) == 0 {
+		return nil, fmt.Errorf("expanding %s Auth Config: allowed_principal_ids is required on access_mode %s", AuthConfigGenericOIDCName, obj.AccessMode)
+	}
+
+	if v, ok := in.Get("enabled").(bool); ok {
+		obj.Enabled = v
+	}
+
+	if v, ok := in.Get("annotations").(map[string]interface{}); ok && len(v) > 0 {
+		obj.Annotations = toMapString(v)
+	}
+
+	if v, ok := in.Get("labels").(map[string]interface{}); ok && len(v) > 0 {
+		obj.Labels = toMapString(v)
+	}
+
+	if v, ok := in.Get("client_id").(string); ok && len(v) > 0 {
+		obj.ClientID = v
+	}
+
+	if v, ok := in.Get("client_secret").(string); ok && len(v) > 0 {
+		obj.ClientSecret = v
+	}
+
+	if v, ok := in.Get("issuer").(string); ok && len(v) > 0 {
+		obj.Issuer = v
+	}
+
+	if v, ok := in.Get("rancher_url").(string); ok && len(v) > 0 {
+		obj.RancherURL = v
+	}
+
+	if v, ok := in.Get("auth_endpoint").(string); ok && len(v) > 0 {
+		obj.AuthEndpoint = v
+	}
+
+	if v, ok := in.Get("token_endpoint").(string); ok && len(v) > 0 {
+		obj.TokenEndpoint = v
+	}
+
+	if v, ok := in.Get("userinfo_endpoint").(string); ok && len(v) > 0 {
+		obj.UserInfoEndpoint = v
+	}
+
+	if v, ok := in.Get("jwks_url").(string); ok && len(v) > 0 {
+		obj.JWKSUrl = v
+	}
+
+	if v, ok := in.Get("scopes").(string); ok && len(v) > 0 {
+		obj.Scopes = v
+	}
+
+	if v, ok := in.Get("group_search_enabled").(bool); ok {
+		obj.GroupSearchEnabled = &v
+	}
+
+	if v, ok := in.Get("groups_field").(string); ok && len(v) > 0 {
+		obj.GroupsClaim = v
+	}
+
+	if v, ok := in.Get("certificate").(string); ok && len(v) > 0 {
+		obj.Certificate = v
+	}
+
+	if v, ok := in.Get("private_key").(string); ok && len(v) > 0 {
+		obj.PrivateKey = v
+	}
+
+	return obj, nil
+}



Test patch:
diff --git a/rancher2/resource_rancher2_auth_config_generic_oidc_test.go b/rancher2/resource_rancher2_auth_config_generic_oidc_test.go
new file mode 100644
index 00000000..63f496af
--- /dev/null
+++ b/rancher2/resource_rancher2_auth_config_generic_oidc_test.go
@@ -0,0 +1,121 @@
+package rancher2
+
+import (
+	"fmt"
+	"os"
+	"time"
+
+	"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
+	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+	"github.com/hashicorp/terraform-plugin-sdk/terraform"
+)
+
+const (
+	testAccRancher2AuthConfigGenericOIDCName = "genericoidc"
+	testAccRancher2AuthConfigGenericOIDCType = "rancher2_auth_config_generic_oidc"
+)
+
+var (
+	testAccProviders                                 map[string]terraform.ResourceProvider
+	testAccProvider                                  *schema.Provider
+	testAccRancher2AuthConfigGenericOIDCClientID     = os.Getenv("RANCHER_OIDC_CLIENT_ID")
+	testAccRancher2AuthConfigGenericOIDCClientSecret = os.Getenv("RANCHER_OIDC_CLIENT_SECRET")
+	testAccRancher2AuthConfigGenericOIDCIssuerURL    = os.Getenv("RANCHER_OIDC_ISSUER_URL")
+	testAccRancher2AuthConfigGenericOIDCRancherURL   = os.Getenv("RANCHER_URL")
+)
+
+func init() {
+	testAccProvider = Provider().(*schema.Provider)
+	testAccProviders = map[string]terraform.ResourceProvider{
+		"rancher2": testAccProvider,
+	}
+}
+
+func testAccCheckRancher2AuthConfigGenericOIDCExists(name string) resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		rs, ok := s.RootModule().Resources[name]
+		if !ok {
+			return fmt.Errorf("Not found: %s", name)
+		}
+
+		if rs.Primary.ID == "" {
+			return fmt.Errorf("No Auth Config Generic OIDC ID is set")
+		}
+
+		// Reading the auth config can be slow, add a delay.
+		time.Sleep(2 * time.Second)
+
+		return nil
+	}
+}
+
+func testAccCheckRancher2AuthConfigGenericOIDCConfig() resource.TestCheckFunc {
+	return func(s *terraform.State) error {
+		client, err := testAccProvider.Meta().(*Config).ManagementClient()
+		if err != nil {
+			return err
+		}
+
+		auth, err := client.AuthConfig.ByID(AuthConfigGenericOIDCName)
+		if err != nil {
+			return fmt.Errorf("Failed to get Auth Config %s: %s", AuthConfigGenericOIDCName, err)
+		}
+
+		if auth.Enabled != true {
+			return fmt.Errorf("Auth Config %s is not enabled", AuthConfigGenericOIDCName)
+		}
+
+		return nil
+	}
+}
+
+func testAccCheckRancher2AuthConfigGenericOIDCDisabled(s *terraform.State) error {
+	client, err := testAccProvider.Meta().(*Config).ManagementClient()
+	if err != nil {
+		return err
+	}
+
+	auth, err := client.AuthConfig.ByID(AuthConfigGenericOIDCName)
+	if err != nil {
+		if IsNotFound(err) {
+			return nil
+		}
+		return err
+	}
+
+	if auth.Enabled == true {
+		return fmt.Errorf("Auth Config %s is still enabled", AuthConfigGenericOIDCName)
+	}
+
+	return nil
+}
+
+func testAccRancher2AuthConfigGenericOIDCConfig() string {
+	return fmt.Sprintf(`
+resource "rancher2_auth_config_generic_oidc" "genericoidc" {
+  client_id            = "%s"
+  client_secret        = "%s"
+  issuer               = "%s"
+  rancher_url          = "%s/verify-auth"
+  enabled              = true
+  scopes               = "openid profile email"
+  groups_field         = "groups"
+  group_search_enabled = true
+}
+`, testAccRancher2AuthConfigGenericOIDCClientID, testAccRancher2AuthConfigGenericOIDCClientSecret, testAccRancher2AuthConfigGenericOIDCIssuerURL, testAccRancher2AuthConfigGenericOIDCRancherURL)
+}
+
+func testAccRancher2AuthConfigGenericOIDCUpdateConfig() string {
+	return fmt.Sprintf(`
+resource "rancher2_auth_config_generic_oidc" "genericoidc" {
+  client_id            = "%s"
+  client_secret        = "%s"
+  issuer               = "%s"
+  rancher_url          = "%s/verify-auth"
+  enabled              = true
+  scopes               = "openid profile"
+  groups_field         = "group"
+  group_search_enabled = false
+}
+`, testAccRancher2AuthConfigGenericOIDCClientID, testAccRancher2AuthConfigGenericOIDCClientSecret, testAccRancher2AuthConfigGenericOIDCIssuerURL, testAccRancher2AuthConfigGenericOIDCRancherURL)
+}
diff --git a/rancher2/structure_auth_config_generic_oidc_test.go b/rancher2/structure_auth_config_generic_oidc_test.go
new file mode 100644
index 00000000..2d909d94
--- /dev/null
+++ b/rancher2/structure_auth_config_generic_oidc_test.go
@@ -0,0 +1,102 @@
+package rancher2
+
+import (
+	"testing"
+
+	"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
+	managementClient "github.com/rancher/rancher/pkg/client/generated/management/v3"
+	"github.com/stretchr/testify/assert"
+)
+
+var (
+	testAuthConfigGenericOIDCConf      *managementClient.OIDCConfig
+	testAuthConfigGenericOIDCInterface map[string]interface{}
+	groupSearchEnabled                 = true
+)
+
+func init() {
+	testAuthConfigGenericOIDCConf = &managementClient.OIDCConfig{
+		Name:                AuthConfigGenericOIDCName,
+		Type:                managementClient.GenericOIDCConfigType,
+		AccessMode:          "access",
+		AllowedPrincipalIDs: []string{"allowed1", "allowed2"},
+		Enabled:             true,
+		ClientID:            "client_id",
+		Issuer:              "issuer",
+		RancherURL:          "rancher_url",
+		AuthEndpoint:        "auth_endpoint",
+		TokenEndpoint:       "token_endpoint",
+		UserInfoEndpoint:    "userinfo_endpoint",
+		JWKSUrl:             "jwks_url",
+		Scopes:              "scopes",
+		GroupSearchEnabled:  &groupSearchEnabled,
+		GroupsClaim:         "groups_field",
+		Certificate:         "certificate",
+		PrivateKey:          "private_key",
+	}
+	testAuthConfigGenericOIDCInterface = map[string]interface{}{
+		"name":                  AuthConfigGenericOIDCName,
+		"type":                  managementClient.GenericOIDCConfigType,
+		"access_mode":           "access",
+		"allowed_principal_ids": []interface{}{"allowed1", "allowed2"},
+		"enabled":               true,
+		"client_id":             "client_id",
+		"issuer":                "issuer",
+		"rancher_url":           "rancher_url",
+		"auth_endpoint":         "auth_endpoint",
+		"token_endpoint":        "token_endpoint",
+		"userinfo_endpoint":     "userinfo_endpoint",
+		"jwks_url":              "jwks_url",
+		"scopes":                "scopes",
+		"group_search_enabled":  true,
+		"groups_field":          "groups_field",
+		"certificate":           "certificate",
+		"private_key":           "private_key",
+	}
+}
+
+func TestFlattenAuthConfigGenericOIDC(t *testing.T) {
+	cases := []struct {
+		Input          *managementClient.OIDCConfig
+		ExpectedOutput map[string]interface{}
+	}{
+		{
+			testAuthConfigGenericOIDCConf,
+			testAuthConfigGenericOIDCInterface,
+		},
+	}
+
+	for _, tc := range cases {
+		output := schema.TestResourceDataRaw(t, authConfigGenericOIDCFields(), map[string]interface{}{})
+		err := flattenAuthConfigGenericOIDC(output, tc.Input)
+		if err != nil {
+			assert.FailNow(t, "[ERROR] on flattener: %#v", err)
+		}
+		expectedOutput := map[string]interface{}{}
+		for k := range tc.ExpectedOutput {
+			expectedOutput[k] = output.Get(k)
+		}
+		assert.Equal(t, tc.ExpectedOutput, expectedOutput, "Unexpected output from flattener.")
+	}
+}
+
+func TestExpandAuthConfigGenericOIDC(t *testing.T) {
+	cases := []struct {
+		Input          map[string]interface{}
+		ExpectedOutput *managementClient.OIDCConfig
+	}{
+		{
+			testAuthConfigGenericOIDCInterface,
+			testAuthConfigGenericOIDCConf,
+		},
+	}
+
+	for _, tc := range cases {
+		inputResourceData := schema.TestResourceDataRaw(t, authConfigGenericOIDCFields(), tc.Input)
+		output, err := expandAuthConfigGenericOIDC(inputResourceData)
+		if err != nil {
+			assert.FailNow(t, "[ERROR] on expander: %#v", err)
+		}
+		assert.Equal(t, tc.ExpectedOutput, output, "Unexpected output from expander.")
+	}
+}