Skip to content

Commit 493535e

Browse files
committed
feat: Add OIDC client resource.
This adds support for the OIDC Provider OIDCClient resource.
1 parent 8f2378c commit 493535e

7 files changed

Lines changed: 973 additions & 0 deletions

aspell_custom.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,4 @@ destructuring
4343
yaml
4444
ttl
4545
pkce
46+
oidcclients

docs/resources/oidc_client.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
page_title: "rancher2_oidc_client Resource"
3+
---
4+
5+
# rancher2\_oidc_client Resource
6+
7+
Provides a Rancher OIDC Client. This can be used to configure the OIDC Clients
8+
available for the Rancher OIDC Provider.
9+
10+
## Example Usage
11+
12+
### Creating a Rancher OIDC Client.
13+
14+
```hcl
15+
resource "rancher2_oidc_client" "oidc-test-client" {
16+
description = "Access for Test Client"
17+
token_expiration_seconds = 600 # expiration of the id_token and access_token
18+
refresh_token_expiration_seconds = 7200 # expiration of the refresh_token
19+
redirect_uris = [
20+
"http://127.0.0.1:5556/auth/rancher/callback",
21+
"http://127.0.0.1:33418/",
22+
"https://vscode.dev/redirect"
23+
]
24+
}
25+
```
26+
27+
## Argument Reference
28+
29+
The following arguments are supported:
30+
31+
* `description` - A human-readable description for the OIDC Client.
32+
* `token_expiration_seconds` - ID Token and Access Token will only be valid for this many seconds.
33+
* `refresh_token_expiration_seconds` - How long can the refresh token be used for?
34+
* `redirect_uris` - Provides a list of allowed redirect URIs for this OIDC Client.
35+
* `annotations` - (Optional/Computed) Annotations for OIDC Client object (map)
36+
* `labels` - (Optional/Computed) Labels for OIDC Client object (map)
37+
38+
## Attributes Reference
39+
40+
The following attributes are exported:
41+
42+
* `id` - (Computed) The ID of the resource (string)
43+
* `client_id` - (Computed) The ID to be used when authenticating as this OIDC Client.
44+
45+
## Import
46+
47+
OIDC Clients can be imported using the Client name in the format `<client_name>`
48+
49+
```
50+
$ terraform import rancher2_oidc_client.foo &lt;CLIENT_NAME&gt;
51+
```

rancher2/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ func Provider() terraform.ResourceProvider {
140140
"rancher2_namespace": resourceRancher2Namespace(),
141141
"rancher2_node_driver": resourceRancher2NodeDriver(),
142142
"rancher2_node_pool": resourceRancher2NodePool(),
143+
"rancher2_oidc_client": resourceRancher2OIDCClient(),
143144
"rancher2_pod_security_admission_configuration_template": resourceRancher2PodSecurityAdmissionConfigurationTemplate(),
144145
"rancher2_project": resourceRancher2Project(),
145146
"rancher2_project_role_template_binding": resourceRancher2ProjectRoleTemplateBinding(),
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package rancher2
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"maps"
7+
8+
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
9+
"github.com/hashicorp/terraform-plugin-sdk/helper/validation"
10+
managementClient "github.com/rancher/rancher/pkg/client/generated/management/v3"
11+
)
12+
13+
func resourceRancher2OIDCClient() *schema.Resource {
14+
return &schema.Resource{
15+
Create: resourceRancher2OIDCClientCreate,
16+
Read: resourceRancher2OIDCClientRead,
17+
Update: resourceRancher2OIDCClientUpdate,
18+
Delete: resourceRancher2OIDCClientDelete,
19+
Importer: &schema.ResourceImporter{
20+
State: resourceRancher2OIDCClientImport,
21+
},
22+
23+
Schema: oidcClientFields(),
24+
}
25+
}
26+
27+
func oidcClientFields() map[string]*schema.Schema {
28+
s := map[string]*schema.Schema{
29+
"token_expiration_seconds": {
30+
Type: schema.TypeInt,
31+
Optional: true,
32+
Computed: true,
33+
Description: "The duration (in seconds) before an access token and ID token expire.",
34+
ValidateFunc: validation.IntAtLeast(1),
35+
},
36+
"refresh_token_expiration_seconds": {
37+
Type: schema.TypeInt,
38+
Optional: true,
39+
Computed: true,
40+
Description: "The duration (in seconds) a refresh token remains valid before it expires.",
41+
ValidateFunc: validation.IntAtLeast(1),
42+
},
43+
"redirect_uris": {
44+
Description: "List of allowed redirect_uris for this client.",
45+
Required: true,
46+
Type: schema.TypeList,
47+
Elem: &schema.Schema{
48+
Type: schema.TypeString,
49+
},
50+
},
51+
"description": {
52+
Type: schema.TypeString,
53+
Optional: true,
54+
Description: "OIDCClient description",
55+
},
56+
"client_id": {
57+
Type: schema.TypeString,
58+
Computed: true,
59+
Description: "The Client ID for OIDC Access.",
60+
},
61+
}
62+
63+
maps.Copy(s, commonAnnotationLabelFields())
64+
65+
return s
66+
}
67+
68+
func resourceRancher2OIDCClientCreate(d *schema.ResourceData, meta any) error {
69+
log.Printf("[INFO] Creating OIDCClient")
70+
oidcClient, err := expandOIDCClient(d)
71+
if err != nil {
72+
return err
73+
}
74+
75+
client, err := meta.(managementClientGetter).ManagementClient()
76+
if err != nil {
77+
return fmt.Errorf("getting a client when creating OIDC Client: %w", err)
78+
}
79+
80+
createdClient, err := client.OIDCClient.Create(oidcClient)
81+
if err != nil {
82+
return fmt.Errorf("creating OIDCClient: %w", err)
83+
}
84+
85+
d.SetId(createdClient.ID)
86+
87+
return resourceRancher2OIDCClientRead(d, meta)
88+
}
89+
90+
func resourceRancher2OIDCClientRead(d *schema.ResourceData, meta any) error {
91+
log.Printf("[INFO] Refreshing OIDCClient ID %s", d.Id())
92+
93+
client, err := meta.(managementClientGetter).ManagementClient()
94+
if err != nil {
95+
return fmt.Errorf("getting a client when reading OIDC Client: %w", err)
96+
}
97+
oidcClient, err := client.OIDCClient.ByID(d.Id())
98+
if err != nil {
99+
if IsNotFound(err) || IsForbidden(err) || IsNotAccessibleByID(err) {
100+
d.SetId("")
101+
return nil
102+
}
103+
return fmt.Errorf("reading OIDC Client %s: %w", d.Id(), err)
104+
}
105+
106+
return flattenOIDCClient(d, oidcClient)
107+
}
108+
109+
func resourceRancher2OIDCClientUpdate(d *schema.ResourceData, meta any) error {
110+
log.Printf("[INFO] Updating OIDCClient ID %s", d.Id())
111+
112+
client, err := meta.(managementClientGetter).ManagementClient()
113+
if err != nil {
114+
return fmt.Errorf("getting a client when updating OIDC Client: %w", err)
115+
}
116+
117+
oidcClient, err := client.OIDCClient.ByID(d.Id())
118+
if err != nil {
119+
return fmt.Errorf("getting OIDC Client %s for update: %w", d.Id(), err)
120+
}
121+
122+
update := map[string]any{
123+
"labels": toMapString(d.Get("labels").(map[string]any)),
124+
"annotations": toMapString(d.Get("annotations").(map[string]any)),
125+
"description": d.Get("description"),
126+
"redirectURIs": toArrayString(d.Get("redirect_uris").([]any)),
127+
"tokenExpirationSeconds": d.Get("token_expiration_seconds"),
128+
"refreshTokenExpirationSeconds": d.Get("refresh_token_expiration_seconds"),
129+
}
130+
131+
_, err = client.OIDCClient.Update(oidcClient, update)
132+
if err != nil {
133+
return fmt.Errorf("updating OIDC Client %s: %w", d.Id(), err)
134+
}
135+
136+
return resourceRancher2OIDCClientRead(d, meta)
137+
}
138+
139+
func resourceRancher2OIDCClientDelete(d *schema.ResourceData, meta any) error {
140+
log.Printf("[INFO] Deleting OIDCClient ID %s", d.Id())
141+
142+
client, err := meta.(managementClientGetter).ManagementClient()
143+
if err != nil {
144+
return fmt.Errorf("getting a client when deleting OIDC Client: %w", err)
145+
}
146+
147+
oidcClient, err := client.OIDCClient.ByID(d.Id())
148+
if err != nil {
149+
if IsNotFound(err) || IsForbidden(err) || IsNotAccessibleByID(err) {
150+
d.SetId("")
151+
return nil
152+
}
153+
return fmt.Errorf("getting OIDC Client %s for deletion: %w", d.Id(), err)
154+
}
155+
156+
err = client.OIDCClient.Delete(oidcClient)
157+
if err != nil {
158+
if !IsNotFound(err) {
159+
return fmt.Errorf("deleting OIDC Client %s: %w", d.Id(), err)
160+
}
161+
}
162+
163+
d.SetId("")
164+
return nil
165+
}
166+
167+
func resourceRancher2OIDCClientImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
168+
err := resourceRancher2OIDCClientRead(d, meta)
169+
if err != nil || d.Id() == "" {
170+
return []*schema.ResourceData{}, err
171+
}
172+
173+
return []*schema.ResourceData{d}, nil
174+
}
175+
176+
type managementClientGetter interface {
177+
ManagementClient() (*managementClient.Client, error)
178+
}

0 commit comments

Comments
 (0)