File: jwt.shtml

package info (click to toggle)
slurm-wlm-contrib 24.11.5-4
  • links: PTS, VCS
  • area: contrib
  • in suites: forky
  • size: 50,600 kB
  • sloc: ansic: 529,598; exp: 64,795; python: 17,051; sh: 9,411; javascript: 6,528; makefile: 4,030; perl: 3,762; pascal: 131
file content (305 lines) | stat: -rw-r--r-- 12,505 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
<!--#include virtual="header.txt"-->

<h1>JSON Web Tokens (JWT) Authentication</h1>

<p>Slurm provides a
<a href="https://datatracker.ietf.org/doc/html/rfc7519">RFC7519</a> compliant
implementation of <a href="https://jwt.io/">JSON Web Tokens (JWT)</a>. This
authentication can be used as an <b>AuthAltType</b>, usually alongside
<b>auth/munge</b> as the <b>AuthType</b>. The only supported communication
direction is from a client connecting to <b>slurmctld</b> and <b>slurmdbd</b>.
This means that certain scenarios (specifically interactive jobs using
<b>srun</b>) are currently not supported for clients with auth/jwt enabled (or
that have SLURM_JWT in their environment).</p>

<h2 id="prerequisites">Prerequisites
<a class="slurm_link" href="#prerequisites"></a>
</h2>
<p>JWT requires <a href="related_software.html#jwt">libjwt</a>.
Both the library and the development headers must be available when Slurm is
compiled.</p>

<h2 id="trust_jwt_create">Full root trust in JWT creation
<a class="slurm_link" href="#trust_jwt_create"></a>
</h2>
<p>The power to create JWTs is the power of root on a cluster. This is a
per-site decision on what/who/when/how to trust. If a given authentication
system can not be fully trusted with the powers of root for the entire cluster,
then an authenticating proxy will need to be used to divide up the trust and
implement the site's specific policies before the requests reach Slurm
(specifically slurmrestd). While possibly inefficient, there is no technical
reason that tiers of authenticating proxies can not be used if there is a lack
of trust but a desire to allow creation of lesser auth tokens. Each site will
need to weight the risks and benefits of which JWTs to trust before implementing
any system. Once a job has been queued, the proxied authentication system will
no longer be involved and the job will run with that user's permissions and
access per Linux/POSIX's ACLs and trusts.</p>

<h2 id="models_trust">Models of trust
<a class="slurm_link" href="#models_trust"></a>
</h2>
<p>There are several ways to handle controlling JWT authentication and access.
Slurm JWT plugin implementation is purposefully simple and will not be able to
support most models of trust needed by sites. There already exists a plethora of
authentication systems, and the expectation is that any site that wants more
complexity than the default offering will use one of those systems instead.</p>

<ul>
<li><a href="#compatibility">External JWT generation</a>
<p>We provide an example python script for generating new JWTs but they are a
standard and most languages have existing tooling for them. This is usually the
easiest route for sites but does require each site to implement the tooling for
their users directly.</p></li>

<li>Authenticating proxy
<p>This is the most versatile option, as any authentication system can be
placed in front of slurmrestd. It requires creating a slurmuser/root token that
can then be used to proxy for any user. There are existing solutions for this
with Nginx and Apache, and probably every other non-trivial proxy. We suggest
choosing the preferred proxy and finding an existing setup guide for
authenticating via that proxy. The proxy will need to have the
<b>X-SLURM-USER-TOKEN</b> and <b>X-SLURM-USER-NAME</b> headers defined.</p>

<p>There is no requirement that an authenticating proxy implement JWT for
clients. This is the primary benefit of authenticating proxies; they can use
any authentication method since they are the trusted point that tells Slurm
which user the request is from. These authentication tokens are only used by
the proxy and are not passed to the job. This is generally not an
issue as once the job is in Slurm, it runs as the Posix user with all of the
inherent trust of that user and it then uses <code>auth/munge</code> or
<code>auth/slurm</code> for everything after that.</p></li>

<li><a href="#external_auth">JWKS</a>
<p>This is like an authentication proxy, as another system is used to create the
tokens, but it skips having the authentication system in front of Slurm by using
signed public keys. This tends to be the preferred solution for sites using
cloud authentication systems, such as:
<ul>
<li><a href="https://aws.amazon.com/blogs/hpc/using-the-slurm-rest-api-to-integrate-with-distributed-architectures-on-aws/">
Amazon Cognito</a></li>
<li><a href="https://www.keycloak.org/">Keycloak</a> - Using keycloak is an
option which doesn't require a cloud auth solution.</li>
</ul>
</p></li>
</ul>

<h2 id="setup">Setup for Standalone Use
<a class="slurm_link" href="#setup"></a>
</h2>
<ol>
<li><a href="related_software.html#jwt">
    Configure and build Slurm with JWT support</a></li>
<li>Add the same JWT key to both the controller and slurmdbd (if used). For the
controller only, it is recommended to put the JWT key in the StateSaveLocation.
For example, using /var/spool/slurm/statesave/:
<pre>
dd if=/dev/random of=/var/spool/slurm/statesave/jwt_hs256.key bs=32 count=1
chown slurm:slurm /var/spool/slurm/statesave/jwt_hs256.key
chmod 0600 /var/spool/slurm/statesave/jwt_hs256.key
chown slurm:slurm /var/spool/slurm/statesave
chmod 0755 /var/spool/slurm/statesave
</pre>
The key does not have to be in the StateSaveLocation, but that is a convenient
location if you have multiple controllers since it is shared between them.
The key should not be placed in a directory where non-admin users might be
able to access it.
The key file should be owned by <b>SlurmUser</b> or <b>root</b>, with
recommended permissions of 0400. The file must not be accessible by 'other'.
</li>
<li>In both slurm.conf and slurmdbd.conf, add JWT as an alternative
authentication type:
<pre>
AuthAltTypes=auth/jwt
AuthAltParameters=jwt_key=/var/spool/slurm/statesave/jwt_hs256.key
</pre>
</li>
<li>Restart slurmctld</li>
<li>Create tokens for users as desired:
<pre>
scontrol token username=$USER
</pre>
An optional <b>lifespan=$LIFESPAN</b> option can be used to change the token
lifespan from the default 1800 seconds. The root account, or <b>SlurmUser</b>
account can be used to generate tokens for any user. Alternatively, a user
may use the command to generate tokens for themselves by simply calling
<pre>
scontrol token
</pre>
Note that administrators can prevent users from generating tokens by setting
the following parameter in slurm.conf:
<pre>
AuthAltParameters=disable_token_creation
</pre>
This functionality is provided to allow sites to control when and how users are
provided tokens along with controlling the token lifespans.
</li>
<li>Export the <b>SLURM_JWT</b> environment variable before calling any Slurm
command.</li>
<li>Export the <b>SLURM_JWT=daemon</b> environment variable before starting
the slurmrestd daemon to activate <i>AuthAltTypes=auth/jwt</i> as the primary
authentication mechanism.</li>
</ol>

<h2 id="external_auth">
External Authentication Integration with JWKS and RS256 Tokens
<a class="slurm_link" href="#external_auth"></a>
</h2>
<p>Starting with the 21.08 release, Slurm can support RS256 tokens such as
those generated by
<a href="https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html">Amazon Cognito</a>,
<a href="https://azure.github.io/azure-workload-identity/docs/installation/self-managed-clusters/oidc-issuer/jwks.html">Azure AD</a>, or
<a href="https://www.keycloak.org/docs/latest/securing_apps/#_client_authentication_adapter">Keycloak</a>.
</p>

<p>To enable Slurm's RS256 token support, an appropriate JWKS file must be
downloaded and configured as such:
<pre>
AuthAltTypes=auth/jwt
AuthAltParameters=jwks=/var/spool/slurm/statesave/jwks.json
</pre>
</p>

<p>The jwks file should be owned by <b>SlurmUser</b> or <b>root</b>, must be
readable by <b>SlurmUser</b>, with recommended permissions of 0400.
The file must not be writable by 'other'.</p>
<p>Note that, by default, the built-in ability to generate HS256 tokens will
be disabled when JWKS support is enabled. It can be re-enabled by explicitly
configuring the <b>jwt_key=</b> option alongside <b>jwks=</b>.
</p>
<p>Note: Slurm ignores the <b>x5c</b> and <b>x5t</b> fields and does not
attempt to verify the certificate chain if presented in the JWKS file. JWTs are
only verified against RSA 256 bit keys provided via <b>e</b> and
<b>n</b> fields.
</p>
<p>JWKS has signing keys that receive trust by being placed in the
jwks.json. Those trusted keys can then create new tokens (which are JWTs) for
any user by signing them. JWKS does not support adding keys for individual
users but only for adding trusted signing keys.
</p>
<p>JWT and JWKS can coexist in Slurm. Slurm will auto-disable JWT when
JWKS is configured as a safety mechanism, to avoid accidentally having both
enabled at the same time.
</p>

<h3 id="user_mapping">User Mapping
<a class="slurm_link" href="#user_mapping"></a></h3>

<p>Depending on the service used to generate tokens, you may run into issues
mapping the token to a username. Slurm defaults to using the <code>sun</code>
(Slurm UserName) field. If the service uses a different field, you will need to
correct this for it to work with Slurm.</p>

<p><b>Option 1</b>: Change Slurm to use a different field. This can be
customized using <a href="slurm.conf.html#OPT_userclaimfield=">
AuthAltParameters=userclaimfield</a>. For example, using the default field
for <a href="https://www.keycloak.org/">KeyCloak</a>:
<pre>
AuthAltParameters=jwks=/local/path/to/jwks.json,userclaimfield=preferred_username
</pre>
</p>

<p><b>Option 2</b>: Change the identity service to use a different field. In
KeyCloak 25.0, for example, you should find this option under <b>Clients ->
Client details -> Dedicated scopes -> Mapper details</b>. Change the username
mapping to use the <code>sun</code> field.</p>

<h2 id="compatibility">Compatibility
<a class="slurm_link" href="#compatibility"></a>
</h2>
Slurm uses libjwt to view and verify
<a href="https://datatracker.ietf.org/doc/html/rfc7519">RFC7519</a> JWT tokens.
Compliant tokens generated by another solution can be used as long as the
following requirements are met:
<ol>
<li>Required tokens for Slurm are present:
	<ul>
		<li>iat: Unix timestamp of creation date.</li>
		<li>exp: Unix timestamp of expiration date.</li>
		<li>sun or username: Slurm UserName (
			<a href="https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_437">
				POSIX.1-2017 User Name
			</a>).
		</li>
	</ul>
</li>
<li>Tokens are signed with HS256 algorithm compliant to RFC7518. RS256 is also
	supported to verify tokens, although Slurm cannot create them
	directly.</li>
<li>Signing key is provided to slurmctld and slurmdbd to allow decryption of
	the tokens. Slurm currently only supports a single signing key.</li>
</ol>

The following scripts require the installation of the JWT Python module.
This script can serve as an example of what you might do to generate
a jwt key for use with Slurm.
<pre>
#!/usr/bin/env python3
import sys
import os
import pprint
import json
import time
from datetime import datetime, timedelta, timezone

from jwt import JWT
from jwt.jwa import HS256
from jwt.jwk import jwk_from_dict
from jwt.utils import b64decode,b64encode

if len(sys.argv) != 3:
    sys.exit("gen_jwt.py [user name] [expiration time (seconds)]");

with open("/var/spool/slurm/statesave/jwt.key", "rb") as f:
    priv_key = f.read()

signing_key = jwk_from_dict({
    'kty': 'oct',
    'k': b64encode(priv_key)
})

message = {
    "exp": int(time.time() + int(sys.argv[2])),
    "iat": int(time.time()),
    "sun": sys.argv[1]
}

a = JWT()
compact_jws = a.encode(message, signing_key, alg='HS256')
print("SLURM_JWT={}".format(compact_jws))
</pre>

Similarly, the following script can be used as an example of how you might
verify that a jwt key is valid for use with Slurm.
<pre>
#!/usr/bin/env python3
import sys
import os
import pprint
import json
import time
from datetime import datetime, timedelta, timezone

from jwt import JWT
from jwt.jwa import HS256
from jwt.jwk import jwk_from_dict
from jwt.utils import b64decode,b64encode

if len(sys.argv) != 2:
    sys.exit("verify_jwt.py [JWT Token]");

with open("/var/spool/slurm/statesave/jwt.key", "rb") as f:
    priv_key = f.read()

signing_key = jwk_from_dict({
    'kty': 'oct',
    'k': b64encode(priv_key)
})

a = JWT()
b = a.decode(sys.argv[1], signing_key, algorithms=["HS256"])
print(b)
</pre>

<p style="text-align:center;">Last modified 07 January 2025</p>

<!--#include virtual="footer.txt"-->