blob: 4e9c9ab955898b56fd083944b0c7a162d19a1bb3 [file] [log] [blame]
<!--#include virtual="header.txt"-->
<h1>JSON Web Tokens (JWT) Authentication</h1>
<p>Slurm provides a RFC7519 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="download.html#jwt">libjwt</a>.
Both the library and the development headers must be available when Slurm is
compiled.</p>
<h2 id="setup">Setup for Standalone Use
<a class="slurm_link" href="#setup"></a>
</h2>
<ol>
<li><a href="download.html#jwt">
Configure and build Slurm for JWT support</a></li>
<li>Add JWT key to controller in StateSaveLocation.
Here is an example with the JWT key in /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>Add JWT as an alternative authentication in slurm.conf and slurmdbd.conf:
<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>
<h2 id="compatibility">Compatibility
<a class="slurm_link" href="#compatibility"></a>
</h2>
Slurm uses libjwt to view and verify RFC7519 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 11 January 2024</p>
<!--#include virtual="footer.txt"-->