Skip to content

Commit

Permalink
Merge pull request #39 from eth-cscs/refreshless
Browse files Browse the repository at this point in the history
Refreshless spawner
  • Loading branch information
rsarm authored Nov 6, 2024
2 parents f02e179 + 04266be commit d47c0c1
Show file tree
Hide file tree
Showing 13 changed files with 267 additions and 122 deletions.
70 changes: 16 additions & 54 deletions chart/f7t4jhub/files/jupyterhub-config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import asyncio
import json
import grp
import os
import requests
import secrets
Expand Down Expand Up @@ -53,69 +55,20 @@ async def get_node_ip_from_output(spawner):
time.sleep(2)


class FirecrestAccessTokenAuth:

_access_token: str = None

def __init__(self, access_token):
self._access_token = access_token

def get_access_token(self):
return self._access_token


class GenericOAuthenticatorCSCS(GenericOAuthenticator):
async def refresh_user(self, user, handler=None):
# self.log.info('Refreshing auth state')
auth_state = await user.get_auth_state()

params = {
'grant_type': 'refresh_token',
'client_id': self.client_id,
'client_secret': self.client_secret,
'refresh_token': auth_state['refresh_token']
}

headers = {
"Content-Type": "application/x-www-form-urlencoded"
}

response = requests.post(self.token_url, data=params, headers=headers)
if response.status_code != 200:
self.log.debug(f"[refresh_user] Request to KeyCloak: {response.status_code}")
try:
self.log.debug(f"[refresh_user] Request to KeyCloak: {response.json()}")
except json.JSONDecodeError:
self.log.debug(f"[refresh_user] Request to KeyCloak: no json output")

return False

token_response = response.json()

auth_state['token_response'].update(token_response)
auth_state['access_token'] = token_response['access_token']
auth_state['refresh_token'] = token_response['refresh_token']

return {
'name': auth_state['oauth_user']['preferred_username'],
'auth_state': auth_state
}


c = get_config()


c.Authenticator.admin_users = {{ .Values.config.adminUsers }}
c.JupyterHub.admin_access = False
c.Authenticator.allow_all = True

c.Authenticator.refresh_pre_spawn = True
# c.Authenticator.refresh_pre_spawn = True
c.Authenticator.auth_refresh_age = 250

c.Authenticator.enable_auth_state = True
c.CryptKeeper.keys = gen_hex_string("/home/juhu/hex_strings_crypt.txt")

c.JupyterHub.authenticator_class = GenericOAuthenticatorCSCS
c.JupyterHub.authenticator_class = GenericOAuthenticator
c.GenericOAuthenticator.client_id = os.environ.get('KC_CLIENT_ID', '<client-id>')
c.GenericOAuthenticator.client_secret = os.environ.get('KC_CLIENT_SECRET', '<client-secret>')
c.GenericOAuthenticator.oauth_callback_url = "{{ .Values.config.auth.oauthCallbackUrl }}"
Expand All @@ -133,13 +86,14 @@ async def refresh_user(self, user, handler=None):
c.JupyterHub.hub_connect_ip = socket.gethostbyname(hostname)

c.JupyterHub.spawner_class = 'firecrestspawner.spawner.SlurmSpawner'
c.Spawner.enable_aux_fc_client = {{ .Values.serviceAccount.enabled | toJson | replace "true" "True" | replace "false" "False" }}
c.Spawner.req_host = '{{ .Values.config.spawner.host }}'
c.Spawner.node_name_template = '{{ .Values.config.spawner.nodeNameTemplate }}'
c.Spawner.req_partition = '{{ .Values.config.spawner.partition }}'
c.Spawner.req_account = '{{ .Values.config.spawner.account }}'
c.Spawner.req_constraint = '{{ .Values.config.spawner.constraint }}'
c.Spawner.req_srun = '{{ .Values.config.spawner.srun }}'
c.Spawner.batch_script = """#!/bin/bash
#SBATCH --job-name={{ .Values.config.spawner.jobName }}
#SBATCH --chdir={{`{{homedir}}`}}
#SBATCH --get-user-env=L
Expand All @@ -151,8 +105,16 @@ async def refresh_user(self, user, handler=None):
{% if gres %}#SBATCH --gres={{`{{gres}}`}}{% endif %}
{% if nprocs %}#SBATCH --cpus-per-task={{`{{nprocs}}`}}{% endif %}
{% if nnodes %}#SBATCH --nodes={{`{{nnodes[0]}}`}}{% endif %}
{% if reservation%}#SBATCH --reservation={{`{{reservation[0]}}`}}{% endif %}
{% if constraint %}#SBATCH --constraint={{`{{constraint[0]}}`}}{% endif %}
{% if reservation is string %}
#SBATCH --reservation={{`{{reservation}}`}}
{% else %}
#SBATCH --reservation={{`{{reservation[0]}}`}}
{% endif %}
{% if constraint is string %}
#SBATCH --constraint={{`{{constraint}}`}}
{% else %}
#SBATCH --constraint={{`{{constraint[0]}}`}}
{% endif %}
{% if options %}#SBATCH {{`{{options}}`}}{% endif %}
# Activate a virtual environment, load modules, etc
Expand Down
15 changes: 15 additions & 0 deletions chart/f7t4jhub/templates/deployment-hub.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ spec:
secretKeyRef:
name: {{ .Release.Name }}-secret
key: authTokenUrl
- name: SA_AUTH_TOKEN_URL
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-secret
key: serviceAccountAuthTokenUrl
{{- if .Values.vault.keycloak.enabled }}
- name: KC_CLIENT_ID
valueFrom:
Expand All @@ -74,6 +79,16 @@ spec:
secretKeyRef:
name: {{ .Release.Name }}-common-secrets
key: kc_client_secret
- name: SA_CLIENT_ID
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-common-secrets
key: sa_client_id
- name: SA_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: {{ .Release.Name }}-common-secrets
key: sa_client_secret
{{- end }}
{{- if .Values.vault.configProxyAuthToken.enabled }}
- name: CONFIGPROXY_AUTH_TOKEN
Expand Down
8 changes: 8 additions & 0 deletions chart/f7t4jhub/templates/external-secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,12 @@ spec:
remoteRef:
key: {{ .Values.vault.configProxyAuthToken.secretPath }}
property: config_proxy_auth_token
- secretKey: sa_client_id
remoteRef:
key: {{ .Values.vault.keycloak.secretPath }}
property: sa_client_id
- secretKey: sa_client_secret
remoteRef:
key: {{ .Values.vault.keycloak.secretPath }}
property: sa_client_secret
{{- end }}
1 change: 1 addition & 0 deletions chart/f7t4jhub/templates/secret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type: Opaque
stringData:
firecrestUrl: {{ .Values.setup.firecrestUrl }}
authTokenUrl: {{ .Values.setup.authTokenUrl}}
serviceAccountAuthTokenUrl: {{ .Values.serviceAccount.authTokenUrl }}
{{- if not .Values.vault.configProxyAuthToken.enabled }}
configProxyAuthToken: {{ $token }}
{{- end }}
11 changes: 8 additions & 3 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,14 @@ f7t4jhub:
# Secret path in Vault (replace with your own secret path)
secretPath: 'secret/path/proxy'

# service account for polling jobs
serviceAccount:
# Enable or disable service account for polling jobs
enabled: true

# URL to obtain an auth token from your identity provider (replace with the SA's token URL)
authTokenUrl: 'https://auth-sa.example.com/auth/realms/yourrealm/protocol/openid-connect/token'

metricbeat:
# Enable or disable annotations for metric beat monitoring
enabled: false
Expand Down Expand Up @@ -140,9 +148,6 @@ f7t4jhub:
# Partition for the job scheduler (customize as needed)
partition: 'slurm_partition'

# Account for the job scheduler (customize as needed)
account: 'slurm_account'

# Constraint for the job scheduler (customize as needed)
constraint: 'slurm_constraint'

Expand Down
2 changes: 1 addition & 1 deletion dockerfiles/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ RUN apt-get update -qq \
RUN python3 -m venv /opt/jhub-env

RUN . /opt/jhub-env/bin/activate && \
pip install --no-cache jupyterhub==4.1.6 pyfirecrest==2.1.0 SQLAlchemy==1.4.52 oauthenticator==16.3.1 python-hostlist==1.23.0
pip install --no-cache jupyterhub==4.1.6 pyfirecrest==2.6.0 SQLAlchemy==1.4.52 oauthenticator==16.3.1 python-hostlist==1.23.0

COPY . firecrestspawner

Expand Down
4 changes: 2 additions & 2 deletions docs/source/deployment.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ They can be accessed in our kubernetes deployment via a set of secrets:

- A `SecretStore <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/secret-store.yaml>`_, which interacts with the ``vault-approle-secret`` secret.

- An `ExternalSecret <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/external-secret.yaml>`_ which interacts with the ``SecretStore`` allowing the deployment to access the Keycloak client's IDs and secrets.
- An `ExternalSecret <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/external-secret.yaml>`_ which interacts with the ``SecretStore`` allowing the deployment to access the client's IDs and secrets.

- An optional `ExternalSecret <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/external-secret-registry.yaml>`_ that's used for to store credentials for a custom container registry. That's currently not in use.
- An optional `ExternalSecret to access credentials for a custom container registry <https://github.com/eth-cscs/firecrestspawner/blob/main/chart/f7t4jhub/templates/external-secret-registry.yaml>`_. That's currently not in use.

The section of the chart related to Vault is optional and can be disabled in the ``values.yaml``.

Expand Down
Loading

0 comments on commit d47c0c1

Please sign in to comment.