| <!--#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"--> |