fix(image): Generate SSL certs on host and add TUI mode

- Fix SSL cert generation: run openssl on host, not in chroot
  (chroot lacks /dev/urandom access)
- Add secubox-console-tui for text-based dashboard
- Add TUI mode to kiosk-launcher (x11, wayland, tui)
- Add secubox-console-tui.service
- Copy TUI script in build process

Fixes nginx "localhost refused to connect" in kiosk mode.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-04-02 10:54:48 +02:00
parent 60e29d5291
commit aeb00ef121
6 changed files with 438 additions and 45 deletions

View File

@ -377,23 +377,26 @@ ok "firstboot.sh installé"
# ── Pre-generate SSL certificates for nginx ─────────────────────────
# (firstboot will regenerate on first boot, but nginx needs certs to start)
# Generate certs on HOST (chroot may lack /dev/urandom)
log "Pre-generating SSL certificates..."
mkdir -p "${ROOTFS}/etc/secubox/tls"
chroot "${ROOTFS}" openssl req -x509 -newkey rsa:2048 -days 365 \
-keyout /etc/secubox/tls/key.pem \
-out /etc/secubox/tls/cert.pem \
-nodes -subj "/CN=secubox/O=CyberMind SecuBox/C=FR" \
-addext "subjectAltName=DNS:localhost,DNS:secubox.local,IP:127.0.0.1,IP:192.168.1.1" \
2>/dev/null || warn "SSL cert generation failed"
chmod 640 "${ROOTFS}/etc/secubox/tls/key.pem" 2>/dev/null || true
chmod 644 "${ROOTFS}/etc/secubox/tls/cert.pem" 2>/dev/null || true
# Create secubox directories
mkdir -p "${ROOTFS}/etc/secubox"
mkdir -p "${ROOTFS}/run/secubox"
mkdir -p "${ROOTFS}/var/lib/secubox"
ok "SSL certificates pre-generated"
openssl req -x509 -newkey rsa:2048 -days 365 \
-keyout "${ROOTFS}/etc/secubox/tls/key.pem" \
-out "${ROOTFS}/etc/secubox/tls/cert.pem" \
-nodes -subj "/CN=secubox/O=CyberMind SecuBox/C=FR" \
-addext "subjectAltName=DNS:localhost,DNS:secubox.local,IP:127.0.0.1,IP:192.168.1.1" \
2>/dev/null
if [[ -f "${ROOTFS}/etc/secubox/tls/cert.pem" ]]; then
chmod 640 "${ROOTFS}/etc/secubox/tls/key.pem"
chmod 644 "${ROOTFS}/etc/secubox/tls/cert.pem"
ok "SSL certificates pre-generated"
else
warn "SSL cert generation failed - nginx may not start"
fi
# ── Étape 5 : Configuration bootloader ────────────────────────────
log "5/7 Configuration bootloader..."

View File

@ -911,24 +911,27 @@ ln -sf /usr/lib/systemd/system/nginx.service \
# ── Pre-generate SSL certificates for nginx ─────────────────────────
# (firstboot normally does this, but nginx needs certs to start on live USB)
# Generate certs on HOST (chroot may lack /dev/urandom) and copy them in
log "Pre-generating SSL certificates..."
mkdir -p "${ROOTFS}/etc/secubox/tls"
chroot "${ROOTFS}" openssl req -x509 -newkey rsa:2048 -days 365 \
-keyout /etc/secubox/tls/key.pem \
-out /etc/secubox/tls/cert.pem \
-nodes -subj "/CN=secubox-live/O=CyberMind SecuBox/C=FR" \
-addext "subjectAltName=DNS:localhost,DNS:secubox.local,IP:127.0.0.1,IP:192.168.1.1" \
2>/dev/null || warn "SSL cert generation failed"
# Set proper permissions
chmod 640 "${ROOTFS}/etc/secubox/tls/key.pem" 2>/dev/null || true
chmod 644 "${ROOTFS}/etc/secubox/tls/cert.pem" 2>/dev/null || true
# Create secubox directories for config
mkdir -p "${ROOTFS}/etc/secubox"
mkdir -p "${ROOTFS}/run/secubox"
mkdir -p "${ROOTFS}/var/lib/secubox"
ok "SSL certificates pre-generated"
# Generate on host system
openssl req -x509 -newkey rsa:2048 -days 365 \
-keyout "${ROOTFS}/etc/secubox/tls/key.pem" \
-out "${ROOTFS}/etc/secubox/tls/cert.pem" \
-nodes -subj "/CN=secubox-live/O=CyberMind SecuBox/C=FR" \
-addext "subjectAltName=DNS:localhost,DNS:secubox.local,IP:127.0.0.1,IP:192.168.1.1" \
2>/dev/null
if [[ -f "${ROOTFS}/etc/secubox/tls/cert.pem" ]]; then
chmod 640 "${ROOTFS}/etc/secubox/tls/key.pem"
chmod 644 "${ROOTFS}/etc/secubox/tls/cert.pem"
ok "SSL certificates pre-generated"
else
warn "SSL cert generation failed - nginx may not start"
fi
# ══════════════════════════════════════════════════════════════════
# Step 5: Network detection & kiosk scripts
@ -938,8 +941,8 @@ log "5/8 Installing SecuBox scripts..."
mkdir -p "${ROOTFS}/usr/sbin"
mkdir -p "${ROOTFS}/usr/lib/secubox"
# Copy scripts (including kiosk-launcher for robust startup)
for script in secubox-net-detect secubox-kiosk-setup secubox-cmdline-handler secubox-kiosk-launcher; do
# Copy scripts (including kiosk-launcher for robust startup and TUI)
for script in secubox-net-detect secubox-kiosk-setup secubox-cmdline-handler secubox-kiosk-launcher secubox-console-tui; do
if [[ -f "${SCRIPT_DIR}/sbin/${script}" ]]; then
cp "${SCRIPT_DIR}/sbin/${script}" "${ROOTFS}/usr/sbin/"
chmod +x "${ROOTFS}/usr/sbin/${script}"
@ -952,9 +955,9 @@ if [[ -f "${SCRIPT_DIR}/firstboot.sh" ]]; then
chmod +x "${ROOTFS}/usr/lib/secubox/firstboot.sh"
fi
# Systemd services (including wayland variant for kiosk)
# Systemd services (including wayland variant for kiosk and TUI)
mkdir -p "${ROOTFS}/etc/systemd/system"
for svc in secubox-net-detect secubox-cmdline secubox-kiosk secubox-kiosk-wayland; do
for svc in secubox-net-detect secubox-cmdline secubox-kiosk secubox-kiosk-wayland secubox-console-tui; do
if [[ -f "${SCRIPT_DIR}/systemd/${svc}.service" ]]; then
cp "${SCRIPT_DIR}/systemd/${svc}.service" "${ROOTFS}/etc/systemd/system/"
fi

View File

@ -449,29 +449,32 @@ ok "SecuBox packages installed"
# ── Pre-generate SSL certificates for nginx ─────────────────────────
# (firstboot normally does this, but nginx needs certs to start)
# Generate certs on HOST (chroot may lack /dev/urandom) and copy them in
log "Pre-generating SSL certificates..."
mkdir -p "${ROOTFS}/etc/secubox/tls"
chroot "${ROOTFS}" openssl req -x509 -newkey rsa:2048 -days 365 \
-keyout /etc/secubox/tls/key.pem \
-out /etc/secubox/tls/cert.pem \
-nodes -subj "/CN=secubox-rpi/O=CyberMind SecuBox/C=FR" \
-addext "subjectAltName=DNS:localhost,DNS:secubox.local,IP:127.0.0.1,IP:192.168.1.1" \
2>/dev/null || warn "SSL cert generation failed"
chmod 640 "${ROOTFS}/etc/secubox/tls/key.pem" 2>/dev/null || true
chmod 644 "${ROOTFS}/etc/secubox/tls/cert.pem" 2>/dev/null || true
# Create secubox directories
mkdir -p "${ROOTFS}/etc/secubox"
mkdir -p "${ROOTFS}/run/secubox"
mkdir -p "${ROOTFS}/var/lib/secubox"
# Generate on host system
openssl req -x509 -newkey rsa:2048 -days 365 \
-keyout "${ROOTFS}/etc/secubox/tls/key.pem" \
-out "${ROOTFS}/etc/secubox/tls/cert.pem" \
-nodes -subj "/CN=secubox-rpi/O=CyberMind SecuBox/C=FR" \
-addext "subjectAltName=DNS:localhost,DNS:secubox.local,IP:127.0.0.1,IP:192.168.1.1" \
2>/dev/null
if [[ -f "${ROOTFS}/etc/secubox/tls/cert.pem" ]]; then
chmod 640 "${ROOTFS}/etc/secubox/tls/key.pem"
chmod 644 "${ROOTFS}/etc/secubox/tls/cert.pem"
ok "SSL certificates pre-generated"
else
warn "SSL cert generation failed - nginx may not start"
fi
# Enable nginx for API proxying
ln -sf /usr/lib/systemd/system/nginx.service \
"${ROOTFS}/etc/systemd/system/multi-user.target.wants/nginx.service" 2>/dev/null || true
ok "SSL certificates pre-generated"
# ══════════════════════════════════════════════════════════════════
# Step 4b: Install kernel (with initramfs disabled to avoid QEMU slowness)
# ══════════════════════════════════════════════════════════════════

354
image/sbin/secubox-console-tui Executable file
View File

@ -0,0 +1,354 @@
#!/bin/bash
# ══════════════════════════════════════════════════════════════════
# SecuBox Console TUI — Text-based Dashboard Interface
# Provides system status and basic controls in terminal mode
# ══════════════════════════════════════════════════════════════════
set -u
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
NC='\033[0m'
BOLD='\033[1m'
# Box drawing characters
H_LINE="═"
V_LINE="║"
TL_CORNER="╔"
TR_CORNER="╗"
BL_CORNER="╚"
BR_CORNER="╝"
# Get terminal size
update_size() {
COLS=$(tput cols 2>/dev/null || echo 80)
ROWS=$(tput lines 2>/dev/null || echo 24)
}
# Draw a horizontal line
draw_line() {
local char="${1:-$H_LINE}"
local width="${2:-$COLS}"
printf '%*s' "$width" '' | tr ' ' "$char"
}
# Center text
center() {
local text="$1"
local width="${2:-$COLS}"
local text_len=${#text}
local padding=$(( (width - text_len) / 2 ))
printf "%*s%s%*s" "$padding" "" "$text" "$padding" ""
}
# Print status indicator
status_icon() {
local status="$1"
case "$status" in
ok|active|running) echo -e "${GREEN}●${NC}" ;;
warn|warning) echo -e "${YELLOW}●${NC}" ;;
error|failed|dead) echo -e "${RED}●${NC}" ;;
unknown|inactive) echo -e "${WHITE}○${NC}" ;;
*) echo -e "${WHITE}○${NC}" ;;
esac
}
# Get service status
get_service_status() {
local svc="$1"
if systemctl is-active "$svc" &>/dev/null; then
echo "active"
elif systemctl is-failed "$svc" &>/dev/null; then
echo "failed"
else
echo "inactive"
fi
}
# Get network info
get_network_info() {
local ip=$(hostname -I 2>/dev/null | awk '{print $1}')
echo "${ip:-No IP}"
}
# Get memory usage
get_memory() {
free -h 2>/dev/null | awk '/^Mem:/{printf "%s/%s", $3, $2}'
}
# Get disk usage
get_disk() {
df -h / 2>/dev/null | awk 'NR==2{printf "%s/%s (%s)", $3, $2, $5}'
}
# Get uptime
get_uptime() {
uptime -p 2>/dev/null | sed 's/up //' || uptime | awk -F'up ' '{print $2}' | awk -F',' '{print $1}'
}
# Get CPU load
get_load() {
cut -d' ' -f1-3 /proc/loadavg 2>/dev/null
}
# Clear screen and draw header
draw_header() {
clear
update_size
echo -e "${CYAN}${BOLD}"
center "╔════════════════════════════════════════════════════════════╗"
center "║ SecuBox Console Dashboard ║"
center "║ CyberMind Security ║"
center "╚════════════════════════════════════════════════════════════╝"
echo -e "${NC}"
echo
}
# Draw system status section
draw_system_status() {
echo -e "${YELLOW}${BOLD} System Status${NC}"
echo -e " $(draw_line '─' 60)"
local hostname=$(hostname 2>/dev/null || echo "secubox")
local ip=$(get_network_info)
local uptime=$(get_uptime)
local load=$(get_load)
local mem=$(get_memory)
local disk=$(get_disk)
printf " ${WHITE}Hostname:${NC} %-20s ${WHITE}IP:${NC} %s\n" "$hostname" "$ip"
printf " ${WHITE}Uptime:${NC} %-20s ${WHITE}Load:${NC} %s\n" "$uptime" "$load"
printf " ${WHITE}Memory:${NC} %-20s ${WHITE}Disk:${NC} %s\n" "$mem" "$disk"
echo
}
# Draw services section
draw_services() {
echo -e "${YELLOW}${BOLD} Core Services${NC}"
echo -e " $(draw_line '─' 60)"
local services=(
"nginx:Web Server"
"secubox-firstboot:First Boot"
"nftables:Firewall"
"ssh:SSH Server"
"NetworkManager:Network Manager"
)
local col=0
for entry in "${services[@]}"; do
local svc="${entry%%:*}"
local name="${entry#*:}"
local status=$(get_service_status "$svc")
local icon=$(status_icon "$status")
printf " %s %-22s" "$icon" "$name"
((col++))
if [[ $col -ge 2 ]]; then
echo
col=0
fi
done
[[ $col -ne 0 ]] && echo
echo
}
# Draw security services
draw_security() {
echo -e "${YELLOW}${BOLD} Security Services${NC}"
echo -e " $(draw_line '─' 60)"
local services=(
"crowdsec:CrowdSec IDS"
"suricata:Suricata IPS"
"secubox-waf:WAF (HAProxy)"
"tor:Tor Network"
"wg-quick@wg0:WireGuard VPN"
)
local col=0
for entry in "${services[@]}"; do
local svc="${entry%%:*}"
local name="${entry#*:}"
local status=$(get_service_status "$svc")
local icon=$(status_icon "$status")
printf " %s %-22s" "$icon" "$name"
((col++))
if [[ $col -ge 2 ]]; then
echo
col=0
fi
done
[[ $col -ne 0 ]] && echo
echo
}
# Draw network interfaces
draw_network() {
echo -e "${YELLOW}${BOLD} Network Interfaces${NC}"
echo -e " $(draw_line '─' 60)"
ip -br addr show 2>/dev/null | head -6 | while read -r iface state addrs; do
local icon=$(status_icon "$([[ $state == "UP" ]] && echo "ok" || echo "inactive")")
printf " %s %-12s %s %s\n" "$icon" "$iface" "$state" "$addrs"
done
echo
}
# Draw menu
draw_menu() {
echo -e "${CYAN}${BOLD} Commands${NC}"
echo -e " $(draw_line '─' 60)"
echo -e " ${WHITE}r${NC} Refresh ${WHITE}s${NC} Services ${WHITE}n${NC} Network ${WHITE}l${NC} Logs"
echo -e " ${WHITE}w${NC} Web UI ${WHITE}c${NC} Config ${WHITE}h${NC} Help ${WHITE}q${NC} Quit"
echo
}
# Draw footer
draw_footer() {
echo -e " $(draw_line '─' 60)"
echo -e " ${CYAN}SecuBox Live USB${NC} | Press ${WHITE}h${NC} for help | ${WHITE}q${NC} to quit"
}
# Show help
show_help() {
clear
draw_header
echo -e "${YELLOW}${BOLD} SecuBox Console TUI - Help${NC}"
echo -e " $(draw_line '─' 60)"
echo
echo -e " ${WHITE}Navigation:${NC}"
echo -e " r - Refresh current view"
echo -e " q - Quit TUI (return to shell)"
echo
echo -e " ${WHITE}Views:${NC}"
echo -e " s - Detailed services status"
echo -e " n - Network interfaces and routes"
echo -e " l - View system logs (journalctl)"
echo
echo -e " ${WHITE}Actions:${NC}"
echo -e " w - Open Web UI in text browser (if available)"
echo -e " c - Edit configuration"
echo
echo -e " ${WHITE}Access:${NC}"
echo -e " Web UI: https://$(get_network_info)/"
echo -e " SSH: ssh root@$(get_network_info)"
echo
echo -e " Press any key to return..."
read -rsn1
}
# Show services detail
show_services() {
clear
draw_header
echo -e "${YELLOW}${BOLD} Service Status (systemctl)${NC}"
echo -e " $(draw_line '─' 60)"
echo
systemctl list-units --type=service --state=running,failed --no-pager --no-legend 2>/dev/null | \
grep -E 'secubox|nginx|crowdsec|suricata|tor|wireguard|nftables|ssh|network' | \
head -20 | while read -r unit load active sub desc; do
local icon=$(status_icon "$active")
printf " %s %-35s %s\n" "$icon" "$unit" "$active"
done
echo
echo -e " Press any key to return..."
read -rsn1
}
# Show network detail
show_network() {
clear
draw_header
echo -e "${YELLOW}${BOLD} Network Configuration${NC}"
echo -e " $(draw_line '─' 60)"
echo
echo -e " ${WHITE}Interfaces:${NC}"
ip -br addr show 2>/dev/null | head -10
echo
echo -e " ${WHITE}Routes:${NC}"
ip route show 2>/dev/null | head -8
echo
echo -e " ${WHITE}DNS:${NC}"
grep nameserver /etc/resolv.conf 2>/dev/null | head -3
echo
echo -e " Press any key to return..."
read -rsn1
}
# Show logs
show_logs() {
clear
journalctl -f --no-pager -n 50 2>/dev/null || {
echo "Press q to return..."
read -rsn1
}
}
# Open web browser
open_web() {
local url="https://$(get_network_info)/"
if command -v w3m &>/dev/null; then
w3m "$url"
elif command -v lynx &>/dev/null; then
lynx "$url"
elif command -v links &>/dev/null; then
links "$url"
else
clear
draw_header
echo -e " ${RED}No text browser installed${NC}"
echo -e " Access the Web UI at: ${WHITE}$url${NC}"
echo
echo -e " Press any key to return..."
read -rsn1
fi
}
# Main dashboard
main_dashboard() {
draw_header
draw_system_status
draw_services
draw_security
draw_menu
draw_footer
}
# Main loop
main() {
# Hide cursor
tput civis 2>/dev/null
trap 'tput cnorm 2>/dev/null; clear; exit 0' EXIT INT TERM
while true; do
main_dashboard
# Read single key with timeout for auto-refresh
if read -rsn1 -t 30 key; then
case "$key" in
r|R) continue ;;
s|S) show_services ;;
n|N) show_network ;;
l|L) show_logs ;;
h|H) show_help ;;
w|W) open_web ;;
q|Q) break ;;
*) continue ;;
esac
fi
done
# Restore cursor
tput cnorm 2>/dev/null
clear
}
main "$@"

View File

@ -433,6 +433,11 @@ main() {
exec su -s /bin/bash "$KIOSK_USER" -c \
"export HOME='$KIOSK_HOME' XDG_RUNTIME_DIR='$XDG_RUNTIME_DIR' XDG_SESSION_TYPE=wayland KIOSK_URL='$KIOSK_URL' WLR_LIBINPUT_NO_DEVICES=1 WLR_NO_HARDWARE_CURSORS=1 WLR_RENDERER_ALLOW_SOFTWARE=1 WLR_RENDERER=pixman; exec /usr/bin/cage -s -- '$KIOSK_HOME/start-kiosk.sh'"
;;
tui)
log "Launching SecuBox Console TUI..."
# Run the TUI interface on console
exec /usr/sbin/secubox-console-tui
;;
*)
err "Unknown mode: $mode"
exit 1

View File

@ -0,0 +1,25 @@
[Unit]
Description=SecuBox Console TUI Dashboard
Documentation=https://secubox.in/docs/tui
After=multi-user.target
After=network-online.target
After=secubox-firstboot.service
# Conflicts with kiosk mode
Conflicts=secubox-kiosk.service
[Service]
Type=simple
ExecStartPre=/bin/sh -c '[ -f /var/lib/secubox/.tui-enabled ] || exit 1'
ExecStart=/usr/sbin/secubox-console-tui
Restart=on-failure
RestartSec=5
StandardInput=tty
StandardOutput=tty
TTYPath=/dev/tty1
TTYReset=yes
TTYVHangup=yes
TTYVTDisallocate=yes
[Install]
WantedBy=multi-user.target