diff --git a/CHANGELOG.md b/CHANGELOG.md
index 80134067..023c5f86 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+## Changed
+
+- Replaced `api_oidc_config` with `jwt_issuer` resource
+
## [1.8.0] - 2024-09-18
### Added
diff --git a/docs/resources/api_oidc_config.md b/docs/resources/api_oidc_config.md
deleted file mode 100644
index 8b5f5e34..00000000
--- a/docs/resources/api_oidc_config.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-# generated by https://github.com/hashicorp/terraform-plugin-docs
-page_title: "cockroach_api_oidc_config Resource - terraform-provider-cockroach"
-subcategory: ""
-description: |-
- Configuration to allow external OIDC providers to issue tokens for use with CC API.
----
-
-# cockroach_api_oidc_config (Resource)
-
-Configuration to allow external OIDC providers to issue tokens for use with CC API.
-
-## Example Usage
-
-```terraform
-resource "cockroach_api_oidc_config" "example" {
- issuer = "https://accounts.google.com"
- audience = "test_audience"
- jwks = "{\"keys\":[{\"alg\":\"RS256\",\"e\":\"AQAB\",\"kid\":\"test_kid1\",\"kty\":\"RSA\",\"n\":\"09lq1lCEuteonwDJOhGTDak11ThplZuC9JEWQNdBnBSQwlkJQIE7A7nTBO0xTibcsh2HwYkC-N_Gs1jP4iwN3dRqnu5FwG2ct5mY8KLwJiHzToFC0MKenSFQCy0FviNtOnpiObcUlDvR2NDeNtMl_6SPzcQEt7GUTBBYZgoAxPmOgevki6ZNO6Y86xFqx3y6v8EPwW010AiC60r4AHGCTBhYF4uqmq5JH2UU4dDh9Udc-9LZxlSqPwJvnKDG2GjcnD8TsU3wjfEM_nRmx3dnXsrZUXYfNGtdv5dlHywf5AhkJmTavqcsJkgrNA-PNBghFMcCR816_kCIkCYWLWC5vQ\"}]}"
- claim = "sub"
- identity_map = [
- {
- token_identity = "token_identity"
- cc_identity = "cc_identity"
- is_regex = false
- },
- {
- token_identity = "(.*)"
- cc_identity = "\\1@example.com"
- is_regex = true
- },
- ]
-}
-```
-
-
-## Schema
-
-### Required
-
-- `audience` (String) The audience that CC API should accept for this API OIDC Configuration.
-- `issuer` (String) The issuer of tokens for the API OIDC Configuration. Usually this is a url.
-- `jwks` (String) The JSON Web Key Set used to check the signature of the JWTs.
-
-### Optional
-
-- `claim` (String) The JWT claim that should be used as the user identifier. Defaults to the subject.
-- `identity_map` (Attributes List) The mapping rules to convert token user identifiers into a new form. (see [below for nested schema](#nestedatt--identity_map))
-
-### Read-Only
-
-- `id` (String) ID of the API OIDC Configuration.
-
-
-### Nested Schema for `identity_map`
-
-Required:
-
-- `cc_identity` (String) The username (email or service account id) of the CC user that the token should map to.
-- `token_identity` (String) The token value that needs to be mapped.
-
-Optional:
-
-- `is_regex` (Boolean) Indicates that the token_principal field is a regex value.
diff --git a/docs/resources/jwt_issuer.md b/docs/resources/jwt_issuer.md
new file mode 100644
index 00000000..7f64412f
--- /dev/null
+++ b/docs/resources/jwt_issuer.md
@@ -0,0 +1,58 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "cockroach_jwt_issuer Resource - terraform-provider-cockroach"
+subcategory: ""
+description: |-
+ Configuration to manage external JWT Issuers to access CockroachDB Cloud API via JWT.
+---
+
+# cockroach_jwt_issuer (Resource)
+
+Configuration to manage external JWT Issuers to access CockroachDB Cloud API via JWT.
+
+## Example Usage
+
+```terraform
+resource "cockroach_jwt_issuer" "example" {
+ issuer_url = "https://accounts.google.com"
+ audience = "test_audience"
+ jwks = "{\"keys\":[{\"alg\":\"RS256\",\"e\":\"AQAB\",\"kid\":\"test_kid1\",\"kty\":\"RSA\",\"n\":\"09lq1lCEuteonwDJOhGTDak11ThplZuC9JEWQNdBnBSQwlkJQIE7A7nTBO0xTibcsh2HwYkC-N_Gs1jP4iwN3dRqnu5FwG2ct5mY8KLwJiHzToFC0MKenSFQCy0FviNtOnpiObcUlDvR2NDeNtMl_6SPzcQEt7GUTBBYZgoAxPmOgevki6ZNO6Y86xFqx3y6v8EPwW010AiC60r4AHGCTBhYF4uqmq5JH2UU4dDh9Udc-9LZxlSqPwJvnKDG2GjcnD8TsU3wjfEM_nRmx3dnXsrZUXYfNGtdv5dlHywf5AhkJmTavqcsJkgrNA-PNBghFMcCR816_kCIkCYWLWC5vQ\"}]}"
+ claim = "email"
+ identity_map = [
+ {
+ token_identity = "token_identity"
+ cc_identity = "cc_identity"
+ },
+ {
+ token_identity = "(.*)"
+ cc_identity = "\\1@example.com"
+ },
+ ]
+}
+```
+
+
+## Schema
+
+### Required
+
+- `audience` (String) The intended audience for consuming the JWT.
+- `issuer_url` (String) The URL of the server issuing JWTs.
+
+### Optional
+
+- `claim` (String) Used to identify the user from the external Identity Provider. Defaults to "sub".
+- `identity_map` (Attributes List) A list of mappings to map the external token identity into CockroachDB Cloud. (see [below for nested schema](#nestedatt--identity_map))
+- `jwks` (String) A set of public keys (JWKS) used to verify the JWT.
+
+### Read-Only
+
+- `id` (String) The unique identifier of the JWT Issuer resource.
+
+
+### Nested Schema for `identity_map`
+
+Required:
+
+- `cc_identity` (String) Specifies how to map the fetched token identity to an identity in CockroachDB Cloud. In case of a regular expression for token_identity, this must contain a \1 placeholder for the matched content.
+- `token_identity` (String) Specifies how to fetch external identity from the token claim. A regular expression must start with a forward slash. The regular expression must be in RE2 compatible syntax. For further details, please see https://github.com/google/re2/wiki/Syntax.
diff --git a/examples/resources/cockroach_api_oidc_config/resource.tf b/examples/resources/cockroach_api_oidc_config/resource.tf
deleted file mode 100644
index a7de0a18..00000000
--- a/examples/resources/cockroach_api_oidc_config/resource.tf
+++ /dev/null
@@ -1,18 +0,0 @@
-resource "cockroach_api_oidc_config" "example" {
- issuer = "https://accounts.google.com"
- audience = "test_audience"
- jwks = "{\"keys\":[{\"alg\":\"RS256\",\"e\":\"AQAB\",\"kid\":\"test_kid1\",\"kty\":\"RSA\",\"n\":\"09lq1lCEuteonwDJOhGTDak11ThplZuC9JEWQNdBnBSQwlkJQIE7A7nTBO0xTibcsh2HwYkC-N_Gs1jP4iwN3dRqnu5FwG2ct5mY8KLwJiHzToFC0MKenSFQCy0FviNtOnpiObcUlDvR2NDeNtMl_6SPzcQEt7GUTBBYZgoAxPmOgevki6ZNO6Y86xFqx3y6v8EPwW010AiC60r4AHGCTBhYF4uqmq5JH2UU4dDh9Udc-9LZxlSqPwJvnKDG2GjcnD8TsU3wjfEM_nRmx3dnXsrZUXYfNGtdv5dlHywf5AhkJmTavqcsJkgrNA-PNBghFMcCR816_kCIkCYWLWC5vQ\"}]}"
- claim = "sub"
- identity_map = [
- {
- token_identity = "token_identity"
- cc_identity = "cc_identity"
- is_regex = false
- },
- {
- token_identity = "(.*)"
- cc_identity = "\\1@example.com"
- is_regex = true
- },
- ]
-}
diff --git a/examples/resources/cockroach_jwt_issuer/resource.tf b/examples/resources/cockroach_jwt_issuer/resource.tf
new file mode 100644
index 00000000..2e58a7a9
--- /dev/null
+++ b/examples/resources/cockroach_jwt_issuer/resource.tf
@@ -0,0 +1,16 @@
+resource "cockroach_jwt_issuer" "example" {
+ issuer_url = "https://accounts.google.com"
+ audience = "test_audience"
+ jwks = "{\"keys\":[{\"alg\":\"RS256\",\"e\":\"AQAB\",\"kid\":\"test_kid1\",\"kty\":\"RSA\",\"n\":\"09lq1lCEuteonwDJOhGTDak11ThplZuC9JEWQNdBnBSQwlkJQIE7A7nTBO0xTibcsh2HwYkC-N_Gs1jP4iwN3dRqnu5FwG2ct5mY8KLwJiHzToFC0MKenSFQCy0FviNtOnpiObcUlDvR2NDeNtMl_6SPzcQEt7GUTBBYZgoAxPmOgevki6ZNO6Y86xFqx3y6v8EPwW010AiC60r4AHGCTBhYF4uqmq5JH2UU4dDh9Udc-9LZxlSqPwJvnKDG2GjcnD8TsU3wjfEM_nRmx3dnXsrZUXYfNGtdv5dlHywf5AhkJmTavqcsJkgrNA-PNBghFMcCR816_kCIkCYWLWC5vQ\"}]}"
+ claim = "email"
+ identity_map = [
+ {
+ token_identity = "token_identity"
+ cc_identity = "cc_identity"
+ },
+ {
+ token_identity = "(.*)"
+ cc_identity = "\\1@example.com"
+ },
+ ]
+}
diff --git a/internal/provider/api_oidc_config_test.go b/internal/provider/api_oidc_config_test.go
deleted file mode 100644
index b8955820..00000000
--- a/internal/provider/api_oidc_config_test.go
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- Copyright 2023 The Cockroach Authors
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-*/
-
-package provider
-
-import (
- "context"
- "fmt"
- "os"
- "testing"
-
- "github.com/cockroachdb/cockroach-cloud-sdk-go/v3/pkg/client"
- mock_client "github.com/cockroachdb/terraform-provider-cockroach/mock"
- "github.com/golang/mock/gomock"
- "github.com/google/uuid"
- "github.com/hashicorp/terraform-plugin-framework/types"
- "github.com/hashicorp/terraform-plugin-testing/helper/resource"
- "github.com/hashicorp/terraform-plugin-testing/terraform"
-)
-
-// TestAccApiOidcConfigResource attempts to create, check, and destroy
-// a real API OIDC Config. It will be skipped if TF_ACC isn't set.
-// In order to work the ApiOidcEnabled Feature Flag must be enabled and
-// the test org must have Org SSO enabled (no need for SAML/OIDC).
-func TestAccApiOidcConfigResource(t *testing.T) {
- t.Parallel()
- issuer := fmt.Sprintf("issuer-%s", GenerateRandomString(4))
- audience := "audience"
- jwks := "{}"
- claim := "subject"
- identityMap := []IdentityMapEntry{
- {
- CcIdentity: types.StringValue("cc_id1"),
- TokenIdentity: types.StringValue("token_id1"),
- IsRegex: types.BoolValue(false),
- },
- {
- CcIdentity: types.StringValue("cc_id2"),
- TokenIdentity: types.StringValue("token_id2"),
- IsRegex: types.BoolValue(true),
- },
- }
-
- testApiOidcConfigResource(t, issuer, audience, jwks, claim, identityMap, false)
-}
-
-// TestIntegrationApiOidcConfigResource attempts to create, check, and destroy
-// an API OIDC Config, but uses a mocked API service.
-func TestIntegrationApiOidcConfigResource(t *testing.T) {
- id := uuid.Must(uuid.NewUUID())
- if os.Getenv(CockroachAPIKey) == "" {
- os.Setenv(CockroachAPIKey, "fake")
- }
-
- ctrl := gomock.NewController(t)
- s := mock_client.NewMockService(ctrl)
- defer HookGlobal(&NewService, func(c *client.Client) client.Service {
- return s
- })()
- issuer := "issuer"
- audience := "audience"
- claim := "claim"
- jwks := "{}"
- identityMap := []IdentityMapEntry{
- {
- CcIdentity: types.StringValue("cc_id1"),
- TokenIdentity: types.StringValue("token_id1"),
- IsRegex: types.BoolValue(false),
- },
- {
- CcIdentity: types.StringValue("cc_id2"),
- TokenIdentity: types.StringValue("token_id2"),
- IsRegex: types.BoolValue(true),
- },
- }
- response := client.ApiOidcConfig{
- Id: id.String(),
- Issuer: issuer,
- Audience: audience,
- Jwks: jwks,
- Claim: &claim,
- IdentityMap: identityMapFromTerraformState(&identityMap),
- }
-
- s.EXPECT().GetApiOidcConfig(gomock.Any(), id.String()).
- Return(&response, nil, nil).AnyTimes()
- s.EXPECT().CreateApiOidcConfig(gomock.Any(), gomock.Any()).
- Return(&response, nil, nil)
- s.EXPECT().DeleteApiOidcConfig(gomock.Any(), id.String()).
- Return(&response, nil, nil)
-
- testApiOidcConfigResource(t, issuer, audience, jwks, claim, identityMap, true)
-}
-
-func testApiOidcConfigResource(t *testing.T, issuer, audience, jwks, claim string, identityMap []IdentityMapEntry, useMock bool) {
- var (
- resourceNameTest = "cockroach_api_oidc_config.test"
- )
- resource.Test(t, resource.TestCase{
- IsUnitTest: useMock,
- PreCheck: func() { testAccPreCheck(t) },
- ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
- Steps: []resource.TestStep{
- {
- Config: getTestApiOidcConfig(issuer, audience, jwks, claim, identityMap),
- Check: resource.ComposeTestCheckFunc(
- testApiOidcConfig(resourceNameTest, issuer, audience, jwks, claim, identityMap),
- resource.TestCheckResourceAttr(resourceNameTest, "issuer", issuer),
- resource.TestCheckResourceAttr(resourceNameTest, "audience", audience),
- resource.TestCheckResourceAttr(resourceNameTest, "jwks", jwks),
- resource.TestCheckResourceAttr(resourceNameTest, "claim", claim),
- ),
- },
- {
- ResourceName: resourceNameTest,
- ImportState: true,
- ImportStateVerify: true,
- },
- },
- })
-}
-
-func testApiOidcConfig(
- resourceName, issuer, audience, jwks, claim string, identityMap []IdentityMapEntry,
-) resource.TestCheckFunc {
- return func(s *terraform.State) error {
- p := testAccProvider.(*provider)
- p.service = NewService(cl)
-
- rs, ok := s.RootModule().Resources[resourceName]
- if !ok {
- return fmt.Errorf("not found: %s", resourceName)
- }
-
- if rs.Primary.ID == "" {
- return fmt.Errorf("no ID is set")
- }
-
- traceAPICall("GetApiOidcConfig")
- //nolint:staticcheck
- roleResp, _, err := p.service.GetApiOidcConfig(context.TODO(), rs.Primary.ID)
- if err == nil {
- respIdentityMap := *roleResp.IdentityMap
- if roleResp.Issuer == issuer && roleResp.Audience == audience && roleResp.Jwks == jwks && *roleResp.Claim == claim && *respIdentityMap[0].CcIdentity == identityMap[0].CcIdentity.ValueString() {
- return nil
- }
- }
-
- return fmt.Errorf("API OIDC Config does not have correct values")
- }
-}
-
-func getTestApiOidcConfig(issuer, audience, jwks, claim string, identityMap []IdentityMapEntry) string {
- identityMapString := "[\n"
- for _, identityMapEntry := range identityMap {
- identityMapString += "{\n"
- identityMapString += fmt.Sprintf("token_identity = %s\n", identityMapEntry.TokenIdentity)
- identityMapString += fmt.Sprintf("cc_identity = %s\n", identityMapEntry.CcIdentity)
- identityMapString += fmt.Sprintf("is_regex = %s\n", identityMapEntry.IsRegex)
- identityMapString += "},\n"
- }
- identityMapString += "]"
- return fmt.Sprintf(`
-resource "cockroach_api_oidc_config" "test" {
- issuer = "%s"
- audience = "%s"
- jwks = "%s"
- claim = "%s"
- identity_map = %s
-}
-`, issuer, audience, jwks, claim, identityMapString)
-}
diff --git a/internal/provider/api_oidc_config.go b/internal/provider/jwt_issuers.go
similarity index 51%
rename from internal/provider/api_oidc_config.go
rename to internal/provider/jwt_issuers.go
index a4146b2d..a3ba653c 100644
--- a/internal/provider/api_oidc_config.go
+++ b/internal/provider/jwt_issuers.go
@@ -1,5 +1,5 @@
/*
-Copyright 2023 The Cockroach Authors
+Copyright 2024 The Cockroach Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -30,73 +30,70 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
)
-type apiOidcConfigResource struct {
+type jwtIssuerResource struct {
provider *provider
}
-func (r *apiOidcConfigResource) Schema(
+func NewJWTIssuerResource() resource.Resource {
+ return &jwtIssuerResource{}
+}
+
+func (r *jwtIssuerResource) Schema(
_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse,
) {
resp.Schema = schema.Schema{
- MarkdownDescription: "Configuration to allow external OIDC providers to issue tokens for use with CC API.",
+ MarkdownDescription: "Configuration to manage external JWT Issuers to access CockroachDB Cloud API via JWT.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
- MarkdownDescription: "ID of the API OIDC Configuration.",
+ Description: "The unique identifier of the JWT Issuer resource.",
},
- "issuer": schema.StringAttribute{
+ "issuer_url": schema.StringAttribute{
Required: true,
- Description: "The issuer of tokens for the API OIDC Configuration. Usually this is a url.",
+ Description: "The URL of the server issuing JWTs.",
},
"audience": schema.StringAttribute{
Required: true,
- Description: "The audience that CC API should accept for this API OIDC Configuration.",
+ Description: "The intended audience for consuming the JWT.",
},
"jwks": schema.StringAttribute{
- Required: true,
- Description: "The JSON Web Key Set used to check the signature of the JWTs.",
+ Optional: true,
+ Description: "A set of public keys (JWKS) used to verify the JWT.",
},
"claim": schema.StringAttribute{
Optional: true,
- Computed: true,
- Description: "The JWT claim that should be used as the user identifier. Defaults to the subject.",
+ Description: "Used to identify the user from the external Identity Provider. Defaults to \"sub\".",
},
"identity_map": schema.ListNestedAttribute{
+ Optional: true,
+ Description: "A list of mappings to map the external token identity into CockroachDB Cloud.",
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"token_identity": schema.StringAttribute{
Required: true,
- Description: "The token value that needs to be mapped.",
+ Description: "Specifies how to fetch external identity from the token claim. A regular expression must start with a forward slash. The regular expression must be in RE2 compatible syntax. For further details, please see https://github.com/google/re2/wiki/Syntax.",
},
"cc_identity": schema.StringAttribute{
Required: true,
- Description: "The username (email or service account id) of the CC user that the token should map to.",
- },
- "is_regex": schema.BoolAttribute{
- Optional: true,
- Computed: true,
- Description: "Indicates that the token_principal field is a regex value.",
+ Description: "Specifies how to map the fetched token identity to an identity in CockroachDB Cloud. In case of a regular expression for token_identity, this must contain a \\1 placeholder for the matched content.",
},
},
},
- Optional: true,
- Computed: true,
- Description: "The mapping rules to convert token user identifiers into a new form.",
},
},
}
}
-func (r *apiOidcConfigResource) Metadata(
+func (r *jwtIssuerResource) Metadata(
_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse,
) {
- resp.TypeName = req.ProviderTypeName + "_api_oidc_config"
+ resp.TypeName = req.ProviderTypeName + "_jwt_issuer"
}
-func (r *apiOidcConfigResource) Configure(
+func (r *jwtIssuerResource) Configure(
_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse,
) {
if req.ProviderData == nil {
@@ -109,7 +106,13 @@ func (r *apiOidcConfigResource) Configure(
}
}
-func (r *apiOidcConfigResource) Create(
+func (r *jwtIssuerResource) ImportState(
+ ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse,
+) {
+ resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
+}
+
+func (r *jwtIssuerResource) Create(
ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse,
) {
if r.provider == nil || !r.provider.configured {
@@ -117,39 +120,38 @@ func (r *apiOidcConfigResource) Create(
return
}
- var apiOIdcConfigSpec ApiOidcConfig
- diags := req.Plan.Get(ctx, &apiOIdcConfigSpec)
+ var jwtIssuerSpec JWTIssuer
+ diags := req.Plan.Get(ctx, &jwtIssuerSpec)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
- createRequest := &client.CreateApiOidcConfigRequest{
- Audience: apiOIdcConfigSpec.Audience.ValueString(),
- Issuer: apiOIdcConfigSpec.Issuer.ValueString(),
- Jwks: apiOIdcConfigSpec.Jwks.ValueString(),
- Claim: apiOIdcConfigSpec.Claim.ValueStringPointer(),
- IdentityMap: identityMapFromTerraformState(apiOIdcConfigSpec.IdentityMap),
+ createRequest := &client.AddJWTIssuerRequest{
+ Audience: jwtIssuerSpec.Audience.ValueString(),
+ IssuerUrl: jwtIssuerSpec.IssuerURL.ValueString(),
+ Jwks: jwtIssuerSpec.Jwks.ValueStringPointer(),
+ Claim: jwtIssuerSpec.Claim.ValueStringPointer(),
+ IdentityMap: identityMapFromTerraformState(jwtIssuerSpec.IdentityMap),
}
- traceAPICall("CreateApiOidcConfig")
- //nolint:staticcheck
- apiResp, _, err := r.provider.service.CreateApiOidcConfig(ctx, createRequest)
+ traceAPICall("AddJWTIssuer")
+ apiResp, _, err := r.provider.service.AddJWTIssuer(ctx, createRequest)
if err != nil {
resp.Diagnostics.AddError(
- "Error creating API OIDC Config",
- fmt.Sprintf("Could not create API OIDC Config: %s", formatAPIErrorMessage(err)),
+ "Error creating JWT Issuer",
+ fmt.Sprintf("Could not create JWT Issuer: %s", formatAPIErrorMessage(err)),
)
return
}
- loadApiOidcConfigToTerraformState(apiResp, &apiOIdcConfigSpec)
- diags = resp.State.Set(ctx, apiOIdcConfigSpec)
+ loadJWTIssuerToTerraformState(apiResp, &jwtIssuerSpec)
+ diags = resp.State.Set(ctx, jwtIssuerSpec)
resp.Diagnostics.Append(diags...)
}
-func (r *apiOidcConfigResource) Read(
+func (r *jwtIssuerResource) Read(
ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse,
) {
if r.provider == nil || !r.provider.configured {
@@ -157,40 +159,39 @@ func (r *apiOidcConfigResource) Read(
return
}
- var state ApiOidcConfig
+ var state JWTIssuer
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
- traceAPICall("GetApiOidcConfig")
- //nolint:staticcheck
- apiResp, httpResp, err := r.provider.service.GetApiOidcConfig(ctx, state.ID.ValueString())
+ traceAPICall("GetJWTIssuer")
+ apiResp, httpResp, err := r.provider.service.GetJWTIssuer(ctx, state.ID.ValueString())
if err != nil {
if httpResp != nil && httpResp.StatusCode == http.StatusNotFound {
resp.Diagnostics.AddWarning(
- "API OIDC Config not found",
- "API OIDC Config not found. API OIDC Config will be removed from state.")
+ "JWT Issuer not found",
+ "JWT Issuer not found. JWT Issuer will be removed from state.")
resp.State.RemoveResource(ctx)
} else {
resp.Diagnostics.AddError(
- "Error getting API OIDC Config",
- fmt.Sprintf("Unexpected error retrieving API OIDC Config: %s", formatAPIErrorMessage(err)))
+ "Error getting JWT Issuer",
+ fmt.Sprintf("Unexpected error retrieving JWT Issuer: %s", formatAPIErrorMessage(err)))
}
return
}
- loadApiOidcConfigToTerraformState(apiResp, &state)
+ loadJWTIssuerToTerraformState(apiResp, &state)
diags = resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}
-func (r *apiOidcConfigResource) Update(
+func (r *jwtIssuerResource) Update(
ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse,
) {
- var plan ApiOidcConfig
+ var plan JWTIssuer
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
@@ -198,106 +199,97 @@ func (r *apiOidcConfigResource) Update(
}
// Get current state
- var state ApiOidcConfig
+ var state JWTIssuer
diags = req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
- traceAPICall("UpdateApiOidcConfig")
- //nolint:staticcheck
- apiResp, _, err := r.provider.service.UpdateApiOidcConfig(ctx, plan.ID.ValueString(), &client.ApiOidcConfig1{
- Audience: plan.Audience.ValueString(),
- Claim: plan.Claim.ValueStringPointer(),
- IdentityMap: identityMapFromTerraformState(plan.IdentityMap),
- Issuer: plan.Issuer.ValueString(),
- Jwks: plan.Jwks.ValueString(),
- })
+ traceAPICall("UpdateJWTIssuer")
+ apiResp, _, err := r.provider.service.UpdateJWTIssuer(
+ ctx,
+ plan.ID.ValueString(),
+ &client.UpdateJWTIssuerRequest{
+ Audience: plan.Audience.ValueStringPointer(),
+ Claim: plan.Claim.ValueStringPointer(),
+ IdentityMap: identityMapFromTerraformState(plan.IdentityMap),
+ IssuerUrl: plan.IssuerURL.ValueStringPointer(),
+ Jwks: plan.Jwks.ValueStringPointer(),
+ },
+ )
if err != nil {
resp.Diagnostics.AddError(
- "Error update API OIDC Config",
- fmt.Sprintf("Could not update API OIDC Config: %s", formatAPIErrorMessage(err)),
+ "Error updating JWT Issuer",
+ fmt.Sprintf("Could not update JWT Issuer: %s", formatAPIErrorMessage(err)),
)
return
}
- loadApiOidcConfigToTerraformState(apiResp, &state)
+ loadJWTIssuerToTerraformState(apiResp, &state)
diags = resp.State.Set(ctx, state)
resp.Diagnostics.Append(diags...)
}
-func (r *apiOidcConfigResource) Delete(
+func (r *jwtIssuerResource) Delete(
ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse,
) {
- var state ApiOidcConfig
+ var state JWTIssuer
diags := req.State.Get(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
- traceAPICall("DeleteApiOidcConfig")
- //nolint:staticcheck
- _, _, err := r.provider.service.DeleteApiOidcConfig(ctx, state.ID.ValueString())
+ traceAPICall("DeleteJWTIssuer")
+ _, _, err := r.provider.service.DeleteJWTIssuer(ctx, state.ID.ValueString())
if err != nil {
resp.Diagnostics.AddError(
- "Error deleting API OIDC Config",
- fmt.Sprintf("Could not delete API OIDC Config: %s", formatAPIErrorMessage(err)),
+ "Error deleting JWT Issuer",
+ fmt.Sprintf("Could not delete JWT Issuer: %s", formatAPIErrorMessage(err)),
)
return
}
- // Remove resource from state
resp.State.RemoveResource(ctx)
}
-func (r *apiOidcConfigResource) ImportState(
- ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse,
-) {
- resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
-}
-
-func NewApiOidcConfigResource() resource.Resource {
- return &apiOidcConfigResource{}
-}
-
-func loadApiOidcConfigToTerraformState(
- apiOidcConfig *client.ApiOidcConfig, state *ApiOidcConfig,
+func loadJWTIssuerToTerraformState(
+ jwtIssuer *client.JWTIssuer, state *JWTIssuer,
) {
- state.ID = types.StringValue(apiOidcConfig.Id)
- state.Audience = types.StringValue(apiOidcConfig.Audience)
- state.Issuer = types.StringValue(apiOidcConfig.Issuer)
- state.Jwks = types.StringValue(apiOidcConfig.Jwks)
- state.Claim = types.StringPointerValue(apiOidcConfig.Claim)
- state.IdentityMap = identityMapToTerraformState(apiOidcConfig.IdentityMap)
+ state.ID = types.StringValue(jwtIssuer.Id)
+ state.Audience = types.StringValue(jwtIssuer.Audience)
+ state.IssuerURL = types.StringValue(jwtIssuer.IssuerUrl)
+ state.Jwks = types.StringPointerValue(jwtIssuer.Jwks)
+ state.Claim = types.StringPointerValue(jwtIssuer.Claim)
+ state.IdentityMap = identityMapToTerraformState(jwtIssuer.IdentityMap)
}
-func identityMapFromTerraformState(identityMap *[]IdentityMapEntry) *[]client.ApiOidcIdentityMapEntry {
+func identityMapFromTerraformState(identityMap *[]IdentityMapEntry) *[]client.JWTIssuerIdentityMapEntry {
if identityMap == nil {
return nil
}
- var out []client.ApiOidcIdentityMapEntry
+ var out []client.JWTIssuerIdentityMapEntry
for _, mapEntry := range *identityMap {
- out = append(out, client.ApiOidcIdentityMapEntry{
- CcIdentity: mapEntry.CcIdentity.ValueStringPointer(),
- IsRegex: mapEntry.IsRegex.ValueBoolPointer(),
+ out = append(out, client.JWTIssuerIdentityMapEntry{
TokenIdentity: mapEntry.TokenIdentity.ValueStringPointer(),
+ CcIdentity: mapEntry.CcIdentity.ValueStringPointer(),
+ // TODO: Need to remove once the field has been removed from the API.
+ IsRegex: types.BoolValue(false).ValueBoolPointer(),
})
}
return &out
}
-func identityMapToTerraformState(identityMap *[]client.ApiOidcIdentityMapEntry) *[]IdentityMapEntry {
+func identityMapToTerraformState(identityMap *[]client.JWTIssuerIdentityMapEntry) *[]IdentityMapEntry {
if identityMap == nil {
return nil
}
var out []IdentityMapEntry
for _, mapEntry := range *identityMap {
out = append(out, IdentityMapEntry{
- CcIdentity: types.StringPointerValue(mapEntry.CcIdentity),
- IsRegex: types.BoolPointerValue(mapEntry.IsRegex),
TokenIdentity: types.StringPointerValue(mapEntry.TokenIdentity),
+ CcIdentity: types.StringPointerValue(mapEntry.CcIdentity),
})
}
return &out
diff --git a/internal/provider/jwt_issuers_test.go b/internal/provider/jwt_issuers_test.go
new file mode 100644
index 00000000..0e8a6ae2
--- /dev/null
+++ b/internal/provider/jwt_issuers_test.go
@@ -0,0 +1,385 @@
+/*
+ Copyright 2024 The Cockroach Authors
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package provider
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "os"
+ "regexp"
+ "testing"
+
+ "github.com/cockroachdb/cockroach-cloud-sdk-go/v3/pkg/client"
+ mock_client "github.com/cockroachdb/terraform-provider-cockroach/mock"
+ "github.com/golang/mock/gomock"
+ "github.com/google/uuid"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-framework/types/basetypes"
+ "github.com/hashicorp/terraform-plugin-testing/helper/resource"
+ "github.com/hashicorp/terraform-plugin-testing/knownvalue"
+ "github.com/hashicorp/terraform-plugin-testing/statecheck"
+ "github.com/hashicorp/terraform-plugin-testing/terraform"
+ "github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+var (
+ testIssuerURL = "https://issuer-%s.com"
+
+ testAudience = "audience"
+ testAudienceUpdated = "audience_updated"
+
+ testJWKS = "{}"
+ testJWKSUpdated = "{updated: 1}"
+
+ testClaim = "sub"
+ testClaimUpdated = "email"
+
+ testTokenID1 = "token_id1"
+ testCCID1 = "cc_id1"
+
+ testTokenID2 = "token_id2"
+ testCCID2 = "cc_id2"
+
+ testIdentityMap = []IdentityMapEntry{
+ {
+ TokenIdentity: types.StringValue(testTokenID1),
+ CcIdentity: types.StringValue(testCCID1),
+ },
+ {
+ TokenIdentity: types.StringValue(testTokenID2),
+ CcIdentity: types.StringValue(testCCID2),
+ },
+ }
+ testIdentityMapUpdated = []IdentityMapEntry{
+ {
+ TokenIdentity: types.StringValue(testTokenID1),
+ CcIdentity: types.StringValue(testCCID1),
+ },
+ }
+)
+
+// TestAccJWTIssuerResource attempts to create, check, and destroy
+// a real JWT Issuer. It will be skipped if TF_ACC isn't set.
+// In order to work, the `JwtIssuerEnabled` Feature Flag must be enabled and
+// the test org must have Org SSO enabled (no need for SAML/OIDC).
+func TestAccJWTIssuerResource(t *testing.T) {
+ t.Parallel()
+
+ issuerURL := fmt.Sprintf(testIssuerURL, GenerateRandomString(4))
+ testJWTIssuerResource(t, issuerURL, false)
+}
+
+// TestIntegrationJWTIssuerResource attempts to create, check, and destroy
+// a JWT issuer resource, but uses a mocked API service.
+func TestIntegrationJWTIssuerResource(t *testing.T) {
+ if os.Getenv(CockroachAPIKey) == "" {
+ require.NoError(t, os.Setenv(CockroachAPIKey, "fake"))
+ }
+
+ ctrl := gomock.NewController(t)
+ s := mock_client.NewMockService(ctrl)
+ defer HookGlobal(&NewService, func(c *client.Client) client.Service {
+ return s
+ })()
+
+ id := uuid.Must(uuid.NewUUID())
+ issuerURL := fmt.Sprintf(testIssuerURL, GenerateRandomString(4))
+ jwtIssuer := &client.JWTIssuer{
+ Id: id.String(),
+ IssuerUrl: issuerURL,
+ Audience: testAudience,
+ Jwks: &testJWKS,
+ Claim: &testClaim,
+ IdentityMap: identityMapFromTerraformState(&testIdentityMap),
+ }
+ jwtIssuerUpdated := &client.JWTIssuer{
+ Id: id.String(),
+ IssuerUrl: issuerURL,
+ Audience: testAudienceUpdated,
+ Jwks: &testJWKSUpdated,
+ Claim: &testClaimUpdated,
+ IdentityMap: identityMapFromTerraformState(&testIdentityMapUpdated),
+ }
+
+ // Create
+ s.EXPECT().AddJWTIssuer(gomock.Any(), gomock.Any()).
+ Return(jwtIssuer, nil, nil)
+ s.EXPECT().GetJWTIssuer(gomock.Any(), id.String()).
+ Return(jwtIssuer, nil, nil).Times(3)
+
+ // Update
+ s.EXPECT().UpdateJWTIssuer(gomock.Any(), id.String(), gomock.Any()).
+ Return(jwtIssuerUpdated, nil, nil)
+ s.EXPECT().GetJWTIssuer(gomock.Any(), id.String()).
+ Return(jwtIssuerUpdated, nil, nil).Times(3)
+
+ // Delete
+ s.EXPECT().DeleteJWTIssuer(gomock.Any(), id.String()).
+ Return(jwtIssuerUpdated, nil, nil)
+ s.EXPECT().GetJWTIssuer(gomock.Any(), id.String()).
+ Return(nil, &http.Response{StatusCode: http.StatusNotFound}, errors.New("not found"))
+
+ testJWTIssuerResource(t, issuerURL, true)
+}
+
+func testJWTIssuerResource(
+ t *testing.T, issuerURL string, useMock bool,
+) {
+ resourceNameTest := "cockroach_jwt_issuer.test"
+ resource.Test(t, resource.TestCase{
+ IsUnitTest: useMock,
+ PreCheck: func() { testAccPreCheck(t) },
+ ProtoV6ProviderFactories: testAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ Config: getTestJWTIssuerCreateConfig(issuerURL),
+ ConfigStateChecks: []statecheck.StateCheck{
+ statecheck.ExpectKnownValue(
+ resourceNameTest,
+ tfjsonpath.New("id"),
+ knownvalue.NotNull(),
+ ),
+ statecheck.ExpectKnownValue(
+ resourceNameTest,
+ tfjsonpath.New("id"),
+ knownvalue.StringRegexp(
+ regexp.MustCompile(
+ "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
+ ),
+ ),
+ ),
+ },
+ Check: resource.ComposeTestCheckFunc(
+ testJWTIssuer(resourceNameTest, issuerURL),
+ resource.TestCheckResourceAttr(resourceNameTest, "issuer_url", issuerURL),
+ resource.TestCheckResourceAttr(resourceNameTest, "audience", testAudience),
+ resource.TestCheckResourceAttr(resourceNameTest, "jwks", testJWKS),
+ resource.TestCheckResourceAttr(resourceNameTest, "claim", testClaim),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.#", "2"),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.0.token_identity", testIdentityMap[0].TokenIdentity.ValueString()),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.0.cc_identity", testIdentityMap[0].CcIdentity.ValueString()),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.1.token_identity", testIdentityMap[1].TokenIdentity.ValueString()),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.1.cc_identity", testIdentityMap[1].CcIdentity.ValueString()),
+ ),
+ },
+ {
+ Config: getTestJWTIssuerUpdateConfig(issuerURL),
+ ConfigStateChecks: []statecheck.StateCheck{
+ statecheck.ExpectKnownValue(
+ resourceNameTest,
+ tfjsonpath.New("id"),
+ knownvalue.NotNull(),
+ ),
+ statecheck.ExpectKnownValue(
+ resourceNameTest,
+ tfjsonpath.New("id"),
+ knownvalue.StringRegexp(
+ regexp.MustCompile(
+ "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$",
+ ),
+ ),
+ ),
+ },
+ Check: resource.ComposeTestCheckFunc(
+ testJWTIssuerUpdated(resourceNameTest, issuerURL),
+ resource.TestCheckResourceAttr(resourceNameTest, "issuer_url", issuerURL),
+ resource.TestCheckResourceAttr(resourceNameTest, "audience", testAudienceUpdated),
+ resource.TestCheckResourceAttr(resourceNameTest, "jwks", testJWKSUpdated),
+ resource.TestCheckResourceAttr(resourceNameTest, "claim", testClaimUpdated),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.#", "1"),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.0.token_identity", testIdentityMap[0].TokenIdentity.ValueString()),
+ resource.TestCheckResourceAttr(resourceNameTest, "identity_map.0.cc_identity", testIdentityMap[0].CcIdentity.ValueString()),
+ ),
+ },
+ {
+ ResourceName: resourceNameTest,
+ ImportState: true,
+ ImportStateVerify: true,
+ Destroy: true,
+ },
+ },
+ CheckDestroy: testJWTIssuerDestroy(resourceNameTest),
+ })
+}
+
+func getTestJWTIssuerCreateConfig(issuerURL string) string {
+ identityMapString := "[\n"
+ for _, identityMapEntry := range testIdentityMap {
+ identityMapString += "{\n"
+ identityMapString += fmt.Sprintf("token_identity = %s\n", identityMapEntry.TokenIdentity)
+ identityMapString += fmt.Sprintf("cc_identity = %s\n", identityMapEntry.CcIdentity)
+ identityMapString += "},\n"
+ }
+ identityMapString += "]"
+
+ return fmt.Sprintf(`
+resource "cockroach_jwt_issuer" "test" {
+ issuer_url = "%s"
+ audience = "%s"
+ jwks = "%s"
+ claim = "%s"
+ identity_map = %s
+}
+`, issuerURL, testAudience, testJWKS, testClaim, identityMapString)
+}
+
+func getTestJWTIssuerUpdateConfig(issuerURL string) string {
+ identityMapString := "[\n"
+ for _, identityMapEntry := range testIdentityMapUpdated {
+ identityMapString += "{\n"
+ identityMapString += fmt.Sprintf("token_identity = %s\n", identityMapEntry.TokenIdentity)
+ identityMapString += fmt.Sprintf("cc_identity = %s\n", identityMapEntry.CcIdentity)
+ identityMapString += "},\n"
+ }
+ identityMapString += "]"
+
+ return fmt.Sprintf(`
+resource "cockroach_jwt_issuer" "test" {
+ issuer_url = "%s"
+ audience = "%s"
+ jwks = "%s"
+ claim = "%s"
+ identity_map = %s
+}
+`, issuerURL, testAudienceUpdated, testJWKSUpdated, testClaimUpdated, identityMapString)
+}
+
+func testJWTIssuer(resourceName, issuerURL string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ p := testAccProvider.(*provider)
+ p.service = NewService(cl)
+
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("not found: %s", resourceName)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("no ID is set")
+ }
+
+ expectedResp := &client.JWTIssuer{
+ IssuerUrl: issuerURL,
+ Audience: testAudience,
+ Jwks: &testJWKS,
+ Claim: &testClaim,
+ IdentityMap: &[]client.JWTIssuerIdentityMapEntry{
+ {
+ TokenIdentity: testIdentityMap[0].TokenIdentity.ValueStringPointer(),
+ CcIdentity: testIdentityMap[0].CcIdentity.ValueStringPointer(),
+ // TODO: Need to remove once the field has been removed from the API.
+ IsRegex: basetypes.NewBoolValue(false).ValueBoolPointer(),
+ },
+ {
+ TokenIdentity: testIdentityMap[1].TokenIdentity.ValueStringPointer(),
+ CcIdentity: testIdentityMap[1].CcIdentity.ValueStringPointer(),
+ // TODO: Need to remove once the field has been removed from the API.
+ IsRegex: basetypes.NewBoolValue(false).ValueBoolPointer(),
+ },
+ },
+ }
+
+ traceAPICall("GetJWTIssuer")
+ jwtIssuerResp, _, err := p.service.GetJWTIssuer(context.TODO(), rs.Primary.ID)
+ if err == nil {
+ // Copy over the resource ID as it is dynamic in nature.
+ expectedResp.Id = jwtIssuerResp.Id
+ if assert.ObjectsAreEqual(expectedResp, jwtIssuerResp) {
+ return nil
+ }
+ }
+
+ return fmt.Errorf("JWT Issuer configuration mismatch, expected %+v, got %+v",
+ expectedResp, jwtIssuerResp)
+ }
+}
+
+func testJWTIssuerUpdated(resourceName, issuerURL string) resource.TestCheckFunc {
+ return func(s *terraform.State) error {
+ p := testAccProvider.(*provider)
+ p.service = NewService(cl)
+
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("not found: %s", resourceName)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("no ID is set")
+ }
+
+ expectedResp := &client.JWTIssuer{
+ IssuerUrl: issuerURL,
+ Audience: testAudienceUpdated,
+ Jwks: &testJWKSUpdated,
+ Claim: &testClaimUpdated,
+ IdentityMap: &[]client.JWTIssuerIdentityMapEntry{
+ {
+ TokenIdentity: testIdentityMapUpdated[0].TokenIdentity.ValueStringPointer(),
+ CcIdentity: testIdentityMapUpdated[0].CcIdentity.ValueStringPointer(),
+ // TODO: Need to remove once the field has been removed from the API.
+ IsRegex: basetypes.NewBoolValue(false).ValueBoolPointer(),
+ },
+ },
+ }
+
+ traceAPICall("GetJWTIssuer")
+ jwtIssuerResp, _, err := p.service.GetJWTIssuer(context.TODO(), rs.Primary.ID)
+ if err == nil {
+ // Copy over the resource ID as it is dynamic in nature.
+ expectedResp.Id = jwtIssuerResp.Id
+ if assert.ObjectsAreEqual(expectedResp, jwtIssuerResp) {
+ return nil
+ }
+ }
+
+ return fmt.Errorf("JWT Issuer configuration mismatch, expected %+v, got %+v",
+ expectedResp, jwtIssuerResp)
+ }
+}
+
+func testJWTIssuerDestroy(resourceName string) resource.TestCheckFunc {
+ return func(s *terraform.State) (err error) {
+ p := testAccProvider.(*provider)
+ p.service = NewService(cl)
+
+ rs, ok := s.RootModule().Resources[resourceName]
+ if !ok {
+ return fmt.Errorf("not found: %s", resourceName)
+ }
+
+ if rs.Primary.ID == "" {
+ return fmt.Errorf("no ID is set")
+ }
+
+ traceAPICall("GetJWTIssuer")
+ _, httpResponse, err := p.service.GetJWTIssuer(context.TODO(), rs.Primary.ID)
+ if err != nil && httpResponse != nil && httpResponse.StatusCode == http.StatusNotFound {
+ return nil
+ }
+
+ var statusCode int
+ if httpResponse != nil {
+ statusCode = httpResponse.StatusCode
+ }
+ return fmt.Errorf("JWT Issuer not destroyed, HTTP response code: %d, error: %v", statusCode, err)
+ }
+}
diff --git a/internal/provider/models.go b/internal/provider/models.go
index e8577dec..49d88762 100644
--- a/internal/provider/models.go
+++ b/internal/provider/models.go
@@ -307,9 +307,9 @@ type FolderDataSourceModel struct {
ParentId types.String `tfsdk:"parent_id"`
}
-type ApiOidcConfig struct {
+type JWTIssuer struct {
ID types.String `tfsdk:"id"`
- Issuer types.String `tfsdk:"issuer"`
+ IssuerURL types.String `tfsdk:"issuer_url"`
Audience types.String `tfsdk:"audience"`
Jwks types.String `tfsdk:"jwks"`
Claim types.String `tfsdk:"claim"`
@@ -319,7 +319,6 @@ type ApiOidcConfig struct {
type IdentityMapEntry struct {
TokenIdentity types.String `tfsdk:"token_identity"`
CcIdentity types.String `tfsdk:"cc_identity"`
- IsRegex types.Bool `tfsdk:"is_regex"`
}
type ServiceAccount struct {
diff --git a/internal/provider/provider.go b/internal/provider/provider.go
index 589883d8..e3042322 100644
--- a/internal/provider/provider.go
+++ b/internal/provider/provider.go
@@ -144,7 +144,7 @@ func (p *provider) Resources(_ context.Context) []func() resource.Resource {
NewMaintenanceWindowResource,
NewVersionDeferralResource,
NewFolderResource,
- NewApiOidcConfigResource,
+ NewJWTIssuerResource,
NewServiceAccountResource,
NewAPIKeyResource,
}