Skip to content

Commit bab08a7

Browse files
committed
feature: allow configuring kid in rsa keys
Signed-off-by: Ruxandra Laceanu <[email protected]>
1 parent 7902dce commit bab08a7

File tree

4 files changed

+112
-0
lines changed

4 files changed

+112
-0
lines changed

docs/resources/realm_keystore_rsa.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ resource "keycloak_realm_keystore_rsa" "keystore_rsa" {
2929
algorithm = "RS256"
3030
keystore_size = 2048
3131
provider_id = "rsa"
32+
33+
extra_config = {
34+
kid = "my-key-id"
35+
}
3236
}
3337
```
3438

@@ -44,6 +48,7 @@ resource "keycloak_realm_keystore_rsa" "keystore_rsa" {
4448
- `algorithm` - (Optional) Intended algorithm for the key. Defaults to `RS256`. Use `RSA-OAEP` for encryption keys
4549
- `keystore_size` - (Optional) Size for the generated keys. Defaults to `2048`.
4650
- `provider_id` - (Optional) Use `rsa` for signing keys, `rsa-enc` for encryption keys
51+
- `extra_config` - (Optional) Map of additional provider configuration options passed through to the Keycloak component config. For RSA keystores this can include keys like `kid`.
4752

4853
## Import
4954

keycloak/realm_keystore_rsa.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ type RealmKeystoreRsa struct {
1919
PrivateKey string
2020
Certificate string
2121
ProviderId string
22+
ExtraConfig map[string]interface{}
2223
}
2324

2425
func convertFromRealmKeystoreRsaToComponent(realmKey *RealmKeystoreRsa) *component {
@@ -43,6 +44,13 @@ func convertFromRealmKeystoreRsaToComponent(realmKey *RealmKeystoreRsa) *compone
4344
},
4445
}
4546

47+
// merge extra config
48+
if realmKey.ExtraConfig != nil {
49+
for k, v := range realmKey.ExtraConfig {
50+
componentConfig[k] = []string{fmt.Sprint(v)}
51+
}
52+
}
53+
4654
return &component{
4755
Id: realmKey.Id,
4856
Name: realmKey.Name,
@@ -86,6 +94,21 @@ func convertFromComponentToRealmKeystoreRsa(component *component, realmId string
8694
ProviderId: component.ProviderId,
8795
}
8896

97+
// capture extra config (anything not in the known keys)
98+
known := map[string]struct{}{
99+
"active": {}, "enabled": {}, "priority": {}, "algorithm": {}, "privateKey": {}, "certificate": {},
100+
}
101+
extra := map[string]interface{}{}
102+
for k, vals := range component.Config {
103+
if _, ok := known[k]; ok {
104+
continue
105+
}
106+
if len(vals) > 0 {
107+
extra[k] = vals[0]
108+
}
109+
}
110+
realmKey.ExtraConfig = extra
111+
89112
return realmKey, nil
90113
}
91114

provider/resource_keycloak_realm_keystore_rsa.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ func resourceKeycloakRealmKeystoreRsa() *schema.Resource {
7676
Description: "RSA key provider id",
7777
ForceNew: true,
7878
},
79+
"extra_config": {
80+
Type: schema.TypeMap,
81+
Optional: true,
82+
},
7983
},
8084
}
8185
}
@@ -95,6 +99,8 @@ func getRealmKeystoreRsaFromData(data *schema.ResourceData) *keycloak.RealmKeyst
9599
ProviderId: data.Get("provider_id").(string),
96100
}
97101

102+
mapper.ExtraConfig = getExtraConfigFromData(data)
103+
98104
return mapper
99105
}
100106

@@ -113,6 +119,7 @@ func setRealmKeystoreRsaData(data *schema.ResourceData, realmKey *keycloak.Realm
113119
data.Set("private_key", realmKey.PrivateKey)
114120
data.Set("certificate", realmKey.Certificate)
115121
}
122+
setExtraConfigData(data, realmKey.ExtraConfig)
116123
}
117124

118125
func resourceKeycloakRealmKeystoreRsaCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {

provider/resource_keycloak_realm_keystore_rsa_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,30 @@ func TestAccKeycloakRealmKeystoreRsa_algorithmValidation(t *testing.T) {
112112
})
113113
}
114114

115+
func TestAccKeycloakRealmKeystoreRsa_extraConfigKid(t *testing.T) {
116+
t.Parallel()
117+
118+
rsaName := acctest.RandomWithPrefix("tf-acc")
119+
kid := acctest.RandomWithPrefix("tf-acc")
120+
privateKey, certificate := generateKeyAndCert(2048)
121+
122+
resource.Test(t, resource.TestCase{
123+
ProviderFactories: testAccProviderFactories,
124+
PreCheck: func() { testAccPreCheck(t) },
125+
CheckDestroy: testAccCheckRealmKeystoreRsaDestroy(),
126+
Steps: []resource.TestStep{
127+
{
128+
Config: testKeycloakRealmKeystoreRsa_withKidExtraConfig(rsaName, privateKey, certificate, kid),
129+
Check: resource.ComposeTestCheckFunc(
130+
testAccCheckRealmKeystoreRsaExists("keycloak_realm_keystore_rsa.realm_rsa"),
131+
testAccCheckRealmKeystoreRsaKidInRealmKeys("keycloak_realm_keystore_rsa.realm_rsa", kid),
132+
),
133+
ExpectNonEmptyPlan: true,
134+
},
135+
},
136+
})
137+
}
138+
115139
func testAccCheckRealmKeystoreRsaExists(resourceName string) resource.TestCheckFunc {
116140
return func(s *terraform.State) error {
117141
_, err := getKeycloakRealmKeystoreRsaFromState(s, resourceName)
@@ -123,6 +147,36 @@ func testAccCheckRealmKeystoreRsaExists(resourceName string) resource.TestCheckF
123147
}
124148
}
125149

150+
func testAccCheckRealmKeystoreRsaKidInRealmKeys(resourceName, expectedKid string) resource.TestCheckFunc {
151+
return func(s *terraform.State) error {
152+
fetchedKeystore, err := getKeycloakRealmKeystoreRsaFromState(s, resourceName)
153+
if err != nil {
154+
return err
155+
}
156+
157+
keys, err := keycloakClient.GetRealmKeys(testCtx, fetchedKeystore.RealmId)
158+
if err != nil {
159+
return fmt.Errorf("error fetching realm keys: %w", err)
160+
}
161+
162+
var candidates []keycloak.Key
163+
for _, k := range keys.Keys {
164+
if k.Algorithm != nil && *k.Algorithm == fetchedKeystore.Algorithm &&
165+
k.Certificate != nil && *k.Certificate == fetchedKeystore.Certificate {
166+
candidates = append(candidates, k)
167+
}
168+
}
169+
170+
for _, c := range candidates {
171+
if c.Kid != nil && *c.Kid == expectedKid {
172+
return nil
173+
}
174+
}
175+
176+
return fmt.Errorf("could not find expected kid in realm keys. expected kid=%s", expectedKid)
177+
}
178+
}
179+
126180
func testAccCheckRealmKeystoreRsaFetch(resourceName string, keystore *keycloak.RealmKeystoreRsa) resource.TestCheckFunc {
127181
return func(s *terraform.State) error {
128182
fetchedKeystore, err := getKeycloakRealmKeystoreRsaFromState(s, resourceName)
@@ -258,3 +312,26 @@ resource "keycloak_realm_keystore_rsa" "realm_rsa" {
258312
}
259313
`, testAccRealmUserFederation.Realm, rsaName, attr, val, privateKey, certificate, provider)
260314
}
315+
316+
func testKeycloakRealmKeystoreRsa_withKidExtraConfig(rsaName, privateKey, certificate, kid string) string {
317+
return fmt.Sprintf(`
318+
data "keycloak_realm" "realm" {
319+
realm = "%s"
320+
}
321+
322+
resource "keycloak_realm_keystore_rsa" "realm_rsa" {
323+
name = "%s"
324+
realm_id = data.keycloak_realm.realm.id
325+
326+
priority = 100
327+
algorithm = "RS256"
328+
private_key = "%s"
329+
certificate = "%s"
330+
provider_id = "rsa"
331+
332+
extra_config = {
333+
"kid" = "%s"
334+
}
335+
}
336+
`, testAccRealmUserFederation.Realm, rsaName, privateKey, certificate, kid)
337+
}

0 commit comments

Comments
 (0)