fix(jupyterhub): setting token ttl
This commit is contained in:
@@ -1,6 +1,10 @@
|
|||||||
hub:
|
hub:
|
||||||
extraEnv:
|
extraEnv:
|
||||||
JUPYTERHUB_CRYPT_KEY: {{ .Env.JUPYTERHUB_CRYPT_KEY | quote }}
|
JUPYTERHUB_CRYPT_KEY: {{ .Env.JUPYTERHUB_CRYPT_KEY | quote }}
|
||||||
|
JUPYTERHUB_VAULT_TOKEN: {{ .Env.JUPYTERHUB_VAULT_TOKEN | quote }}
|
||||||
|
VAULT_ADDR: {{ .Env.VAULT_ADDR | quote }}
|
||||||
|
NOTEBOOK_VAULT_TOKEN_TTL: {{ .Env.NOTEBOOK_VAULT_TOKEN_TTL | quote }}
|
||||||
|
NOTEBOOK_VAULT_TOKEN_MAX_TTL: {{ .Env.NOTEBOOK_VAULT_TOKEN_MAX_TTL | quote }}
|
||||||
|
|
||||||
# Install packages at container startup
|
# Install packages at container startup
|
||||||
extraFiles:
|
extraFiles:
|
||||||
@@ -70,8 +74,16 @@ hub:
|
|||||||
username = spawner.user.name
|
username = spawner.user.name
|
||||||
|
|
||||||
# Step 1: Initialize admin Vault client
|
# Step 1: Initialize admin Vault client
|
||||||
vault_client = hvac.Client(url="{{ .Env.VAULT_ADDR }}", verify=False)
|
import os
|
||||||
vault_client.token = "{{ .Env.JUPYTERHUB_VAULT_TOKEN }}"
|
vault_addr = os.environ.get("VAULT_ADDR", "{{ .Env.VAULT_ADDR }}")
|
||||||
|
vault_token = os.environ.get("JUPYTERHUB_VAULT_TOKEN", "{{ .Env.JUPYTERHUB_VAULT_TOKEN }}")
|
||||||
|
|
||||||
|
spawner.log.info(f"pre_spawn_hook starting for {username}")
|
||||||
|
spawner.log.info(f"Vault address: {vault_addr}")
|
||||||
|
spawner.log.info(f"Vault token present: {bool(vault_token)}, length: {len(vault_token) if vault_token else 0}")
|
||||||
|
|
||||||
|
vault_client = hvac.Client(url=vault_addr, verify=False)
|
||||||
|
vault_client.token = vault_token
|
||||||
|
|
||||||
if not vault_client.is_authenticated():
|
if not vault_client.is_authenticated():
|
||||||
raise Exception("Admin token is not authenticated")
|
raise Exception("Admin token is not authenticated")
|
||||||
@@ -96,11 +108,16 @@ hub:
|
|||||||
spawner.log.warning("Policy creation failed (may already exist): {}".format(policy_e))
|
spawner.log.warning("Policy creation failed (may already exist): {}".format(policy_e))
|
||||||
|
|
||||||
# Step 3: Create user-specific token
|
# Step 3: Create user-specific token
|
||||||
|
# Get TTL settings from environment variables
|
||||||
|
user_token_ttl = os.environ.get("NOTEBOOK_VAULT_TOKEN_TTL", "24h")
|
||||||
|
user_token_max_ttl = os.environ.get("NOTEBOOK_VAULT_TOKEN_MAX_TTL", "168h")
|
||||||
|
|
||||||
token_response = vault_client.auth.token.create(
|
token_response = vault_client.auth.token.create(
|
||||||
policies=[user_policy_name],
|
policies=[user_policy_name],
|
||||||
ttl="1h",
|
ttl=user_token_ttl,
|
||||||
renewable=True,
|
renewable=True,
|
||||||
display_name="notebook-{}".format(username)
|
display_name="notebook-{}".format(username),
|
||||||
|
explicit_max_ttl=user_token_max_ttl
|
||||||
)
|
)
|
||||||
|
|
||||||
user_vault_token = token_response["auth"]["client_token"]
|
user_vault_token = token_response["auth"]["client_token"]
|
||||||
@@ -109,7 +126,7 @@ hub:
|
|||||||
# Set user-specific Vault token as environment variable
|
# Set user-specific Vault token as environment variable
|
||||||
spawner.environment["NOTEBOOK_VAULT_TOKEN"] = user_vault_token
|
spawner.environment["NOTEBOOK_VAULT_TOKEN"] = user_vault_token
|
||||||
|
|
||||||
spawner.log.info("✅ User-specific Vault token created for {} (expires in {}s, renewable)".format(username, lease_duration))
|
spawner.log.info("✅ User-specific Vault token created for {} (TTL: {}s, renewable, max TTL: {})".format(username, lease_duration, user_token_max_ttl))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
spawner.log.error("Failed to create user-specific Vault token for {}: {}".format(spawner.user.name, e))
|
spawner.log.error("Failed to create user-specific Vault token for {}: {}".format(spawner.user.name, e))
|
||||||
@@ -266,8 +283,17 @@ singleuser:
|
|||||||
|
|
||||||
cull:
|
cull:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
# for production
|
||||||
timeout: 7200 # 2 hours idle timeout
|
timeout: 7200 # 2 hours idle timeout
|
||||||
every: 600 # Check every 10 minutes
|
every: 600 # Check every 10 minutes
|
||||||
|
|
||||||
|
# for testing
|
||||||
|
# timeout: 300 # 5 minutes idle timeout (for testing) │ │
|
||||||
|
# every: 60 # Check every 1 minute (for testing) │ │
|
||||||
|
|
||||||
|
# maxAge: 86400 # Maximum age of a server pod (1 day)
|
||||||
|
|
||||||
adminUsers: true # Also cull admin users' server pods
|
adminUsers: true # Also cull admin users' server pods
|
||||||
users: false # Don't delete user accounts, only stop server pods
|
users: false # Don't delete user accounts, only stop server pods
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export JUPYTERHUB_OIDC_CLIENT_SESSION_MAX := env("JUPYTERHUB_OIDC_CLIENT_SESSION
|
|||||||
export JUPYTERHUB_NFS_PV_ENABLED := env("JUPYTERHUB_NFS_PV_ENABLED", "")
|
export JUPYTERHUB_NFS_PV_ENABLED := env("JUPYTERHUB_NFS_PV_ENABLED", "")
|
||||||
export JUPYTERHUB_STORAGE_CLASS := env("JUPYTERHUB_STORAGE_CLASS", "")
|
export JUPYTERHUB_STORAGE_CLASS := env("JUPYTERHUB_STORAGE_CLASS", "")
|
||||||
export JUPYTERHUB_VAULT_INTEGRATION_ENABLED := env("JUPYTERHUB_VAULT_INTEGRATION_ENABLED", "")
|
export JUPYTERHUB_VAULT_INTEGRATION_ENABLED := env("JUPYTERHUB_VAULT_INTEGRATION_ENABLED", "")
|
||||||
export JUPYTER_PYTHON_KERNEL_TAG := env("JUPYTER_PYTHON_KERNEL_TAG", "python-3.12-24")
|
export JUPYTER_PYTHON_KERNEL_TAG := env("JUPYTER_PYTHON_KERNEL_TAG", "python-3.12-28")
|
||||||
export KERNEL_IMAGE_BUUN_STACK_REPOSITORY := env("KERNEL_IMAGE_BUUN_STACK_REPOSITORY", "buun-stack-notebook")
|
export KERNEL_IMAGE_BUUN_STACK_REPOSITORY := env("KERNEL_IMAGE_BUUN_STACK_REPOSITORY", "buun-stack-notebook")
|
||||||
export KERNEL_IMAGE_BUUN_STACK_CUDA_REPOSITORY := env("KERNEL_IMAGE_BUUN_STACK_CUDA_REPOSITORY", "buun-stack-cuda-notebook")
|
export KERNEL_IMAGE_BUUN_STACK_CUDA_REPOSITORY := env("KERNEL_IMAGE_BUUN_STACK_CUDA_REPOSITORY", "buun-stack-cuda-notebook")
|
||||||
export JUPYTER_PROFILE_MINIMAL_ENABLED := env("JUPYTER_PROFILE_MINIMAL_ENABLED", "false")
|
export JUPYTER_PROFILE_MINIMAL_ENABLED := env("JUPYTER_PROFILE_MINIMAL_ENABLED", "false")
|
||||||
@@ -20,8 +20,10 @@ export JUPYTER_PROFILE_TENSORFLOW_ENABLED := env("JUPYTER_PROFILE_TENSORFLOW_ENA
|
|||||||
export JUPYTER_PROFILE_BUUN_STACK_ENABLED := env("JUPYTER_PROFILE_BUUN_STACK_ENABLED", "false")
|
export JUPYTER_PROFILE_BUUN_STACK_ENABLED := env("JUPYTER_PROFILE_BUUN_STACK_ENABLED", "false")
|
||||||
export JUPYTER_PROFILE_BUUN_STACK_CUDA_ENABLED := env("JUPYTER_PROFILE_BUUN_STACK_CUDA_ENABLED", "false")
|
export JUPYTER_PROFILE_BUUN_STACK_CUDA_ENABLED := env("JUPYTER_PROFILE_BUUN_STACK_CUDA_ENABLED", "false")
|
||||||
export IMAGE_REGISTRY := env("IMAGE_REGISTRY", "localhost:30500")
|
export IMAGE_REGISTRY := env("IMAGE_REGISTRY", "localhost:30500")
|
||||||
export NOTEBOOK_VAULT_TOKEN_TTL := env("NOTEBOOK_VAULT_TOKEN_TTL", "1h")
|
export JUPYTERHUB_VAULT_TOKEN_TTL := env("JUPYTERHUB_VAULT_TOKEN_TTL", "720h") # 30 days
|
||||||
export NOTEBOOK_VAULT_TOKEN_MAX_TTL := env("NOTEBOOK_VAULT_TOKEN_MAX_TTL", "720h")
|
export JUPYTERHUB_VAULT_TOKEN_MAX_TTL := env("JUPYTERHUB_VAULT_TOKEN_MAX_TTL", "8760h") # 1 year
|
||||||
|
export NOTEBOOK_VAULT_TOKEN_TTL := env("NOTEBOOK_VAULT_TOKEN_TTL", "24h") # 1 day
|
||||||
|
export NOTEBOOK_VAULT_TOKEN_MAX_TTL := env("NOTEBOOK_VAULT_TOKEN_MAX_TTL", "168h") # 7 days
|
||||||
export KEYCLOAK_REALM := env("KEYCLOAK_REALM", "buunstack")
|
export KEYCLOAK_REALM := env("KEYCLOAK_REALM", "buunstack")
|
||||||
export LONGHORN_NAMESPACE := env("LONGHORN_NAMESPACE", "longhorn")
|
export LONGHORN_NAMESPACE := env("LONGHORN_NAMESPACE", "longhorn")
|
||||||
export VAULT_ADDR := env("VAULT_ADDR", "http://vault.vault.svc:8200")
|
export VAULT_ADDR := env("VAULT_ADDR", "http://vault.vault.svc:8200")
|
||||||
@@ -221,12 +223,12 @@ create-jupyterhub-vault-token:
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
echo "Creating JupyterHub Vault token with admin policy..."
|
echo "Creating JupyterHub Vault token with admin policy..."
|
||||||
echo " TTL: ${NOTEBOOK_VAULT_TOKEN_TTL}"
|
echo " TTL: ${JUPYTERHUB_VAULT_TOKEN_TTL}"
|
||||||
echo " Max TTL: ${NOTEBOOK_VAULT_TOKEN_MAX_TTL}"
|
echo " Max TTL: ${JUPYTERHUB_VAULT_TOKEN_MAX_TTL}"
|
||||||
|
|
||||||
# JupyterHub needs admin privileges to read Keycloak credentials from Vault
|
# JupyterHub needs admin privileges to read Keycloak credentials from Vault
|
||||||
# Create token and store in Vault
|
# Create token and store in Vault
|
||||||
just vault::create-token-and-store admin jupyterhub/vault-token ${NOTEBOOK_VAULT_TOKEN_TTL} ${NOTEBOOK_VAULT_TOKEN_MAX_TTL}
|
just vault::create-token-and-store admin jupyterhub/vault-token ${JUPYTERHUB_VAULT_TOKEN_TTL} ${JUPYTERHUB_VAULT_TOKEN_MAX_TTL}
|
||||||
|
|
||||||
echo "✓ JupyterHub Vault token created and stored"
|
echo "✓ JupyterHub Vault token created and stored"
|
||||||
echo ""
|
echo ""
|
||||||
|
|||||||
Reference in New Issue
Block a user