mirror of
https://github.com/stellarshenson/stellars-jupyterhub-ds.git
synced 2026-03-07 21:50:28 +00:00
feat: enhance traefik-host-based-routing with CIFS and cert installers
- Add optional CIFS mount support via compose_cifs.yml and .env - Create install_cert.sh for Linux (multi-distro support) - Enhance install_cert.bat with folder argument and help flags - Fix compose_override.yml stray quote, add idle culler defaults - Enhance generate-certs.sh with generic CN and verification - Update start.sh/stop.sh to support ENABLE_CIFS from .env - Update README with CIFS and certificate installation docs
This commit is contained in:
@@ -162,3 +162,6 @@ This journal tracks substantive work on documents, diagrams, and documentation c
|
||||
|
||||
53. **Task - Create stop.sh script**: Added stop.sh to complement start.sh for platform shutdown<br>
|
||||
**Result**: Created stop.sh mirroring start.sh pattern - resolves script location via readlink/dirname, respects compose_override.yml if present, runs docker compose down --remove-orphans
|
||||
|
||||
54. **Task - Enhance traefik-host-based-routing template**: Major improvements to deployment template with CIFS support and certificate installers<br>
|
||||
**Result**: Added optional CIFS mount support via compose_cifs.yml and .env.example (ENABLE_CIFS=1), created install_cert.sh for Linux (multi-distro: Debian/Ubuntu, RHEL/CentOS, Arch, Alpine, macOS) and enhanced install_cert.bat for Windows with folder argument and help flags, fixed compose_override.yml stray quote and added JUPYTERHUB_IDLE_CULLER_ENABLED/JUPYTERHUB_SIGNUP_ENABLED defaults, enhanced generate-certs.sh with generic CN for browser compatibility and verification output, updated start.sh/stop.sh to load .env and conditionally include compose_cifs.yml, updated README with CIFS instructions and certificate installation commands, added .env to .gitignore
|
||||
|
||||
6
extra/traefik-host-based-routing/.env.example
Normal file
6
extra/traefik-host-based-routing/.env.example
Normal file
@@ -0,0 +1,6 @@
|
||||
# Optional environment variables
|
||||
# Copy to .env and customize
|
||||
|
||||
# Enable CIFS mount for shared storage (0=disabled, 1=enabled)
|
||||
# Requires compose_cifs.yml to be configured with NAS credentials
|
||||
ENABLE_CIFS=0
|
||||
3
extra/traefik-host-based-routing/.gitignore
vendored
3
extra/traefik-host-based-routing/.gitignore
vendored
@@ -15,6 +15,9 @@ Thumbs.db
|
||||
# Docker
|
||||
.docker/
|
||||
|
||||
# Environment (may contain credentials)
|
||||
.env
|
||||
|
||||
# TLS certificates (private keys)
|
||||
certs/*.pem
|
||||
certs/**/*.pem
|
||||
|
||||
@@ -27,9 +27,13 @@ Template for deploying stellars-jupyterhub-ds with local Traefik reverse proxy a
|
||||
```
|
||||
<name>_stellars_jupyterhub_ds/
|
||||
compose_override.yml # Local Traefik + JupyterHub config
|
||||
start.sh # Pull latest + start services
|
||||
compose_cifs.yml # Optional CIFS mount configuration
|
||||
start.sh # Clone/update + start services
|
||||
stop.sh # Stop services
|
||||
generate-certs.sh # Certificate generation script
|
||||
install_cert.sh # Linux certificate installer
|
||||
install_cert.bat # Windows certificate installer
|
||||
.env.example # Example environment config
|
||||
certs/
|
||||
tls.yml # Traefik TLS configuration
|
||||
_.yourdomain.example.com/ # Generated wildcard cert
|
||||
@@ -43,8 +47,19 @@ Template for deploying stellars-jupyterhub-ds with local Traefik reverse proxy a
|
||||
Edit `compose_override.yml` to customize:
|
||||
- Domain name (replace `YOURDOMAIN` placeholder)
|
||||
- Ports (default: 80/443)
|
||||
- Environment variables (idle culler, signup)
|
||||
- Network name
|
||||
- Additional services
|
||||
|
||||
### Optional CIFS Mount
|
||||
|
||||
To enable shared NAS storage for user containers:
|
||||
|
||||
1. Edit `compose_cifs.yml` with your NAS credentials
|
||||
2. Create `.env` from `.env.example`:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
3. Set `ENABLE_CIFS=1` in `.env`
|
||||
|
||||
## Access
|
||||
|
||||
@@ -52,13 +67,26 @@ After deployment:
|
||||
- JupyterHub: https://jupyterhub.yourdomain.example.com/
|
||||
- Traefik: https://traefik.yourdomain.example.com
|
||||
|
||||
Import `certs/_.<domain>/cert.pem` to browser for trusted HTTPS.
|
||||
### Certificate Installation
|
||||
|
||||
Import the self-signed certificate to your browser for trusted HTTPS:
|
||||
|
||||
**Linux:**
|
||||
```bash
|
||||
./install_cert.sh certs/_.yourdomain.example.com/
|
||||
```
|
||||
|
||||
**Windows:**
|
||||
```cmd
|
||||
install_cert.bat certs\_.yourdomain.example.com\
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
||||
```bash
|
||||
./start.sh # Pull latest + start services
|
||||
./stop.sh # Stop all services
|
||||
./start.sh # Clone repo (if missing) + start services
|
||||
./start.sh --refresh # Pull latest upstream + start services
|
||||
./stop.sh # Stop all services
|
||||
```
|
||||
|
||||
To view logs:
|
||||
|
||||
20
extra/traefik-host-based-routing/compose_cifs.yml
Normal file
20
extra/traefik-host-based-routing/compose_cifs.yml
Normal file
@@ -0,0 +1,20 @@
|
||||
# =============================================================================
|
||||
# CIFS Volume Mount - Optional
|
||||
# =============================================================================
|
||||
#
|
||||
# Enable by setting ENABLE_CIFS=1 in .env
|
||||
#
|
||||
# Update credentials and mount path below before enabling.
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
volumes:
|
||||
jupyterhub_shared:
|
||||
driver: local
|
||||
name: jupyterhub_shared
|
||||
driver_opts:
|
||||
type: cifs
|
||||
device: //nas.example.com/shared
|
||||
o: username=YOUR_USERNAME,password=YOUR_PASSWORD,uid=1000,gid=1000,vers=3.0
|
||||
|
||||
# EOF
|
||||
@@ -7,7 +7,7 @@
|
||||
# ACCESS: https://jupyterhub.YOURDOMAIN/ or https://jupyterhub.localhost/
|
||||
# TRUST: Import certs/_.YOURDOMAIN/cert.pem to browser
|
||||
#
|
||||
# Replace YOURDOMAIN with your actual domain (e.g., lab.stellars-tech.eu)
|
||||
# Replace YOURDOMAIN with your actual domain (e.g., lab.example.com)
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
@@ -68,6 +68,8 @@ services:
|
||||
ports: []
|
||||
environment:
|
||||
- JUPYTERHUB_BASE_URL=/
|
||||
- JUPYTERHUB_IDLE_CULLER_ENABLED=1
|
||||
- JUPYTERHUB_SIGNUP_ENABLED=0
|
||||
networks:
|
||||
- jupyterhub_network
|
||||
labels:
|
||||
@@ -75,7 +77,6 @@ services:
|
||||
|
||||
# JupyterHub router (root path)
|
||||
- "traefik.http.routers.jupyterhub-rtr.rule=Host(`jupyterhub.YOURDOMAIN`) || Host(`jupyterhub.localhost`)"
|
||||
"
|
||||
- "traefik.http.routers.jupyterhub-rtr.entrypoints=websecure"
|
||||
- "traefik.http.routers.jupyterhub-rtr.tls=true"
|
||||
- "traefik.http.routers.jupyterhub-rtr.service=jupyterhub-svc"
|
||||
|
||||
@@ -4,13 +4,16 @@
|
||||
# =============================================================================
|
||||
#
|
||||
# Usage: ./generate-certs.sh <domain>
|
||||
# Example: ./generate-certs.sh lab.stellars-tech.eu
|
||||
# Example: ./generate-certs.sh lab.example.com
|
||||
#
|
||||
# Creates:
|
||||
# certs/_.domain/cert.pem - Certificate (import to browser)
|
||||
# certs/_.domain/key.pem - Private key
|
||||
# certs/tls.yml - Traefik TLS configuration
|
||||
#
|
||||
# Note: Uses generic CN to avoid browser CN validation issues across multiple
|
||||
# domains. All domains are specified in SAN (Subject Alternative Name) field.
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
@@ -19,7 +22,7 @@ DOMAIN="${1:-}"
|
||||
|
||||
if [ -z "$DOMAIN" ]; then
|
||||
echo "Usage: $0 <domain>"
|
||||
echo "Example: $0 lab.stellars-tech.eu"
|
||||
echo "Example: $0 lab.example.com"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -32,16 +35,17 @@ echo "Generating self-signed certificate for *.${DOMAIN}"
|
||||
mkdir -p "$CERT_DIR"
|
||||
|
||||
# Generate self-signed certificate
|
||||
# Uses generic CN to avoid browser CN validation issues; domains are in SAN
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
|
||||
-keyout "${CERT_DIR}/key.pem" \
|
||||
-out "${CERT_DIR}/cert.pem" \
|
||||
-subj "/CN=*.${DOMAIN}" \
|
||||
-addext "subjectAltName=DNS:*.${DOMAIN},DNS:${DOMAIN},DNS:localhost,DNS:*.localhost"
|
||||
-subj "/CN=DEV Certificate" \
|
||||
-addext "subjectAltName=DNS:*.${DOMAIN},DNS:${DOMAIN},DNS:*.app.localhost,DNS:app.localhost,DNS:*.localhost,DNS:localhost"
|
||||
|
||||
# Generate Traefik TLS configuration
|
||||
cat > "$TLS_CONFIG" << EOF
|
||||
# TLS Configuration for self-signed certificates
|
||||
# Wildcard cert: *.${DOMAIN}
|
||||
# Wildcard cert: *.${DOMAIN}, *.localhost
|
||||
# Import cert.pem to browser for trusted HTTPS
|
||||
|
||||
tls:
|
||||
@@ -57,12 +61,15 @@ tls:
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
echo "Certificate generated successfully:"
|
||||
echo " - ${CERT_DIR}/cert.pem (import to browser)"
|
||||
echo " - ${CERT_DIR}/key.pem"
|
||||
echo " - ${TLS_CONFIG}"
|
||||
echo "Certificate generated:"
|
||||
openssl x509 -in "${CERT_DIR}/cert.pem" -noout -subject -dates -ext subjectAltName
|
||||
|
||||
echo ""
|
||||
echo "Key verified:"
|
||||
openssl rsa -in "${CERT_DIR}/key.pem" -check -noout
|
||||
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. Edit compose_override.yml - replace YOURDOMAIN with ${DOMAIN}"
|
||||
echo " 2. Import ${CERT_DIR}/cert.pem to your browser"
|
||||
echo " 3. Run: make start"
|
||||
echo " 3. Run: ./start.sh"
|
||||
|
||||
@@ -1,10 +1,29 @@
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
REM Check for help flag
|
||||
if "%~1"=="-h" goto :show_help
|
||||
if "%~1"=="--help" goto :show_help
|
||||
if "%~1"=="/?" goto :show_help
|
||||
|
||||
REM Optional argument: folder to search for certificates (default: current directory)
|
||||
set "CERT_DIR=%~1"
|
||||
if "%CERT_DIR%"=="" set "CERT_DIR=."
|
||||
|
||||
REM Check if directory exists
|
||||
if not exist "%CERT_DIR%\" (
|
||||
echo Error: Directory '%CERT_DIR%' not found.
|
||||
echo Use --help for usage information.
|
||||
pause
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
echo ============================================
|
||||
echo Certificate Installer - Root Trust Store
|
||||
echo ============================================
|
||||
echo.
|
||||
echo Scanning directory: %CERT_DIR%
|
||||
echo.
|
||||
echo WARNING: This script installs certificates
|
||||
echo into your Trusted Root Certification
|
||||
echo Authorities store.
|
||||
@@ -32,47 +51,134 @@ if /i not "%proceed%"=="Y" (
|
||||
)
|
||||
echo.
|
||||
|
||||
set "found=0"
|
||||
echo Scanning for certificate and key files...
|
||||
echo.
|
||||
|
||||
for %%F in (*.cer *.crt *.pem *.der) do (
|
||||
set "found=0"
|
||||
set "certcount=0"
|
||||
set "keycount=0"
|
||||
|
||||
for %%F in ("%CERT_DIR%\*.cer" "%CERT_DIR%\*.crt" "%CERT_DIR%\*.pem" "%CERT_DIR%\*.der" "%CERT_DIR%\*.key" "%CERT_DIR%\*.p12" "%CERT_DIR%\*.pfx") do (
|
||||
set "found=1"
|
||||
echo --------------------------------------------
|
||||
echo File: %%F
|
||||
echo --------------------------------------------
|
||||
|
||||
REM Get certificate details using PowerShell
|
||||
powershell -Command ^
|
||||
"$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2('%%F'); " ^
|
||||
"Write-Host 'Subject (CN):' $cert.Subject; " ^
|
||||
"Write-Host 'Issuer:' $cert.Issuer; " ^
|
||||
"Write-Host 'Valid From:' $cert.NotBefore; " ^
|
||||
"Write-Host 'Valid To:' $cert.NotAfter; " ^
|
||||
"Write-Host 'Thumbprint:' $cert.Thumbprint; " ^
|
||||
"$san = $cert.Extensions | Where-Object { $_.Oid.FriendlyName -eq 'Subject Alternative Name' }; " ^
|
||||
"if ($san) { Write-Host 'SANs:' $san.Format(1) } else { Write-Host 'SANs: (none)' }"
|
||||
REM Create temp PowerShell script for reliable execution
|
||||
(
|
||||
echo $file = '%%F'
|
||||
echo $ext = [System.IO.Path]::GetExtension^($file^).ToLower^(^)
|
||||
echo $content = Get-Content $file -Raw -ErrorAction SilentlyContinue
|
||||
echo.
|
||||
echo # Check for private key patterns
|
||||
echo $isKey = $false
|
||||
echo if ^($ext -eq '.key'^) { $isKey = $true }
|
||||
echo elseif ^($content -match '-----BEGIN ^(RSA ^|EC ^|ENCRYPTED ^|^)PRIVATE KEY-----'^) { $isKey = $true }
|
||||
echo elseif ^($content -match '-----BEGIN OPENSSH PRIVATE KEY-----'^) { $isKey = $true }
|
||||
echo.
|
||||
echo if ^($isKey^) {
|
||||
echo Write-Host '[PRIVATE KEY] - Skipping ^(not a certificate^)' -ForegroundColor Yellow
|
||||
echo Write-Host 'Type: Private Key file'
|
||||
echo exit 1
|
||||
echo }
|
||||
echo.
|
||||
echo # Check for PKCS#12/PFX files
|
||||
echo if ^($ext -eq '.p12' -or $ext -eq '.pfx'^) {
|
||||
echo Write-Host '[PKCS#12/PFX] - Contains certificate + private key bundle' -ForegroundColor Yellow
|
||||
echo Write-Host 'Note: Use certutil or MMC to import PFX files with private keys'
|
||||
echo exit 2
|
||||
echo }
|
||||
echo.
|
||||
echo # Try to load as certificate
|
||||
echo try {
|
||||
echo $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2^($file^)
|
||||
echo Write-Host '[CERTIFICATE]' -ForegroundColor Green
|
||||
echo Write-Host 'Subject ^(CN^):' $cert.Subject
|
||||
echo Write-Host 'Issuer:' $cert.Issuer
|
||||
echo Write-Host 'Valid From:' $cert.NotBefore
|
||||
echo Write-Host 'Valid To:' $cert.NotAfter
|
||||
echo Write-Host 'Thumbprint:' $cert.Thumbprint
|
||||
echo $san = $cert.Extensions ^| Where-Object { $_.Oid.FriendlyName -eq 'Subject Alternative Name' }
|
||||
echo if ^($san^) { Write-Host 'SANs:' $san.Format^(1^) } else { Write-Host 'SANs: ^(none^)' }
|
||||
echo exit 0
|
||||
echo } catch {
|
||||
echo Write-Host '[UNKNOWN/INVALID] - Could not parse as certificate' -ForegroundColor Red
|
||||
echo Write-Host 'Error:' $_.Exception.Message
|
||||
echo exit 3
|
||||
echo }
|
||||
) > "%TEMP%\certcheck.ps1"
|
||||
|
||||
powershell -ExecutionPolicy Bypass -File "%TEMP%\certcheck.ps1"
|
||||
set "exitcode=!errorlevel!"
|
||||
|
||||
echo.
|
||||
set /p "confirm=Install this certificate to Trusted Root store? (Y/N): "
|
||||
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo Installing %%F...
|
||||
powershell -Command "Import-Certificate -FilePath '%%F' -CertStoreLocation Cert:\CurrentUser\Root" >nul 2>&1
|
||||
if !errorlevel! equ 0 (
|
||||
echo [SUCCESS] Certificate installed.
|
||||
REM Only prompt for installation if it's a valid certificate (exit code 0)
|
||||
if "!exitcode!"=="0" (
|
||||
set /p "confirm=Install this certificate to Trusted Root store? (Y/N): "
|
||||
|
||||
if /i "!confirm!"=="Y" (
|
||||
echo Installing %%F...
|
||||
powershell -Command "Import-Certificate -FilePath '%%F' -CertStoreLocation Cert:\CurrentUser\Root" >nul 2>&1
|
||||
if !errorlevel! equ 0 (
|
||||
echo [SUCCESS] Certificate installed.
|
||||
set /a "certcount+=1"
|
||||
) else (
|
||||
echo [ERROR] Failed to install certificate. Try running as Administrator.
|
||||
)
|
||||
) else (
|
||||
echo [ERROR] Failed to install certificate. Try running as Administrator.
|
||||
echo Skipped %%F
|
||||
)
|
||||
) else if "!exitcode!"=="1" (
|
||||
set /a "keycount+=1"
|
||||
echo [Skipped - Private key]
|
||||
) else if "!exitcode!"=="2" (
|
||||
echo [Skipped - Use different tool for PFX import]
|
||||
) else (
|
||||
echo Skipped %%F
|
||||
echo [Skipped - Invalid or unrecognized file]
|
||||
)
|
||||
echo.
|
||||
)
|
||||
|
||||
REM Cleanup temp file
|
||||
del "%TEMP%\certcheck.ps1" 2>nul
|
||||
|
||||
if "!found!"=="0" (
|
||||
echo No certificate files found in current directory.
|
||||
echo Supported extensions: .cer, .crt, .pem, .der
|
||||
echo No certificate or key files found in '%CERT_DIR%'.
|
||||
echo Supported extensions: .cer, .crt, .pem, .der, .key, .p12, .pfx
|
||||
)
|
||||
|
||||
echo ============================================
|
||||
echo Summary:
|
||||
echo Certificates installed: !certcount!
|
||||
echo Private keys found (skipped): !keycount!
|
||||
echo ============================================
|
||||
echo.
|
||||
echo Done.
|
||||
pause
|
||||
exit /b
|
||||
|
||||
:show_help
|
||||
echo Certificate Installer - Install certificates to Windows trust store
|
||||
echo.
|
||||
echo Usage: install_cert.bat [OPTIONS] [DIRECTORY]
|
||||
echo.
|
||||
echo Arguments:
|
||||
echo DIRECTORY Folder to search for certificates (default: current directory)
|
||||
echo.
|
||||
echo Options:
|
||||
echo -h, --help, /? Show this help message and exit
|
||||
echo.
|
||||
echo Supported file types:
|
||||
echo .cer, .crt, .pem, .der - X.509 certificates (will be installed)
|
||||
echo .key - Private keys (skipped)
|
||||
echo .p12, .pfx - PKCS#12 bundles (skipped - use different tool)
|
||||
echo.
|
||||
echo Examples:
|
||||
echo install_cert.bat # Scan current directory
|
||||
echo install_cert.bat C:\path\to\certs # Scan specific directory
|
||||
echo install_cert.bat .\my-certs # Scan relative path
|
||||
echo.
|
||||
echo Note: May require Administrator privileges for system-wide installation.
|
||||
pause
|
||||
exit /b
|
||||
|
||||
229
extra/traefik-host-based-routing/install_cert.sh
Executable file
229
extra/traefik-host-based-routing/install_cert.sh
Executable file
@@ -0,0 +1,229 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Show help
|
||||
show_help() {
|
||||
cat << 'EOF'
|
||||
Certificate Installer - Install certificates to system trust store
|
||||
|
||||
Usage: install_cert.sh [OPTIONS] [DIRECTORY]
|
||||
|
||||
Arguments:
|
||||
DIRECTORY Folder to search for certificates (default: current directory)
|
||||
|
||||
Options:
|
||||
-h, --help Show this help message and exit
|
||||
|
||||
Supported file types:
|
||||
.cer, .crt, .pem, .der - X.509 certificates (will be installed)
|
||||
.key - Private keys (skipped)
|
||||
.p12, .pfx - PKCS#12 bundles (skipped - use different tool)
|
||||
|
||||
Examples:
|
||||
install_cert.sh # Scan current directory
|
||||
install_cert.sh /path/to/certs # Scan specific directory
|
||||
install_cert.sh ./my-certs # Scan relative path
|
||||
|
||||
Note: Requires sudo privileges for system-wide certificate installation.
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
|
||||
show_help
|
||||
fi
|
||||
|
||||
# Optional argument: folder to search for certificates (default: current directory)
|
||||
CERT_DIR="${1:-.}"
|
||||
|
||||
# Resolve to absolute path and check if exists
|
||||
if [ ! -d "$CERT_DIR" ]; then
|
||||
echo "Error: Directory '$CERT_DIR' not found."
|
||||
echo "Use --help for usage information."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "============================================"
|
||||
echo " Certificate Installer - Root Trust Store"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo " Scanning directory: $CERT_DIR"
|
||||
echo ""
|
||||
echo " WARNING: This script installs certificates"
|
||||
echo " into your system's trusted root store."
|
||||
echo ""
|
||||
echo " This is intended for custom self-signed"
|
||||
echo " certificates from TRUSTED sources only."
|
||||
echo ""
|
||||
echo " *** INSTALLING UNKNOWN CERTIFICATES IS ***"
|
||||
echo " *** EXTREMELY DANGEROUS! ***"
|
||||
echo ""
|
||||
echo " A malicious root certificate can allow"
|
||||
echo " attackers to intercept ALL your encrypted"
|
||||
echo " traffic, including passwords, banking,"
|
||||
echo " and personal data."
|
||||
echo ""
|
||||
echo " Only proceed if you know and trust the"
|
||||
echo " source of these certificates!"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
read -p "Do you want to continue? (Y/N): " proceed
|
||||
|
||||
if [[ ! "$proceed" =~ ^[Yy]$ ]]; then
|
||||
echo "Aborted."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Scanning for certificate and key files..."
|
||||
echo ""
|
||||
|
||||
found=0
|
||||
certcount=0
|
||||
keycount=0
|
||||
|
||||
# Detect OS for correct certificate installation path
|
||||
install_cert() {
|
||||
local certfile="$1"
|
||||
|
||||
if [ -f /etc/debian_version ]; then
|
||||
# Debian/Ubuntu
|
||||
sudo cp "$certfile" /usr/local/share/ca-certificates/
|
||||
sudo update-ca-certificates
|
||||
elif [ -f /etc/redhat-release ]; then
|
||||
# RHEL/CentOS/Fedora
|
||||
sudo cp "$certfile" /etc/pki/ca-trust/source/anchors/
|
||||
sudo update-ca-trust
|
||||
elif [ -f /etc/arch-release ]; then
|
||||
# Arch Linux
|
||||
sudo cp "$certfile" /etc/ca-certificates/trust-source/anchors/
|
||||
sudo trust extract-compat
|
||||
elif [ -f /etc/alpine-release ]; then
|
||||
# Alpine Linux
|
||||
sudo cp "$certfile" /usr/local/share/ca-certificates/
|
||||
sudo update-ca-certificates
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# macOS
|
||||
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$certfile"
|
||||
else
|
||||
echo "[ERROR] Unknown OS. Please install manually."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
for file in "$CERT_DIR"/*.cer "$CERT_DIR"/*.crt "$CERT_DIR"/*.pem "$CERT_DIR"/*.der "$CERT_DIR"/*.key "$CERT_DIR"/*.p12 "$CERT_DIR"/*.pfx; do
|
||||
# Skip if no files match the pattern
|
||||
[ -e "$file" ] || continue
|
||||
|
||||
found=1
|
||||
echo "--------------------------------------------"
|
||||
echo "File: $file"
|
||||
echo "--------------------------------------------"
|
||||
|
||||
ext="${file##*.}"
|
||||
ext=$(echo "$ext" | tr '[:upper:]' '[:lower:]')
|
||||
|
||||
# Check for private key
|
||||
is_key=false
|
||||
|
||||
if [ "$ext" = "key" ]; then
|
||||
is_key=true
|
||||
elif [ -f "$file" ] && grep -q -E -- "-----BEGIN (RSA |EC |ENCRYPTED )?PRIVATE KEY-----|-----BEGIN OPENSSH PRIVATE KEY-----" "$file" 2>/dev/null; then
|
||||
is_key=true
|
||||
fi
|
||||
|
||||
if [ "$is_key" = true ]; then
|
||||
echo -e "\033[33m[PRIVATE KEY]\033[0m - Skipping (not a certificate)"
|
||||
echo "Type: Private Key file"
|
||||
echo ""
|
||||
echo "[Skipped - Private key]"
|
||||
((keycount++))
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check for PKCS#12/PFX files
|
||||
if [ "$ext" = "p12" ] || [ "$ext" = "pfx" ]; then
|
||||
echo -e "\033[33m[PKCS#12/PFX]\033[0m - Contains certificate + private key bundle"
|
||||
echo "Note: Use 'openssl pkcs12' to extract certificate, or import directly with browser"
|
||||
echo ""
|
||||
echo "[Skipped - Use different tool for PFX import]"
|
||||
echo ""
|
||||
continue
|
||||
fi
|
||||
|
||||
# Try to parse as certificate using openssl
|
||||
cert_info=$(openssl x509 -in "$file" -noout -subject -issuer -dates -fingerprint -ext subjectAltName 2>/dev/null)
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "\033[32m[CERTIFICATE]\033[0m"
|
||||
|
||||
# Extract and display certificate details
|
||||
subject=$(openssl x509 -in "$file" -noout -subject 2>/dev/null | sed 's/subject=/Subject (CN): /')
|
||||
issuer=$(openssl x509 -in "$file" -noout -issuer 2>/dev/null | sed 's/issuer=/Issuer: /')
|
||||
startdate=$(openssl x509 -in "$file" -noout -startdate 2>/dev/null | sed 's/notBefore=/Valid From: /')
|
||||
enddate=$(openssl x509 -in "$file" -noout -enddate 2>/dev/null | sed 's/notAfter=/Valid To: /')
|
||||
fingerprint=$(openssl x509 -in "$file" -noout -fingerprint -sha256 2>/dev/null | sed 's/sha256 Fingerprint=/Thumbprint (SHA256): /' | sed 's/SHA256 Fingerprint=/Thumbprint (SHA256): /')
|
||||
san=$(openssl x509 -in "$file" -noout -ext subjectAltName 2>/dev/null | grep -v "X509v3 Subject Alternative Name:")
|
||||
|
||||
echo "$subject"
|
||||
echo "$issuer"
|
||||
echo "$startdate"
|
||||
echo "$enddate"
|
||||
echo "$fingerprint"
|
||||
|
||||
if [ -n "$san" ]; then
|
||||
echo "SANs:$san"
|
||||
else
|
||||
echo "SANs: (none)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
read -p "Install this certificate to Trusted Root store? (Y/N): " confirm
|
||||
|
||||
if [[ "$confirm" =~ ^[Yy]$ ]]; then
|
||||
echo "Installing $file..."
|
||||
|
||||
# Convert to PEM if needed (for DER format)
|
||||
if [ "$ext" = "der" ]; then
|
||||
tmpfile=$(mktemp)
|
||||
openssl x509 -in "$file" -inform DER -out "$tmpfile" -outform PEM
|
||||
install_cert "$tmpfile"
|
||||
result=$?
|
||||
rm -f "$tmpfile"
|
||||
else
|
||||
install_cert "$file"
|
||||
result=$?
|
||||
fi
|
||||
|
||||
if [ $result -eq 0 ]; then
|
||||
echo "[SUCCESS] Certificate installed."
|
||||
((certcount++))
|
||||
else
|
||||
echo "[ERROR] Failed to install certificate. Make sure you have sudo privileges."
|
||||
fi
|
||||
else
|
||||
echo "Skipped $file"
|
||||
fi
|
||||
else
|
||||
echo -e "\033[31m[UNKNOWN/INVALID]\033[0m - Could not parse as certificate"
|
||||
echo "Error: File is not a valid X.509 certificate or format not recognized"
|
||||
echo ""
|
||||
echo "[Skipped - Invalid or unrecognized file]"
|
||||
fi
|
||||
echo ""
|
||||
done
|
||||
|
||||
if [ "$found" -eq 0 ]; then
|
||||
echo "No certificate or key files found in '$CERT_DIR'."
|
||||
echo "Supported extensions: .cer, .crt, .pem, .der, .key, .p12, .pfx"
|
||||
fi
|
||||
|
||||
echo "============================================"
|
||||
echo "Summary:"
|
||||
echo " Certificates installed: $certcount"
|
||||
echo " Private keys found (skipped): $keycount"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Done."
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/bin/bash
|
||||
# Start JupyterHub platform with latest upstream
|
||||
# Start JupyterHub platform
|
||||
# Usage: ./start.sh [--refresh]
|
||||
|
||||
set -e
|
||||
|
||||
@@ -9,6 +10,14 @@ REPO_URL="https://github.com/stellarshenson/stellars-jupyterhub-ds.git"
|
||||
REPO_DIR="stellars-jupyterhub-ds"
|
||||
REFRESH=false
|
||||
|
||||
# Default configuration (override via .env)
|
||||
ENABLE_CIFS="${ENABLE_CIFS:-0}"
|
||||
|
||||
# Load environment variables if .env exists
|
||||
if [[ -f .env ]]; then
|
||||
source .env
|
||||
fi
|
||||
|
||||
# Parse arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
@@ -37,9 +46,16 @@ else
|
||||
git clone "$REPO_URL"
|
||||
fi
|
||||
|
||||
# Build compose command with optional CIFS mount
|
||||
COMPOSE_FILES="-f stellars-jupyterhub-ds/compose.yml -f compose_override.yml"
|
||||
if [[ "${ENABLE_CIFS}" == "1" ]]; then
|
||||
echo "CIFS mount enabled"
|
||||
COMPOSE_FILES="${COMPOSE_FILES} -f compose_cifs.yml"
|
||||
fi
|
||||
|
||||
echo "Starting JupyterHub platform..."
|
||||
docker compose -f stellars-jupyterhub-ds/compose.yml -f compose_override.yml pull
|
||||
docker compose ${COMPOSE_FILES} pull
|
||||
docker pull stellars/stellars-jupyterlab-ds:latest
|
||||
docker compose -f stellars-jupyterhub-ds/compose.yml -f compose_override.yml up -d --no-build
|
||||
docker compose ${COMPOSE_FILES} up -d --no-build
|
||||
|
||||
echo "Done. Access: https://jupyterhub.YOURDOMAIN/"
|
||||
|
||||
@@ -3,7 +3,23 @@
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# Default configuration (override via .env)
|
||||
ENABLE_CIFS="${ENABLE_CIFS:-0}"
|
||||
|
||||
# Load environment variables if .env exists
|
||||
if [[ -f .env ]]; then
|
||||
source .env
|
||||
fi
|
||||
|
||||
# Build compose command with optional CIFS mount
|
||||
COMPOSE_FILES="-f stellars-jupyterhub-ds/compose.yml -f compose_override.yml"
|
||||
if [[ "${ENABLE_CIFS}" == "1" ]]; then
|
||||
COMPOSE_FILES="${COMPOSE_FILES} -f compose_cifs.yml"
|
||||
fi
|
||||
|
||||
echo "Stopping services..."
|
||||
docker compose -f stellars-jupyterhub-ds/compose.yml -f compose_override.yml down
|
||||
docker compose ${COMPOSE_FILES} down
|
||||
|
||||
echo "Done."
|
||||
|
||||
Reference in New Issue
Block a user