Skip to content

Commit 084d316

Browse files
committed
Squashed all JWT auth
Add aspell Enable jwt-cpp in fasttest Add test + some minor improvements reduce unneeded possible clash points
1 parent ecdfbcd commit 084d316

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1733
-13
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,3 +369,6 @@
369369
[submodule "contrib/idna"]
370370
path = contrib/idna
371371
url = https://github.com/ada-url/idna.git
372+
[submodule "contrib/jwt-cpp"]
373+
path = contrib/jwt-cpp
374+
url = https://github.com/Thalhammer/jwt-cpp.git

contrib/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ add_contrib (openldap-cmake openldap)
8585
add_contrib (grpc-cmake grpc)
8686
add_contrib (msgpack-c-cmake msgpack-c)
8787
add_contrib (libarchive-cmake libarchive)
88-
88+
add_contrib (jwt-cpp-cmake jwt-cpp)
8989
add_contrib (corrosion-cmake corrosion)
9090

9191
if (ENABLE_FUZZING)

contrib/jwt-cpp

Submodule jwt-cpp added at a6927cb
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
add_library(_jwt-cpp INTERFACE)
2+
target_include_directories(_jwt-cpp SYSTEM BEFORE INTERFACE "${ClickHouse_SOURCE_DIR}/contrib/jwt-cpp/include/")
3+
add_library(ch_contrib::jwt-cpp ALIAS _jwt-cpp)

docker/test/fasttest/run.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ function clone_submodules
155155
contrib/libfiu
156156
contrib/incbin
157157
contrib/yaml-cpp
158+
contrib/jwt-cpp
158159
)
159160

160161
git submodule sync

docs/en/operations/external-authenticators/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ The following external authenticators and directories are supported:
1616
- [LDAP](./ldap.md#external-authenticators-ldap) [Authenticator](./ldap.md#ldap-external-authenticator) and [Directory](./ldap.md#ldap-external-user-directory)
1717
- Kerberos [Authenticator](./kerberos.md#external-authenticators-kerberos)
1818
- [SSL X.509 authentication](./ssl-x509.md#ssl-external-authentication)
19-
- HTTP [Authenticator](./http.md)
19+
- HTTP [Authenticator](./http.md)
20+
- JWT [Authenticator](./jwt.md)
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
---
2+
slug: /en/operations/external-authenticators/jwt
3+
---
4+
# JWT
5+
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md';
6+
7+
<SelfManaged />
8+
9+
Existing and properly configured ClickHouse users can be authenticated via JWT.
10+
11+
Currently, JWT can only be used as an external authenticator for existing users, which are defined in `users.xml` or in local access control paths.
12+
The username will be extracted from the JWT after validating the token expiration and against the signature. Signature can be validated by:
13+
- static public key
14+
- static JWKS
15+
- received from the JWKS servers
16+
17+
It is mandatory for a JWT tot indicate the name of the ClickHouse user under `"sub"` claim, otherwise it will not be accepted.
18+
19+
A JWT may additionally be verified by checking the JWT payload.
20+
In this case, the occurrence of specified claims from the user settings in the JWT payload is checked.
21+
See [Enabling JWT authentication in `users.xml`](#enabling-jwt-auth-in-users-xml)
22+
23+
To use JWT authentication, JWT validators must be configured in ClickHouse config.
24+
25+
26+
## Enabling JWT validators in ClickHouse {#enabling-jwt-validators-in-clickhouse}
27+
28+
To enable JWT validators, add `jwt_validators` section in `config.xml`. This section may contain several JWT verifiers, minimum is 1.
29+
30+
### Verifying JWT signature using static key {$verifying-jwt-signature-using-static-key}
31+
32+
**Example**
33+
```xml
34+
<clickhouse>
35+
<!- ... -->
36+
<jwt_validators>
37+
<my_static_key_validator>
38+
<algo>HS256</algo>
39+
<static_key>my_static_secret</static_key>
40+
</my_static_key_validator>
41+
</jwt_validators>
42+
</clickhouse>
43+
```
44+
45+
#### Parameters:
46+
47+
- `algo` - Algorithm for validate signature. Supported:
48+
49+
| HMSC | RSA | ECDSA | PSS | EdDSA |
50+
| ----- | ----- | ------ | ----- | ------- |
51+
| HS256 | RS256 | ES256 | PS256 | Ed25519 |
52+
| HS384 | RS384 | ES384 | PS384 | Ed448 |
53+
| HS512 | RS512 | ES512 | PS512 | |
54+
| | | ES256K | | |
55+
Also support None.
56+
- `static_key` - key for symmetric algorithms. Mandatory for `HS*` family algorithms.
57+
- `static_key_in_base64` - indicates if the `static_key` key is base64-encoded. Optional, default: `False`.
58+
- `public_key` - public key for asymmetric algorithms. Mandatory except for `HS*` family algorithms and `None`.
59+
- `private_key` - private key for asymmetric algorithms. Optional.
60+
- `public_key_password` - public key password. Optional.
61+
- `private_key_password` - private key password. Optional.
62+
63+
### Verifying JWT signature using static JWKS {$verifying-jwt-signature-using-static-jwks}
64+
65+
:::note
66+
Only RS* family algorithms are supported!
67+
:::
68+
69+
**Example**
70+
```xml
71+
<clickhouse>
72+
<!- ... -->
73+
<jwt_validators>
74+
<my_static_jwks_validator>
75+
<static_jwks>{"keys": [{"kty": "RSA", "alg": "RS256", "kid": "mykid", "n": "_public_key_mod_", "e": "AQAB"}]}</static_jwks>
76+
</my_static_jwks_validator>
77+
</jwt_validators>
78+
</clickhouse>
79+
```
80+
81+
#### Parameters:
82+
- `static_jwks` - content of JWKS in json
83+
- `static_jwks_file` - path to file with JWKS
84+
85+
:::note
86+
Only one of `static_jwks` or `static_jwks_file` keys must be present in one verifier
87+
:::
88+
89+
### Verifying JWT signature using JWKS servers {$verifying-jwt-signature-using-static-jwks}
90+
91+
**Example**
92+
```xml
93+
<clickhouse>
94+
<!- ... -->
95+
<jwt_validators>
96+
<basic_auth_server>
97+
<uri>http://localhost:8000/.well-known/jwks.json</uri>
98+
<connection_timeout_ms>1000</connection_timeout_ms>
99+
<receive_timeout_ms>1000</receive_timeout_ms>
100+
<send_timeout_ms>1000</send_timeout_ms>
101+
<max_tries>3</max_tries>
102+
<retry_initial_backoff_ms>50</retry_initial_backoff_ms>
103+
<retry_max_backoff_ms>1000</retry_max_backoff_ms>
104+
<refresh_ms>300000</refresh_ms>
105+
</basic_auth_server>
106+
</jwt_validators>
107+
</clickhouse>
108+
```
109+
110+
#### Parameters:
111+
112+
- `uri` - JWKS endpoint. Mandatory.
113+
- `refresh_ms` - Period for resend request for refreshing JWKS. Optional, default: 300000.
114+
115+
Timeouts in milliseconds on the socket used for communicating with the server (optional):
116+
- `connection_timeout_ms` - Default: 1000.
117+
- `receive_timeout_ms` - Default: 1000.
118+
- `send_timeout_ms` - Default: 1000.
119+
120+
Retry parameters (optional):
121+
- `max_tries` - The maximum number of attempts to make an authentication request. Default: 3.
122+
- `retry_initial_backoff_ms` - The backoff initial interval on retry. Default: 50.
123+
- `retry_max_backoff_ms` - The maximum backoff interval. Default: 1000.
124+
125+
### Enabling JWT authentication in `users.xml` {#enabling-jwt-auth-in-users-xml}
126+
127+
In order to enable JWT authentication for the user, specify `jwt` section instead of `password` or other similar sections in the user definition.
128+
129+
Parameters:
130+
- `claims` - An optional string containing a json object that should be contained in the token payload.
131+
132+
Example (goes into `users.xml`):
133+
```xml
134+
<clickhouse>
135+
<!- ... -->
136+
<my_user>
137+
<!- ... -->
138+
<jwt>
139+
<claims>{"resource_access":{"account": {"roles": ["view-profile"]}}}</claims>
140+
</jwt>
141+
</my_user>
142+
</clickhouse>
143+
```
144+
145+
Here, the JWT payload must contain `["view-profile"]` on path `resource_access.account.roles`, otherwise authentication will not succeed even with a valid JWT.
146+
147+
```
148+
{
149+
...
150+
"resource_access": {
151+
"account": {
152+
"roles": ["view-profile"]
153+
}
154+
},
155+
...
156+
}
157+
```
158+
159+
:::note
160+
JWT authentication cannot be used together with any other authentication method. The presence of any other sections like `password` alongside `jwt` will force ClickHouse to shut down.
161+
:::
162+
163+
### Enabling JWT authentication using SQL {#enabling-jwt-auth-using-sql}
164+
165+
When [SQL-driven Access Control and Account Management](/docs/en/guides/sre/user-management/index.md#access-control) is enabled in ClickHouse, users identified by JWT authentication can also be created using SQL statements.
166+
167+
```sql
168+
CREATE USER my_user IDENTIFIED WITH jwt CLAIMS '{"resource_access":{"account": {"roles": ["view-profile"]}}}'
169+
```
170+
171+
Or without additional JWT payload checks:
172+
173+
```sql
174+
CREATE USER my_user IDENTIFIED WITH jwt
175+
```
176+
177+
## JWT authentication examples {#jwt-authentication-examples}
178+
179+
#### Console client
180+
181+
```
182+
clickhouse-client -jwt <token>
183+
```
184+
185+
#### HTTP requests
186+
187+
```
188+
curl 'http://localhost:8080/?' \
189+
-H 'Authorization: Bearer <TOKEN>' \
190+
-H 'Content type: text/plain;charset=UTF-8' \
191+
--data-raw 'SELECT current_user()'
192+
```
193+
:::note
194+
ClickHouse will look for a JWT token in (by priority):
195+
1. `X-ClickHouse-JWT-Token` header.
196+
2. `Authorization` header.
197+
3. `token` request parameter. In this case, the "Bearer" prefix should not exist.
198+
:::
199+
200+
### Passing session settings {#passing-session-settings}
201+
202+
If `settings_key` exists in the `jwt_validators` section or exists in the verifier section and the payload contains a sub-object of that `settings_key`, ClickHouse will attempt to parse its key:value pairs as string values ​​and set them as session settings for the currently authenticated user. If parsing fails, the JWT payload will be ignored.
203+
204+
The `settings_key` in the verifier section takes precedence over the `settings_key` from the `jwt_validators` section. If `settings_key` in the verifier section does not exist, the `settings_key` from the `jwt_validators` section will be used.

0 commit comments

Comments
 (0)