Skip to content

Commit 5367660

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

7 files changed

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

0 commit comments

Comments
 (0)