-
Notifications
You must be signed in to change notification settings - Fork 4
Token authentication -> edge #616
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: antalya
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,219 @@ | ||
--- | ||
slug: /en/operations/external-authenticators/jwt | ||
--- | ||
# JWT | ||
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md'; | ||
|
||
<SelfManaged /> | ||
|
||
Existing and properly configured ClickHouse users can be authenticated via JWT. | ||
|
||
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. | ||
The username will be extracted from the JWT after validating the token expiration and against the signature. Signature can be validated by: | ||
- static public key | ||
- static JWKS | ||
- received from the JWKS servers | ||
|
||
It is mandatory for a JWT tot indicate the name of the ClickHouse user under `"sub"` claim, otherwise it will not be accepted. | ||
|
||
A JWT may additionally be verified by checking the JWT payload. | ||
In this case, the occurrence of specified claims from the user settings in the JWT payload is checked. | ||
See [Enabling JWT authentication in `users.xml`](#enabling-jwt-auth-in-users-xml) | ||
|
||
To use JWT authentication, JWT validators must be configured in ClickHouse config. | ||
|
||
|
||
## Enabling JWT validators in ClickHouse {#enabling-jwt-validators-in-clickhouse} | ||
|
||
To enable JWT validators, add `token_validators` section in `config.xml`. This section may contain several JWT verifiers, minimum is 1. | ||
|
||
### Verifying JWT signature using static key {$verifying-jwt-signature-using-static-key} | ||
|
||
**Example** | ||
```xml | ||
<clickhouse> | ||
<!- ... --> | ||
<jwt_validators> | ||
<my_static_key_validator> | ||
<algo>HS256</algo> | ||
<static_key>my_static_secret</static_key> | ||
</my_static_key_validator> | ||
</jwt_validators> | ||
</clickhouse> | ||
``` | ||
|
||
#### Parameters: | ||
|
||
- `algo` - Algorithm for validate signature. Supported: | ||
|
||
| HMAC | RSA | ECDSA | PSS | EdDSA | | ||
|-------| ----- | ------ | ----- | ------- | | ||
| HS256 | RS256 | ES256 | PS256 | Ed25519 | | ||
| HS384 | RS384 | ES384 | PS384 | Ed448 | | ||
| HS512 | RS512 | ES512 | PS512 | | | ||
| | | ES256K | | | | ||
Also support None. | ||
- `static_key` - key for symmetric algorithms. Mandatory for `HS*` family algorithms. | ||
- `static_key_in_base64` - indicates if the `static_key` key is base64-encoded. Optional, default: `False`. | ||
- `public_key` - public key for asymmetric algorithms. Mandatory except for `HS*` family algorithms and `None`. | ||
- `private_key` - private key for asymmetric algorithms. Optional. | ||
- `public_key_password` - public key password. Optional. | ||
- `private_key_password` - private key password. Optional. | ||
|
||
### Verifying JWT signature using static JWKS {$verifying-jwt-signature-using-static-jwks} | ||
|
||
:::note | ||
Only RS* family algorithms are supported! | ||
::: | ||
|
||
**Example** | ||
```xml | ||
<clickhouse> | ||
<!- ... --> | ||
<jwt_validators> | ||
<my_static_jwks_validator> | ||
<static_jwks>{"keys": [{"kty": "RSA", "alg": "RS256", "kid": "mykid", "n": "_public_key_mod_", "e": "AQAB"}]}</static_jwks> | ||
</my_static_jwks_validator> | ||
</jwt_validators> | ||
</clickhouse> | ||
``` | ||
|
||
#### Parameters: | ||
- `static_jwks` - content of JWKS in json | ||
- `static_jwks_file` - path to file with JWKS | ||
|
||
:::note | ||
Only one of `static_jwks` or `static_jwks_file` keys must be present in one verifier | ||
::: | ||
|
||
### Verifying JWT signature using JWKS servers {$verifying-jwt-signature-using-static-jwks} | ||
|
||
**Example** | ||
```xml | ||
<clickhouse> | ||
<!- ... --> | ||
<jwt_validators> | ||
<basic_auth_server> | ||
<uri>http://localhost:8000/.well-known/jwks.json</uri> | ||
<connection_timeout_ms>1000</connection_timeout_ms> | ||
<receive_timeout_ms>1000</receive_timeout_ms> | ||
<send_timeout_ms>1000</send_timeout_ms> | ||
<max_tries>3</max_tries> | ||
<retry_initial_backoff_ms>50</retry_initial_backoff_ms> | ||
<retry_max_backoff_ms>1000</retry_max_backoff_ms> | ||
<refresh_ms>300000</refresh_ms> | ||
</basic_auth_server> | ||
</jwt_validators> | ||
</clickhouse> | ||
``` | ||
|
||
#### Parameters: | ||
|
||
- `uri` - JWKS endpoint. Mandatory. | ||
- `refresh_ms` - Period for resend request for refreshing JWKS. Optional, default: 300000. | ||
|
||
Timeouts in milliseconds on the socket used for communicating with the server (optional): | ||
- `connection_timeout_ms` - Default: 1000. | ||
- `receive_timeout_ms` - Default: 1000. | ||
- `send_timeout_ms` - Default: 1000. | ||
|
||
Retry parameters (optional): | ||
- `max_tries` - The maximum number of attempts to make an authentication request. Default: 3. | ||
- `retry_initial_backoff_ms` - The backoff initial interval on retry. Default: 50. | ||
- `retry_max_backoff_ms` - The maximum backoff interval. Default: 1000. | ||
|
||
### Verifying access tokens {$verifying-access-tokens} | ||
|
||
Access tokens that are not JWT (and thus no data can be extracted from the token directly) need to be resolved by external providers. | ||
|
||
**Example** | ||
```xml | ||
<clickhouse> | ||
<!- ... --> | ||
<access_token_processors> | ||
<my_access_token_processor> | ||
<provider>google</provider> | ||
</my_access_token_processor> | ||
</access_token_processors> | ||
</clickhouse> | ||
``` | ||
|
||
#### Parameters: | ||
|
||
- `provider` - name of provider that will be used for token processing. Mandatory parameter. Possible options: `google`. | ||
|
||
|
||
### Enabling JWT authentication in `users.xml` {#enabling-jwt-auth-in-users-xml} | ||
|
||
In order to enable JWT authentication for the user, specify `jwt` section instead of `password` or other similar sections in the user definition. | ||
|
||
Parameters: | ||
- `claims` - An optional string containing a json object that should be contained in the token payload. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If take me as reference customer and document reader, it's not clean, what exactly can be in payload. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, I inherited this thing, and I think I will remove it: it can be confusing indeed, and its use case is not obvious. Also, it makes code somewhat more complex |
||
|
||
Example (goes into `users.xml`): | ||
```xml | ||
<clickhouse> | ||
<!- ... --> | ||
<my_user> | ||
<!- ... --> | ||
<jwt> | ||
<claims>{"resource_access":{"account": {"roles": ["view-profile"]}}}</claims> | ||
</jwt> | ||
</my_user> | ||
</clickhouse> | ||
``` | ||
|
||
Here, the JWT payload must contain `["view-profile"]` on path `resource_access.account.roles`, otherwise authentication will not succeed even with a valid JWT. | ||
|
||
``` | ||
{ | ||
... | ||
"resource_access": { | ||
"account": { | ||
"roles": ["view-profile"] | ||
} | ||
}, | ||
... | ||
} | ||
``` | ||
|
||
:::note | ||
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. | ||
::: | ||
|
||
### Enabling JWT authentication using SQL {#enabling-jwt-auth-using-sql} | ||
|
||
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. | ||
|
||
```sql | ||
CREATE USER my_user IDENTIFIED WITH jwt CLAIMS '{"resource_access":{"account": {"roles": ["view-profile"]}}}' | ||
``` | ||
|
||
Or without additional JWT payload checks: | ||
|
||
```sql | ||
CREATE USER my_user IDENTIFIED WITH jwt | ||
``` | ||
|
||
## JWT authentication examples {#jwt-authentication-examples} | ||
|
||
#### Console client | ||
|
||
``` | ||
clickhouse-client -jwt <token> | ||
``` | ||
|
||
#### HTTP requests | ||
|
||
``` | ||
curl 'http://localhost:8080/?' \ | ||
-H 'Authorization: Bearer <TOKEN>' \ | ||
-H 'Content type: text/plain;charset=UTF-8' \ | ||
--data-raw 'SELECT current_user()' | ||
``` | ||
:::note | ||
ClickHouse will look for a JWT token in (by priority): | ||
1. `X-ClickHouse-JWT-Token` header. | ||
2. `Authorization` header. | ||
3. `token` request parameter. In this case, the "Bearer" prefix should not exist. | ||
::: |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
--- | ||
slug: /en/operations/external-authenticators/oauth | ||
title: "OAuth 2.0" | ||
--- | ||
import SelfManaged from '@site/docs/en/_snippets/_self_managed_only_no_roadmap.md'; | ||
|
||
<SelfManaged /> | ||
|
||
OAuth 2.0 access tokens can be used to authenticate ClickHouse users. This works in two ways: | ||
|
||
- Existing users (defined in `users.xml` or in local access control paths) can be authenticated with access token if this user can be `IDENTIFIED WITH jwt`. | ||
- Use Identity Provider (IdP) as an external user directory and allow locally undefined users to be authenticated with a token if it is valid and recognized by the provider. | ||
|
||
Though this authentication method is different from JWT authentication, it works under the same authentication method to maintain better compatibility. | ||
|
||
For both of these approaches a definition of `access_token_processors` is mandatory. | ||
|
||
## Access Token Processors | ||
|
||
To define an access token processor, add `access_token_processors` section to `config.xml`. Example: | ||
```xml | ||
<clickhouse> | ||
<access_token_processors> | ||
<gogoogle> | ||
<provider>Google</provider> | ||
<email_filter>^[A-Za-z0-9._%+-]+@example\.com$</email_filter> | ||
<cache_lifetime>600</cache_lifetime> | ||
</gogoogle> | ||
<azuure> | ||
<provider>azure</provider> | ||
<client_id>CLIENT_ID</client_id> | ||
<tenant_id>TENANT_ID</tenant_id> | ||
</azuure> | ||
</access_token_processors> | ||
</clickhouse> | ||
``` | ||
|
||
:::note | ||
Different providers have different sets of parameters. | ||
::: | ||
|
||
**Parameters** | ||
|
||
- `provider` -- name of identity provider. Mandatory, case-insensitive. Supported options: "Google", "Azure". | ||
- `cache_lifetime` -- maximum lifetime of cached token (in seconds). Optional, default: 3600. | ||
- `email_filter` -- Regex for validation of user emails. Optional parameter, only for Google IdP. | ||
- `client_id` -- Azure AD (Entra ID) client ID. Optional parameter, only for Azure IdP. | ||
- `tenant_id` -- Azure AD (Entra ID) tenant ID. Optional parameter, only for Azure IdP. | ||
|
||
### Tokens cache | ||
To reduce number of requests to IdP, tokens are cached internally for no longer then `cache_lifetime` seconds. | ||
If token expires sooner than `cache_lifetime`, then cache entry for this token will only be valid while token is valid. | ||
If token lifetime is longer than `cache_lifetime`, cache entry for this token will be valid for `cache_lifetime`. | ||
|
||
## IdP as External Authenticator {#idp-external-authenticator} | ||
|
||
Locally defined users can be authenticated with an access token. To allow this, `jwt` must be specified as user's authentication method. Example: | ||
|
||
```xml | ||
<clickhouse> | ||
<!- ... --> | ||
<users> | ||
<!- ... --> | ||
<my_user> | ||
<!- ... --> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
</jwt> | ||
</my_user> | ||
</users> | ||
</clickhouse> | ||
``` | ||
|
||
At each login attempt, ClickHouse will attempt to validate token and get user info against every defined access token provider. | ||
|
||
When SQL-driven [Access Control and Account Management](/docs/en/guides/sre/user-management/index.md#access-control) is enabled, users that are authenticated with tokens can also be created using the [CREATE USER](/docs/en/sql-reference/statements/create/user.md#create-user-statement) statement. | ||
|
||
Query: | ||
|
||
```sql | ||
CREATE USER my_user IDENTIFIED WITH jwt; | ||
``` | ||
|
||
## Identity Provider as an External User Directory {#idp-external-user-directory} | ||
|
||
If there is no suitable user pre-defined in ClickHouse, authentication is still possible: Identity Provider can be used as source of user information. | ||
To allow this, add `token` section to the `users_directories` section of the `config.xml` file. | ||
|
||
At each login attempt, ClickHouse tries to find the user definition locally and authenticate it as usual. | ||
If the user is not defined, ClickHouse will treat user as externally defined, and will try to validate the token and get user information from the specified processor. | ||
If validated successfully, the user will be considered existing and authenticated. The user will be assigned roles from the list specified in the `roles` section. | ||
All this implies that the SQL-driven [Access Control and Account Management](/docs/en/guides/sre/user-management/index.md#access-control) is enabled and roles are created using the [CREATE ROLE](/docs/en/sql-reference/statements/create/role.md#create-role-statement) statement. | ||
|
||
**Example** | ||
|
||
```xml | ||
<clickhouse> | ||
<token> | ||
<processor>gogoogle</processor> | ||
<roles> | ||
<token_test_role_1 /> | ||
</roles> | ||
</token> | ||
</clickhouse> | ||
``` | ||
|
||
**Parameters** | ||
|
||
- `server` — Name of one of processors defined in `access_token_processors` config section described above. This parameter is mandatory and cannot be empty. | ||
- `roles` — Section with a list of locally defined roles that will be assigned to each user retrieved from the IdP. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"and 'azure'"