feat(jupyterhub): admin vault token renewal
This commit is contained in:
@@ -19,15 +19,17 @@ export JUPYTER_PROFILE_PYTORCH_ENABLED := env("JUPYTER_PROFILE_PYTORCH_ENABLED",
|
||||
export JUPYTER_PROFILE_TENSORFLOW_ENABLED := env("JUPYTER_PROFILE_TENSORFLOW_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 IMAGE_REGISTRY := env("IMAGE_REGISTRY", "localhost:30500")
|
||||
export JUPYTERHUB_VAULT_TOKEN_TTL := env("JUPYTERHUB_VAULT_TOKEN_TTL", "720h") # 30 days
|
||||
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 LONGHORN_NAMESPACE := env("LONGHORN_NAMESPACE", "longhorn")
|
||||
export VAULT_ADDR := env("VAULT_ADDR", "http://vault.vault.svc:8200")
|
||||
export JUPYTERHUB_VAULT_TOKEN_TTL := env("JUPYTERHUB_VAULT_TOKEN_TTL", "24h")
|
||||
export JUPYTERHUB_VAULT_TOKEN_MAX_TTL := env("JUPYTERHUB_VAULT_TOKEN_MAX_TTL", "720h")
|
||||
export NOTEBOOK_VAULT_TOKEN_TTL := env("NOTEBOOK_VAULT_TOKEN_TTL", "24h")
|
||||
export NOTEBOOK_VAULT_TOKEN_MAX_TTL := env("NOTEBOOK_VAULT_TOKEN_MAX_TTL", "168h")
|
||||
export VAULT_AGENT_LOG_LEVEL := env("VAULT_AGENT_LOG_LEVEL", "info")
|
||||
export JUPYTER_BUUNSTACK_LOG_LEVEL := env("JUPYTER_BUUNSTACK_LOG_LEVEL", "warning")
|
||||
export IMAGE_REGISTRY := env("IMAGE_REGISTRY", "localhost:30500")
|
||||
export LONGHORN_NAMESPACE := env("LONGHORN_NAMESPACE", "longhorn")
|
||||
export KEYCLOAK_REALM := env("KEYCLOAK_REALM", "buunstack")
|
||||
export VAULT_HOST := env("VAULT_HOST", "")
|
||||
export VAULT_ADDR := "https://" + VAULT_HOST
|
||||
|
||||
[private]
|
||||
default:
|
||||
@@ -116,13 +118,26 @@ install:
|
||||
kubectl apply -n ${JUPYTERHUB_NAMESPACE} -f nfs-pvc.yaml
|
||||
fi
|
||||
|
||||
# Always create new JupyterHub Vault token on deployment
|
||||
echo "Creating new JupyterHub Vault token for this deployment..."
|
||||
just create-jupyterhub-vault-token
|
||||
export JUPYTERHUB_VAULT_TOKEN=$(just vault::get jupyterhub/vault-token token)
|
||||
# Setup Vault Agent for automatic token management
|
||||
if [ -z "${JUPYTERHUB_VAULT_INTEGRATION_ENABLED}" ]; then
|
||||
if gum confirm "Are you going to enable Vault integration?"; then
|
||||
JUPYTERHUB_VAULT_INTEGRATION_ENABLED=true
|
||||
else
|
||||
JUPYTERHUB_VAULT_INTEGRATION_ENABLED=false
|
||||
fi
|
||||
fi
|
||||
if [ "${JUPYTERHUB_VAULT_INTEGRATION_ENABLED}" = "true" ]; then
|
||||
echo "Setting up Vault Agent for automatic token management..."
|
||||
echo " Token TTL: ${JUPYTERHUB_VAULT_TOKEN_TTL}"
|
||||
echo " Token Max TTL: ${JUPYTERHUB_VAULT_TOKEN_MAX_TTL}"
|
||||
just setup-vault-integration
|
||||
|
||||
# Read user policy template for Vault
|
||||
export USER_POLICY_HCL=$(cat user_policy.hcl)
|
||||
# Read user policy template for Vault
|
||||
export USER_POLICY_HCL=$(cat user_policy.hcl)
|
||||
else
|
||||
echo "Vault integration disabled - deploying without Vault support"
|
||||
export USER_POLICY_HCL=""
|
||||
fi
|
||||
|
||||
# https://z2jh.jupyter.org/en/stable/
|
||||
gomplate -f jupyterhub-values.gomplate.yaml -o jupyterhub-values.yaml
|
||||
@@ -133,17 +148,6 @@ install:
|
||||
# wait deployments manually because `helm upgrade --wait` does not work for JupyterHub
|
||||
just k8s::wait-deployments-ready ${JUPYTERHUB_NAMESPACE} hub proxy
|
||||
|
||||
if [ -z "${JUPYTERHUB_VAULT_INTEGRATION_ENABLED}" ]; then
|
||||
if gum confirm "Are you going to enable Vault integration?"; then
|
||||
JUPYTERHUB_VAULT_INTEGRATION_ENABLED=true
|
||||
else
|
||||
JUPYTERHUB_VAULT_INTEGRATION_ENABLED=false
|
||||
fi
|
||||
fi
|
||||
if [ "${JUPYTERHUB_VAULT_INTEGRATION_ENABLED}" = "true" ]; then
|
||||
just setup-vault-jwt-auth
|
||||
fi
|
||||
|
||||
# Uninstall JupyterHub
|
||||
uninstall:
|
||||
#!/bin/bash
|
||||
@@ -205,18 +209,53 @@ push-kernel-images:
|
||||
docker push ${IMAGE_REGISTRY}/${KERNEL_IMAGE_BUUN_STACK_CUDA_REPOSITORY}:${JUPYTER_PYTHON_KERNEL_TAG}
|
||||
fi
|
||||
|
||||
# Setup Vault integration for JupyterHub (user-specific tokens)
|
||||
setup-vault-jwt-auth:
|
||||
# Setup Vault integration for JupyterHub (user-specific tokens + auto-renewal)
|
||||
setup-vault-integration root_token='':
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
echo "Setting up Vault integration for JupyterHub..."
|
||||
|
||||
echo "✓ Vault integration configured (user-specific tokens)"
|
||||
# Create Kubernetes role for JupyterHub in Vault
|
||||
echo "Creating Kubernetes authentication role for JupyterHub..."
|
||||
echo " Service Account: hub"
|
||||
echo " Namespace: jupyter"
|
||||
echo " Policies: admin"
|
||||
echo " TTL: ${JUPYTERHUB_VAULT_TOKEN_TTL}"
|
||||
echo " Max TTL: ${JUPYTERHUB_VAULT_TOKEN_MAX_TTL}"
|
||||
export VAULT_TOKEN="{{ root_token }}"
|
||||
while [ -z "${VAULT_TOKEN}" ]; do
|
||||
VAULT_TOKEN=$(gum input --prompt="Vault root token: " --password --width=100)
|
||||
done
|
||||
vault write auth/kubernetes/role/jupyterhub \
|
||||
bound_service_account_names=hub \
|
||||
bound_service_account_namespaces=jupyter \
|
||||
policies=admin \
|
||||
ttl=${JUPYTERHUB_VAULT_TOKEN_TTL} \
|
||||
max_ttl=${JUPYTERHUB_VAULT_TOKEN_MAX_TTL}
|
||||
|
||||
# Create Vault Agent configuration with gomplate
|
||||
echo "Creating Vault Agent configuration..."
|
||||
gomplate -f vault-agent-config.gomplate.hcl -o vault-agent-config.hcl
|
||||
kubectl create configmap vault-agent-config -n ${JUPYTERHUB_NAMESPACE} \
|
||||
--from-file=agent.hcl=vault-agent-config.hcl \
|
||||
--from-file=token-monitor.tpl=token-monitor.tpl \
|
||||
--dry-run=client -o yaml | kubectl apply -f -
|
||||
|
||||
echo "✓ Vault integration configured (user-specific tokens + auto-renewal)"
|
||||
echo ""
|
||||
echo "Configuration Summary:"
|
||||
echo " JupyterHub Token TTL: ${JUPYTERHUB_VAULT_TOKEN_TTL}"
|
||||
echo " JupyterHub Token Max TTL: ${JUPYTERHUB_VAULT_TOKEN_MAX_TTL}"
|
||||
echo " User Token TTL: ${NOTEBOOK_VAULT_TOKEN_TTL}"
|
||||
echo " User Token Max TTL: ${NOTEBOOK_VAULT_TOKEN_MAX_TTL}"
|
||||
echo " Vault Agent Log Level: ${VAULT_AGENT_LOG_LEVEL}"
|
||||
echo " Auto-renewal: Every $(( $(echo ${JUPYTERHUB_VAULT_TOKEN_TTL} | sed 's/m/*60/g; s/h/*3600/g; s/s//g' | bc) / 2 ))s (TTL/2)"
|
||||
echo ""
|
||||
echo "Users can now access Vault from notebooks using:"
|
||||
echo " from buunstack import SecretStore"
|
||||
echo " secrets = SecretStore()"
|
||||
echo " # Each user gets their own isolated Vault token and policy"
|
||||
echo " # Admin token is automatically renewed by Vault Agent"
|
||||
|
||||
# Create JupyterHub Vault token (uses admin policy for JWT operations)
|
||||
create-jupyterhub-vault-token:
|
||||
|
||||
Reference in New Issue
Block a user