diff --git a/jupyterhub/jupyterhub-values.gomplate.yaml b/jupyterhub/jupyterhub-values.gomplate.yaml index bad9851..a3dbd61 100644 --- a/jupyterhub/jupyterhub-values.gomplate.yaml +++ b/jupyterhub/jupyterhub-values.gomplate.yaml @@ -73,6 +73,14 @@ hub: with open('/srv/jupyterhub/pre_spawn_hook.py', 'r') as f: exec(f.read()) + configure-security-context: | + # Configure container security context for restricted Pod Security Standard + c.KubeSpawner.container_security_context = { + 'capabilities': { + 'drop': ['ALL'] + } + } + {{- if eq .Env.JUPYTERHUB_VAULT_INTEGRATION_ENABLED "true" }} # Vault token renewal sidecar configuration extraVolumes: @@ -155,6 +163,21 @@ proxy: type: ClusterIP singleuser: + # Disable block-cloud-metadata sidecar for restricted Pod Security Standard compliance + # Not needed in self-hosted environments without cloud metadata services + cloudMetadata: + blockWithIptables: false + + # Pod Security Standard (restricted) compliance + allowPrivilegeEscalation: false + + # Additional security context via extraPodConfig + extraPodConfig: + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + storage: {{ if env.Getenv "PVC_NAME" -}} type: static @@ -180,6 +203,10 @@ singleuser: {{- if eq .Env.JUPYTERHUB_GPU_ENABLED "true" }} extraPodConfig: runtimeClassName: nvidia + securityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault extraResource: limits: nvidia.com/gpu: "{{ .Env.JUPYTERHUB_GPU_LIMIT }}" @@ -206,7 +233,6 @@ singleuser: - name: airflow-dags persistentVolumeClaim: claimName: airflow-dags-pvc - optional: true # Don't fail if PVC doesn't exist yet extraVolumeMounts: - name: airflow-dags mountPath: /home/jovyan/airflow-dags diff --git a/jupyterhub/justfile b/jupyterhub/justfile index 714c5be..334f4b4 100644 --- a/jupyterhub/justfile +++ b/jupyterhub/justfile @@ -110,6 +110,9 @@ install root_token='': just create-namespace + kubectl label namespace ${JUPYTERHUB_NAMESPACE} \ + pod-security.kubernetes.io/enforce=restricted --overwrite + # Create crypt key secret if it doesn't exist if ! kubectl get secret jupyterhub-crypt-key -n ${JUPYTERHUB_NAMESPACE} &>/dev/null; then just create-crypt-key-secret @@ -394,21 +397,6 @@ create-jupyterhub-vault-token root_token='': VAULT_TOKEN=$(gum input --prompt="Vault root token: " --password --width=100) done - echo "Creating JupyterHub admin Vault token" - - # jupyterhub-admin policy should exist (created by setup-vault-integration) - - # Check if token already exists - if vault kv get secret/jupyterhub/vault-token >/dev/null 2>&1; then - echo "Existing admin token found at secret/jupyterhub/vault-token" - if gum confirm "Replace existing token with new one?"; then - echo "Creating new admin token..." - else - echo "Using existing token" - return 0 - fi - fi - # Create admin vault token with unlimited max TTL echo "" echo "Creating admin token (TTL: ${JUPYTERHUB_VAULT_TOKEN_TTL}, Max TTL: unlimited)..."