Skip to content

Commit 108d473

Browse files
Adam Lockeelasticmachinejustincr-elastic
authored
[DOCS] JWT doc enhancements (#86411) (#87394)
* [DOCS] Add examples for run-as privileges * Add JWT run_as and realm examples * Adding examples for run_as, moving that section, and other 🔥 edits * Add section headers 🖍️ * Incorporate Justin's suggestions from code review Co-authored-by: Justin Cranford <[email protected]> * Edits and clarifications based on reviewer feedback. * Clarify run_as privilege in roles * Fix typo * Add redirect to fix cross-book linking * Expand the run_as examples * Update request * Remove NOTCONSOLE from curl commands * Update run_as example and expand section on unsupported realms * Split note for unsupported realms * Remove note that OAuth2 tokens aren't supported and clarify run_as from unsupported realms * Apply Justin's suggestions from code review Co-authored-by: Justin Cranford <[email protected]> * Update support for different authentication mechanisms * Apply suggestions from code review Co-authored-by: Justin Cranford <[email protected]> * Add note from review, cleanup, and typo fixes Co-authored-by: Elastic Machine <[email protected]> Co-authored-by: Justin Cranford <[email protected]> Co-authored-by: Elastic Machine <[email protected]> Co-authored-by: Justin Cranford <[email protected]>
1 parent 55afb10 commit 108d473

File tree

4 files changed

+376
-59
lines changed

4 files changed

+376
-59
lines changed

docs/reference/redirects.asciidoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33

44
The following pages have moved or been deleted.
55

6+
[role="exclude",id="jwt-realm"]
7+
=== JWT realm
8+
9+
Refer to <<jwt-auth-realm,JWT authentication>>.
10+
11+
[role="exclude",id="_authorizing_with_the_role_mapping_api"]
12+
==== Role mapping with JWT
13+
14+
Refer to <<jwt-authorization-role-mapping,Authorizing with the role mapping API>>.
15+
616
[role="exclude",id="migration-api-feature-upgrade"]
717
=== Feature upgrade APIs
818

docs/reference/settings/security-settings.asciidoc

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,9 +2180,11 @@ for every request, set to `0` to disable the JWT cache. Defaults to `20m`.
21802180
// tag::jwt-pkc-jwkset-path-tag[]
21812181
`pkc_jwkset_path` {ess-icon}::
21822182
(<<static-cluster-setting,Static>>)
2183-
The file path or URL to a JSON Web Key Set with the public key material that
2183+
The file path or URL to a JSON Web Key Set (JWKS) with the public key material that
21842184
the JWT Realm uses for verifying token signatures. If a path is provided,
2185-
then it is resolved relative to the {es} configuration directory.
2185+
then it is resolved relative to the {es} configuration directory. In {ecloud},
2186+
use an absolute path starting with `/app/config/`.
2187+
+
21862188
If a URL is provided, then it must be either a `file` URL or an `https` URL.
21872189
{es} automatically caches the retrieved JWK set to avoid unnecessary HTTP
21882190
requests, but will attempt to refresh the JWK upon signature verification

x-pack/docs/en/security/authentication/jwt-realm.asciidoc

Lines changed: 156 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[role="xpack"]
2-
[[jwt-realm]]
2+
[[jwt-auth-realm]]
33
=== JWT authentication
44

55
beta::[]
@@ -40,22 +40,17 @@ way to enable OIDC authentication in {kib}.
4040
[[jwt-realm-configuration]]
4141
==== Configure {es} to use a JWT realm
4242

43-
To use JWT authentication, you create the realm in the `elasticsearch.yml` file
43+
To use JWT authentication, create the realm in the `elasticsearch.yml` file
4444
to configure it within the {es} authentication chain.
4545

4646
The JWT realm has a few mandatory settings, plus optional settings that are
47-
described in <<ref-jwt-settings,JWT realm settings>>. The following example
48-
includes the most common settings. After defining settings, use the
49-
{ref}/elasticsearch-keystore.html[`elasticsearch-keystore`] tool to store
50-
values in the {es} keystore.
51-
52-
NOTE: The example values are not intended for every use case, and are included
53-
only to highlight some common settings for this realm.
47+
described in <<ref-jwt-settings,JWT realm settings>>.
5448

55-
Client authentication is enabled by default for the JWT realms. Disabling client
56-
authentication is possible, but strongly discouraged.
49+
NOTE: Client authentication is enabled by default for the JWT realms. Disabling
50+
client authentication is possible, but strongly discouraged.
5751

58-
. Add your JWT realm to the `elasticsearch.yml` file:
52+
. Add your JWT realm to the `elasticsearch.yml` file. The following example
53+
includes the most common settings, which are not intended for every use case:
5954
+
6055
--
6156
[source,yaml]
@@ -97,36 +92,41 @@ verify the signature of the JWT from the JWT issuer.
9792
`pkc_jwkset_path`::
9893
The file path to a JSON Web Key Set (JWKS) containing the public key material
9994
that the JWT realm uses to verify JWT signatures. If a path is provided,
100-
then it is resolved relative to the {es} configuration directory.
95+
then it is resolved relative to the {es} configuration directory. In {ecloud},
96+
use an absolute path starting with `/app/config/`.
10197

10298
`claims.principal`::
10399
The name of the JWT claim that contains the user's principal (username).
104100

105101
--
106102

107-
. Store the `shared_secret` value for `client_authentication.type`:
103+
. After defining settings, use the
104+
{ref}/elasticsearch-keystore.html[`elasticsearch-keystore`] tool to store
105+
values for secure settings in the {es} keystore.
106+
107+
.. Store the `shared_secret` value for `client_authentication.type`:
108108
+
109109
[source,shell]
110110
----
111111
bin/elasticsearch-keystore add xpack.security.authc.realms.jwt.jwt1.client_authentication.shared_secret
112112
----
113113

114-
. Store the HMAC keys for `allowed_signature_algorithms`, which use the HMAC
114+
.. Store the HMAC keys for `allowed_signature_algorithms`, which use the HMAC
115115
SHA-256 algorithm `HS256` in the example:
116116
+
117117
[source,shell]
118118
----
119119
bin/elasticsearch-keystore add-file xpack.security.authc.realms.jwt.jwt1.hmac_jwkset <path> <1>
120120
----
121121
<1> Path to a JWKS, which is a resource for a set of JSON-encoded secret keys.
122-
The file can be removed after the contents are loaded into the {es} keystore setting.
122+
The file can be removed after you load the contents into the {es} keystore.
123123
+
124124
[NOTE]
125125
====
126-
Using the JWK Set is preferred. However, you can add an HMAC key in string format
126+
Using the JWKS is preferred. However, you can add an HMAC key in string format
127127
using the following command. This format is compatible with OIDC HMAC keys, but
128128
only supports a single key with no attributes. You can only use one HMAC format
129-
simultaneously.
129+
(either `hmac_jwkset` or `hmac_key`) simultaneously.
130130
131131
[source,shell]
132132
----
@@ -158,12 +158,14 @@ Signature: UnnFmsoFKfNmKMsVoDQmKI_3-j95PCaKdgqqau3jPMY
158158
This example illustrates a partial decoding of a JWT. The validity period is
159159
from 2000 to 2099 (inclusive), as defined by the issue time (`iat`) and
160160
expiration time (`exp`). JWTs typically have a validity period shorter than
161-
100 years. The signature in this example is deterministic because the header,
162-
claims, and HMAC key are fixed.
161+
100 years, such as 1-2 hours or 1-7 days, not an entire human life.
163162

164-
The supported JWT encoding is JSON Web Signature (JWS). The JWS `Header` and
165-
`Signature` are validated using OpenID Connect ID Token validation rules. Some
166-
validation is customizable through <<ref-jwt-settings,JWT realm settings>>.
163+
The signature in this example is deterministic because the header, claims, and
164+
HMAC key are fixed. JWTs typically have a `nonce` claim to make the signature
165+
non-deterministic. The supported JWT encoding is JSON Web Signature (JWS), and
166+
the JWS `Header` and `Signature` are validated using OpenID Connect ID Token
167+
validation rules. Some validation is customizable through
168+
<<ref-jwt-settings,JWT realm settings>>.
167169

168170
[[jwt-validation-header]]
169171
===== Header claims
@@ -256,15 +258,18 @@ setting `claims.dn_pattern` to extract a substring value.
256258
[[jwt-authorization]]
257259
==== JWT realm authorization
258260
The JWT realm supports authorization with the create or update role mappings API,
259-
as well as delegating authorization to another realm.
261+
or delegating authorization to another realm. You cannot use these methods
262+
simultaneously, so choose whichever works best for your environment.
260263

261264
IMPORTANT: You cannot map roles in the JWT realm using the `role_mapping.yml`
262265
file.
263266

267+
[[jwt-authorization-role-mapping]]
264268
===== Authorizing with the role mapping API
265269
You can use the
266270
<<security-api-put-role-mapping,create or update role mappings API>> to define
267-
role mappings in the JWT realm:
271+
role mappings that determine which roles should be assigned to each user based on
272+
their username, groups, or other metadata.
268273

269274
[source,console]
270275
----
@@ -301,14 +306,15 @@ boolean values, and collections that are used as the {es} user's metadata.
301306
These values are key value pairs formatted as
302307
`metadata.jwt_claim_<key>` = `<value>`.
303308

309+
[[jwt-authorization-delegation]]
304310
===== Delegating JWT authorization to another realm
305-
If you <<authorization_realms,delegate authorization>> to another realm from the
311+
If you <<authorization_realms,delegate authorization>> to other realms from the
306312
JWT realm, only the `principal` claim is available for role lookup. When
307313
delegating the assignment and lookup of roles to another realm from the JWT
308314
realm, claims for `dn`, `groups`, `mail`, `metadata`, and `name` are not used
309315
for the {es} user's values. Only the JWT `principal` claim is passed to the
310-
delegated authorization realm. The realm that is delegated for authorization
311-
- not the JWT realm - becomes responsible for populating all of the {es} user's
316+
delegated authorization realms. The realms that are delegated for authorization
317+
- not the JWT realm - become responsible for populating all of the {es} user's
312318
values.
313319

314320
The following example shows how you define delegation authorization in the
@@ -344,11 +350,99 @@ If realm `jwt2` successfully authenticates a client with a JWT for principal
344350
this defined role mapping, the realm can also look up this role mapping rule
345351
linked to realm `native1`.
346352

353+
[[jwt-realm-runas]]
354+
===== Applying the `run_as` privilege to JWT realm users
355+
{es} can retrieve roles for a JWT user through either role mapping or
356+
delegated authorization. Regardless of which option you choose, you can apply the
357+
<<run-as-privilege-apply,`run_as` privilege>> to a role so that a user can
358+
submit authenticated requests to "run as" a different user. To submit requests as
359+
another user, include the `es-security-runas-user` header in your requests.
360+
Requests run as if they were issued from that user and {es} uses their roles.
361+
362+
For example, let's assume that there's a user with the username `user123_runas`.
363+
The following request creates a user role named `jwt_role1`, which specifies a
364+
`run_as` user with the `user123_runas` username. Any user with the `jwt_role1`
365+
role can issue requests as the specified `run_as` user.
366+
367+
[source,console]
368+
----
369+
POST /_security/role/jwt_role1?refresh=true
370+
{
371+
"cluster": ["manage"],
372+
"indices": [ { "names": [ "*" ], "privileges": ["read"] } ],
373+
"run_as": [ "user123_runas" ],
374+
"metadata" : { "version" : 1 }
375+
}
376+
----
377+
378+
You can then map that role to a user in a specific realm. The following request
379+
maps the `jwt_role1` role to a user with the username `user2` in the `jwt2` JWT
380+
realm. This means that {es} will use the `jwt2` realm to authenticate the user
381+
named `user2`. Because `user2` has a role (the `jwt_role1` role) that includes
382+
the `run_as` privilege, {es} retrieves the role mappings for the `user123_runas`
383+
user and uses the roles for that user to submit requests.
384+
385+
[source,console]
386+
----
387+
POST /_security/role_mapping/jwt_user1?refresh=true
388+
{
389+
"roles": [ "jwt_role1"],
390+
"rules" : { "all" : [
391+
{ "field": { "realm.name": "jwt2" } },
392+
{ "field": { "username": "user2" } }
393+
] },
394+
"enabled": true,
395+
"metadata" : { "version" : 1 }
396+
}
397+
----
398+
399+
After mapping the roles, you can make an
400+
<<security-api-authenticate,authenticated call>> to {es} using a JWT and include
401+
the `ES-Client-Authentication` header:
402+
403+
[source,sh]
404+
----
405+
curl -s -X GET -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiZXMwMSIsImVzMDIiLCJlczAzIl0sInN1YiI6InVzZXIyIiwiaXNzIjoibXktaXNzdWVyIiwiZXhwIjo0MDcwOTA4ODAwLCJpYXQiOjk0NjY4NDgwMCwiZW1haWwiOiJ1c2VyMkBzb21ldGhpbmcuZXhhbXBsZS5jb20ifQ.UgO_9w--EoRyUKcWM5xh9SimTfMzl1aVu6ZBsRWhxQA" -H "ES-Client-Authentication: sharedsecret test-secret" https://localhost:9200/_security/_authenticate
406+
----
407+
// NOTCONSOLE
408+
409+
The response includes the user who submitted the request (`user2`), including
410+
the `jwt_role1` role that you mapped to this user in the JWT realm:
411+
412+
[source,sh]
413+
----
414+
{"username":"user2","roles":["jwt_role1"],"full_name":null,"email":"[email protected]",
415+
"metadata":{"jwt_claim_email":"[email protected]","jwt_claim_aud":["es01","es02","es03"],
416+
"jwt_claim_sub":"user2","jwt_claim_iss":"my-issuer"},"enabled":true,"authentication_realm":
417+
{"name":"jwt2","type":"jwt"},"lookup_realm":{"name":"jwt2","type":"jwt"},"authentication_type":"realm"}
418+
%
419+
----
420+
421+
If you want to specify a request as the `run_as` user, include the
422+
the `es-security-runas-user` header with the name of the user that you
423+
want to submit requests as. The following request uses the `user123_runas` user:
424+
425+
[source,sh]
426+
----
427+
curl -s -X GET -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiZXMwMSIsImVzMDIiLCJlczAzIl0sInN1YiI6InVzZXIyIiwiaXNzIjoibXktaXNzdWVyIiwiZXhwIjo0MDcwOTA4ODAwLCJpYXQiOjk0NjY4NDgwMCwiZW1haWwiOiJ1c2VyMkBzb21ldGhpbmcuZXhhbXBsZS5jb20ifQ.UgO_9w--EoRyUKcWM5xh9SimTfMzl1aVu6ZBsRWhxQA" -H "ES-Client-Authentication: sharedsecret test-secret" -H "es-security-runas-user: user123_runas" https://localhost:9200/_security/_authenticate
428+
----
429+
// NOTCONSOLE
430+
431+
In the response, you'll see that the `user123_runas` user submitted the request,
432+
and {es} used the `jwt_role1` role:
433+
434+
[source,sh]
435+
----
436+
{"username":"user123_runas","roles":["jwt_role1"],"full_name":null,"email":null,"metadata":{},
437+
"enabled":true,"authentication_realm":{"name":"jwt2","type":"jwt"},"lookup_realm":{"name":"native",
438+
"type":"native"},"authentication_type":"realm"}%
439+
----
440+
347441
[[hmac-oidc-example]]
348442
==== Authorizing to the JWT realm with an OIDC HMAC key
349443
The following settings are for a JWT issuer, {es}, and a client of {es}. The
350-
example HMAC key is in an OIDC HMAC compatible format. The key bytes are the
351-
UTF-8 encoding of the UNICODE characters.
444+
example HMAC key is in an OIDC format that's compatible with HMAC. The key bytes
445+
are the UTF-8 encoding of the UNICODE characters.
352446

353447
IMPORTANT: HMAC UTF-8 keys need to be longer than HMAC random byte keys to
354448
achieve the same key strength.
@@ -368,21 +462,25 @@ HMAC OIDC: hmac-oidc-key-string-for-hs256-algorithm
368462

369463
[[hmac-oidc-example-jwt-realm]]
370464
===== JWT realm settings
371-
The following settings are for `elasticsearch.yml`.
465+
To define a JWT realm, add the following realm settings to `elasticsearch.yml`.
372466

373467
[source,yaml]
374468
----
375-
xpack.security.authc.realms.jwt.jwt8.order: 8
469+
xpack.security.authc.realms.jwt.jwt8.order: 8 <1>
376470
xpack.security.authc.realms.jwt.jwt8.allowed_issuer: iss8
377471
xpack.security.authc.realms.jwt.jwt8.allowed_audiences: [aud8]
378472
xpack.security.authc.realms.jwt.jwt8.allowed_signature_algorithms: [HS256]
379473
xpack.security.authc.realms.jwt.jwt8.claims.principal: sub
380474
xpack.security.authc.realms.jwt.jwt8.client_authentication.type: shared_secret
381475
----
476+
<1> In {ecloud}, the realm order starts at `2`. `0` and `1` are reserved in the
477+
realm chain on {ecloud}.
382478

383479
===== JWT realm secure settings
384-
The following secure settings are for the
385-
{ref}/elasticsearch-keystore.html[`elasticsearch-keystore`].
480+
After defining the realm settings, use the
481+
{ref}/elasticsearch-keystore.html[`elasticsearch-keystore`] tool to add the
482+
following secure settings to the {es} keystore. In {ecloud}, you define settings
483+
for the {es} keystore under **Security** in your deployment.
386484

387485
[source,yaml]
388486
----
@@ -413,7 +511,30 @@ The following header settings are for an {es} client.
413511

414512
[source,js]
415513
----
416-
ES-Client-Authentication: SharedSecret client-shared-secret-string
417514
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3M4IiwiYXVkIjoiYXVkOCIsInN1YiI6InNlY3VyaXR5X3Rlc3RfdXNlciIsImV4cCI6NDA3MDkwODgwMCwiaWF0Ijo5NDY2ODQ4MDB9.UnnFmsoFKfNmKMsVoDQmKI_3-j95PCaKdgqqau3jPMY
515+
ES-Client-Authentication: SharedSecret client-shared-secret-string
516+
----
517+
// NOTCONSOLE
518+
519+
You can use this header in a `curl` request to make an authenticated call to
520+
{es}. Both the bearer token and the client authorization token must be
521+
specified as separate headers with the `-H` option:
522+
523+
[source,sh]
524+
----
525+
curl -s -X GET -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJpc3M4IiwiYXVkIjoiYXVkOCIsInN1YiI6InNlY3VyaXR5X3Rlc3RfdXNlciIsImV4cCI6NDA3MDkwODgwMCwiaWF0Ijo5NDY2ODQ4MDB9.UnnFmsoFKfNmKMsVoDQmKI_3-j95PCaKdgqqau3jPMY" -H "ES-Client-Authentication: SharedSecret client-shared-secret-string" https://localhost:9200/_security/_authenticate
418526
----
419527
// NOTCONSOLE
528+
529+
If you used role mapping in the JWT realm, the response includes the user's
530+
`username`, their `roles`, metadata about the user, and the details about the
531+
JWT realm itself.
532+
533+
[source,sh]
534+
----
535+
{"username":"user2","roles":["jwt_role1"],"full_name":null,"email":"[email protected]",
536+
"metadata":{"jwt_claim_email":"[email protected]","jwt_claim_aud":["es01","es02","es03"],
537+
"jwt_claim_sub":"user2","jwt_claim_iss":"my-issuer"},"enabled":true,"authentication_realm":
538+
{"name":"jwt2","type":"jwt"},"lookup_realm":{"name":"jwt2","type":"jwt"},"authentication_type":"realm"}
539+
%
540+
----

0 commit comments

Comments
 (0)