You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
jwtauthccl, securityccl: sync SQL roles from JWT groups claim
Previously, JWT login authenticated users but did not mirror group membership
into SQL roles.
This was inadequate because one would like to also authorize the user based on
group membership information present in the JWT. A similar role-sync is already
in place in the LDAP auth flow.
To address this, this patch adds an authorizer that grants/revokes roles listed
in the token’s "groups" claim, or any other claim as configured. If the JWT
does not contain a field with groups, the authorizer tries to fetch the groups
from the IdP's userinfo endpoint.
If the fetched groups list is empty, meaning the claim exists but contains `[]`
or the userinfo response yields no groups, the server:
1. revokes all existing SQL role memberships for the user, and
2. rejects the login with `JWT authorization: empty group list`.
The feature is disabled by default and gated by
`server.jwt_authentication.authorization.enabled`.
Additionally, the field names of the JWT and userinfo JSONs where cockroach
looks for the groups list can be customized using
`server.jwt_authentication.group_claim` and
`server.jwt_authentication.userinfo_group_key` respectively.
This commit also provides a new package `securityccl/jwthelper` that provides
`ExtractGroups()`, a small helper that accepts a JWT and extracts and normalizes
group information.
This helper is now used by jwtauthccl and can be reused by oidcccl for
supporting authorization in the OIDC flow.
Fixes: #104671
Epic: CRDB-48763
Release note (security update): CockroachDB can now synchronise SQL
role membership from the groups claim contained in a JWT when
`server.jwt_authentication.authorization.enabled = true`. The claim
name and the fallback *userinfo* JSON key are configurable by
`server.jwt_authentication.group_claim` and
`server.jwt_authentication.userinfo_group_key` respectively.
Behaviour matches the existing LDAP role-sync feature.
.
Common IdP examples
-------------------
- Okta (default mapping)
SET CLUSTER SETTING server.jwt_authentication.group_claim = 'groups';
SET CLUSTER SETTING server.jwt_authentication.userinfo_group_key = 'groups';
.
- Keycloak
If you map Keycloak Groups to a JWT claim (default):
group_claim = 'groups' -- e.g. "groups": ["team-a","team-b"]
.
If you prefer Keycloak’s built-in realm roles, CockroachDB does not follow
nested paths like "realm_access.roles". Add a Keycloak protocol mapper that
flattens roles into a top-level claim (for example "roles") and then
configure:
group_claim = 'roles'; -- e.g. "roles": ["team-a","team-b"]
.
The userinfo endpoint usually returns the same JSON keys, so the same values
work for `userinfo_group_key` as well.
Copy file name to clipboardExpand all lines: docs/generated/settings/settings-for-tenants.txt
+3Lines changed: 3 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -125,13 +125,16 @@ server.hsts.enabled boolean false if true, HSTS headers will be sent along with
125
125
server.http.base_path string / path to redirect the user to upon succcessful login application
126
126
server.identity_map.configuration string system-identity to database-username mappings application
127
127
server.jwt_authentication.audience string sets accepted audience values for JWT logins over the SQL interface application
128
+
server.jwt_authentication.authorization.enabled boolean false enables role synchronisation based on group claims in JWTs application
128
129
server.jwt_authentication.claim string sets the JWT claim that is parsed to get the username application
129
130
server.jwt_authentication.client.timeout duration 15s sets the client timeout for external calls made during JWT authentication (e.g. fetching JWKS, etc.) application
130
131
server.jwt_authentication.enabled boolean false enables or disables JWT login for the SQL interface application
132
+
server.jwt_authentication.group_claim string groups sets the name of the JWT claim that contains groups used for role mapping application
131
133
server.jwt_authentication.issuers.configuration (alias: server.jwt_authentication.issuers) string sets accepted issuer values for JWT logins over the SQL interface which can be a single issuer URL string or a JSON string containing an array of issuer URLs or a JSON object containing map of issuer URLS to JWKS URIs application
132
134
server.jwt_authentication.issuers.custom_ca string sets the PEM encoded custom root CA for verifying certificates while fetching JWKS application
133
135
server.jwt_authentication.jwks string "{""keys"":[]}" sets the public key set for JWT logins over the SQL interface (JWKS format) application
134
136
server.jwt_authentication.jwks_auto_fetch.enabled boolean false enables or disables automatic fetching of JWKS from the issuer's well-known endpoint or JWKS URI set in JWTAuthIssuersConfig. If this is enabled, the server.jwt_authentication.jwks will be ignored. application
137
+
server.jwt_authentication.userinfo_group_key string groups sets the field name to look for in userinfo JSON that lists groups when groups claim is absent from JWT application
135
138
server.ldap_authentication.client.tls_certificate string sets the client certificate PEM for establishing mTLS connection with LDAP server application
136
139
server.ldap_authentication.client.tls_key string sets the client key PEM for establishing mTLS connection with LDAP server application
137
140
server.ldap_authentication.domain.custom_ca string sets the PEM encoded custom root CA for verifying domain certificates when establishing connection with LDAP server application
Copy file name to clipboardExpand all lines: docs/generated/settings/settings.html
+3Lines changed: 3 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -157,13 +157,16 @@
157
157
<tr><td><divid="setting-server-http-base-path" class="anchored"><code>server.http.base_path</code></div></td><td>string</td><td><code>/</code></td><td>path to redirect the user to upon succcessful login</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
158
158
<tr><td><divid="setting-server-identity-map-configuration" class="anchored"><code>server.identity_map.configuration</code></div></td><td>string</td><td><code></code></td><td>system-identity to database-username mappings</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
159
159
<tr><td><divid="setting-server-jwt-authentication-audience" class="anchored"><code>server.jwt_authentication.audience</code></div></td><td>string</td><td><code></code></td><td>sets accepted audience values for JWT logins over the SQL interface</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
160
+
<tr><td><divid="setting-server-jwt-authentication-authorization-enabled" class="anchored"><code>server.jwt_authentication.authorization.enabled</code></div></td><td>boolean</td><td><code>false</code></td><td>enables role synchronisation based on group claims in JWTs</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
160
161
<tr><td><divid="setting-server-jwt-authentication-claim" class="anchored"><code>server.jwt_authentication.claim</code></div></td><td>string</td><td><code></code></td><td>sets the JWT claim that is parsed to get the username</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
161
162
<tr><td><divid="setting-server-jwt-authentication-client-timeout" class="anchored"><code>server.jwt_authentication.client.timeout</code></div></td><td>duration</td><td><code>15s</code></td><td>sets the client timeout for external calls made during JWT authentication (e.g. fetching JWKS, etc.)</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
162
163
<tr><td><divid="setting-server-jwt-authentication-enabled" class="anchored"><code>server.jwt_authentication.enabled</code></div></td><td>boolean</td><td><code>false</code></td><td>enables or disables JWT login for the SQL interface</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
164
+
<tr><td><divid="setting-server-jwt-authentication-group-claim" class="anchored"><code>server.jwt_authentication.group_claim</code></div></td><td>string</td><td><code>groups</code></td><td>sets the name of the JWT claim that contains groups used for role mapping</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
163
165
<tr><td><divid="setting-server-jwt-authentication-issuers" class="anchored"><code>server.jwt_authentication.issuers.configuration<br/>(alias: server.jwt_authentication.issuers)</code></div></td><td>string</td><td><code></code></td><td>sets accepted issuer values for JWT logins over the SQL interface which can be a single issuer URL string or a JSON string containing an array of issuer URLs or a JSON object containing map of issuer URLS to JWKS URIs</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
164
166
<tr><td><divid="setting-server-jwt-authentication-issuers-custom-ca" class="anchored"><code>server.jwt_authentication.issuers.custom_ca</code></div></td><td>string</td><td><code></code></td><td>sets the PEM encoded custom root CA for verifying certificates while fetching JWKS</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
165
167
<tr><td><divid="setting-server-jwt-authentication-jwks" class="anchored"><code>server.jwt_authentication.jwks</code></div></td><td>string</td><td><code>{"keys":[]}</code></td><td>sets the public key set for JWT logins over the SQL interface (JWKS format)</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
166
168
<tr><td><divid="setting-server-jwt-authentication-jwks-auto-fetch-enabled" class="anchored"><code>server.jwt_authentication.jwks_auto_fetch.enabled</code></div></td><td>boolean</td><td><code>false</code></td><td>enables or disables automatic fetching of JWKS from the issuer's well-known endpoint or JWKS URI set in JWTAuthIssuersConfig. If this is enabled, the server.jwt_authentication.jwks will be ignored.</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
169
+
<tr><td><divid="setting-server-jwt-authentication-userinfo-group-key" class="anchored"><code>server.jwt_authentication.userinfo_group_key</code></div></td><td>string</td><td><code>groups</code></td><td>sets the field name to look for in userinfo JSON that lists groups when groups claim is absent from JWT</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
167
170
<tr><td><divid="setting-server-ldap-authentication-client-tls-certificate" class="anchored"><code>server.ldap_authentication.client.tls_certificate</code></div></td><td>string</td><td><code></code></td><td>sets the client certificate PEM for establishing mTLS connection with LDAP server</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
168
171
<tr><td><divid="setting-server-ldap-authentication-client-tls-key" class="anchored"><code>server.ldap_authentication.client.tls_key</code></div></td><td>string</td><td><code></code></td><td>sets the client key PEM for establishing mTLS connection with LDAP server</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
169
172
<tr><td><divid="setting-server-ldap-authentication-domain-custom-ca" class="anchored"><code>server.ldap_authentication.domain.custom_ca</code></div></td><td>string</td><td><code></code></td><td>sets the PEM encoded custom root CA for verifying domain certificates when establishing connection with LDAP server</td><td>Serverless/Dedicated/Self-Hosted</td></tr>
0 commit comments