cistech-tunnel: Mount entrypoint.sh from shared folder
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
No more image rebuild needed for script changes. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,9 @@
|
||||
],
|
||||
"volumes": [
|
||||
{ "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/root" },
|
||||
{ "hostPath": "${APP_DATA_DIR}", "containerPath": "/runtime" }
|
||||
{ "hostPath": "${APP_DATA_DIR}", "containerPath": "/runtime" },
|
||||
{ "hostPath": "/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared", "containerPath": "/shared" },
|
||||
{ "hostPath": "/etc/runtipi/repos/runtipi/apps/cistech-tunnel/shared/entrypoint.sh", "containerPath": "/entrypoint.sh", "readOnly": true }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
224
apps/cistech-tunnel/shared/entrypoint.sh
Normal file
224
apps/cistech-tunnel/shared/entrypoint.sh
Normal file
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
: "${OC_URL:?OC_URL required}"
|
||||
|
||||
# Auto-fetch server certificate pin if not provided
|
||||
get_server_cert_pin() {
|
||||
local url="$1"
|
||||
local host=$(echo "$url" | sed -E 's|https?://([^/:]+).*|\1|')
|
||||
local port=443
|
||||
|
||||
echo "Fetching certificate pin from $host:$port..." >&2
|
||||
|
||||
# Get certificate and compute pin-sha256
|
||||
local pin=$(echo | openssl s_client -connect "$host:$port" -servername "$host" 2>/dev/null | \
|
||||
openssl x509 -pubkey -noout 2>/dev/null | \
|
||||
openssl pkey -pubin -outform DER 2>/dev/null | \
|
||||
openssl dgst -sha256 -binary | \
|
||||
base64)
|
||||
|
||||
if [[ -n "$pin" ]]; then
|
||||
echo "pin-sha256:$pin"
|
||||
else
|
||||
echo "ERROR: Failed to fetch certificate from $host" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get or fetch OC_SERVERCERT
|
||||
if [[ -z "${OC_SERVERCERT:-}" ]]; then
|
||||
OC_SERVERCERT=$(get_server_cert_pin "$OC_URL")
|
||||
echo "Auto-detected server cert: $OC_SERVERCERT"
|
||||
fi
|
||||
|
||||
NOVNC_PORT="${NOVNC_PORT:-6901}"
|
||||
VNC_PASSWORD="${VNC_PASSWORD:-changeme}"
|
||||
DISPLAY_ADDR="${DISPLAY:-:1}"
|
||||
OC_INTERFACE="${OC_INTERFACE:-tun0}"
|
||||
OC_USER="${OC_USER:-}"
|
||||
OC_PASSWORD="${OC_PASSWORD:-}"
|
||||
OC_TOTP_SECRET="${OC_TOTP_SECRET:-}"
|
||||
|
||||
# Default to hidden browser if OC_USER is set
|
||||
if [[ -n "$OC_USER" ]]; then
|
||||
OC_SSO_ARGS_DEFAULT="--browser-display-mode hidden -u $OC_USER"
|
||||
else
|
||||
OC_SSO_ARGS_DEFAULT="--browser-display-mode shown"
|
||||
fi
|
||||
|
||||
CLOUDFLARED_MODE="${CLOUDFLARED_MODE:-off}" # off|token|config
|
||||
CLOUDFLARED_TOKEN="${CLOUDFLARED_TOKEN:-}"
|
||||
SSH_TUNNEL_ENABLE="${SSH_TUNNEL_ENABLE:-0}"
|
||||
SSH_DEST="${SSH_DEST:-zawa@10.3.1.201}"
|
||||
SSH_FORWARDS="${SSH_FORWARDS:-0.0.0.0:8090:localhost:8090}"
|
||||
|
||||
pids=()
|
||||
|
||||
# Setup keyring with TOTP secret if provided
|
||||
setup_keyring() {
|
||||
if [[ -n "$OC_TOTP_SECRET" && -n "$OC_USER" ]]; then
|
||||
python3 -c "
|
||||
import keyring
|
||||
keyring.set_password('openconnect-sso', 'totp/$OC_USER', '$OC_TOTP_SECRET'.upper())
|
||||
print('TOTP secret stored in keyring for $OC_USER')
|
||||
"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create vpn_connect command in PATH and save environment
|
||||
create_vpn_command() {
|
||||
# Save environment variables to a file
|
||||
cat > /etc/vpn.env << ENVFILE
|
||||
export OC_URL="$OC_URL"
|
||||
export OC_SERVERCERT="$OC_SERVERCERT"
|
||||
export OC_INTERFACE="$OC_INTERFACE"
|
||||
export OC_USER="$OC_USER"
|
||||
export OC_PASSWORD="$OC_PASSWORD"
|
||||
export OC_SSO_ARGS_DEFAULT="$OC_SSO_ARGS_DEFAULT"
|
||||
export OC_SSO_ARGS="${OC_SSO_ARGS:-$OC_SSO_ARGS_DEFAULT}"
|
||||
export OC_AUTHGROUP="${OC_AUTHGROUP:-}"
|
||||
export OC_USERAGENT="${OC_USERAGENT:-}"
|
||||
export OC_EXTRA_ARGS="${OC_EXTRA_ARGS:-}"
|
||||
export OC_TOTP_SECRET="$OC_TOTP_SECRET"
|
||||
export DISPLAY=":1"
|
||||
ENVFILE
|
||||
|
||||
# Build openconnect command
|
||||
OPENCONNECT_CMD="/usr/sbin/openconnect --protocol=anyconnect --servercert $OC_SERVERCERT --interface $OC_INTERFACE --script /usr/share/vpnc-scripts/vpnc-script"
|
||||
[[ -n "${OC_AUTHGROUP:-}" ]] && OPENCONNECT_CMD+=" --authgroup $OC_AUTHGROUP"
|
||||
[[ -n "${OC_USERAGENT:-}" ]] && OPENCONNECT_CMD+=" --useragent $OC_USERAGENT"
|
||||
[[ -n "${OC_EXTRA_ARGS:-}" ]] && OPENCONNECT_CMD+=" ${OC_EXTRA_ARGS}"
|
||||
echo "export OPENCONNECT_CMD=\"$OPENCONNECT_CMD\"" >> /etc/vpn.env
|
||||
|
||||
cat > /usr/local/bin/vpn_connect << 'VPNCMD'
|
||||
#!/usr/bin/env bash
|
||||
source /etc/vpn.env
|
||||
echo "[$(date)] Starting VPN connection..."
|
||||
|
||||
# Set password for openconnect
|
||||
export OPENCONNECT_PASSWORD="$OC_PASSWORD"
|
||||
|
||||
# openconnect-sso reads TOTP from keyring automatically
|
||||
# Pass password via stdin for SSO form if needed
|
||||
if [[ -n "$OC_USER" && -n "$OC_PASSWORD" ]]; then
|
||||
echo "$OC_PASSWORD" | openconnect-sso -s "$OC_URL" ${OC_SSO_ARGS:-$OC_SSO_ARGS_DEFAULT} -- $OPENCONNECT_CMD
|
||||
elif [[ -n "$OC_USER" ]]; then
|
||||
echo "" | openconnect-sso -s "$OC_URL" ${OC_SSO_ARGS:-$OC_SSO_ARGS_DEFAULT} -- $OPENCONNECT_CMD
|
||||
else
|
||||
openconnect-sso -s "$OC_URL" ${OC_SSO_ARGS:-$OC_SSO_ARGS_DEFAULT} -- $OPENCONNECT_CMD
|
||||
fi
|
||||
VPNCMD
|
||||
chmod +x /usr/local/bin/vpn_connect
|
||||
}
|
||||
|
||||
# Create VPN runner script that keeps shell open
|
||||
create_vpn_script() {
|
||||
cat > /tmp/vpn-runner.sh << 'VPNSCRIPT'
|
||||
#!/usr/bin/env bash
|
||||
cd /root
|
||||
|
||||
echo "============================================"
|
||||
echo " Cistech VPN Container"
|
||||
echo "============================================"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " vpn_connect - Start/restart VPN connection"
|
||||
echo " Ctrl+C - Stop auto-reconnect and drop to shell"
|
||||
echo ""
|
||||
echo "Starting VPN with auto-reconnect..."
|
||||
echo ""
|
||||
|
||||
while true; do
|
||||
vpn_connect
|
||||
echo ""
|
||||
echo "[$(date)] VPN disconnected. Reconnecting in 10 seconds..."
|
||||
echo "(Press Ctrl+C to stop auto-reconnect)"
|
||||
sleep 10
|
||||
done
|
||||
VPNSCRIPT
|
||||
chmod +x /tmp/vpn-runner.sh
|
||||
}
|
||||
|
||||
start_gui() {
|
||||
mkdir -p /root/.vnc
|
||||
x11vnc -storepasswd "$VNC_PASSWORD" /root/.vnc/pass >/dev/null 2>&1 || true
|
||||
rm -f /tmp/.X1-lock /tmp/.X11-unix/X1 2>/dev/null || true
|
||||
Xvfb "$DISPLAY_ADDR" -screen 0 ${XVFB_WxHxD:-1280x800x24} +extension RANDR &
|
||||
pids+=($!)
|
||||
sleep 0.5
|
||||
export DISPLAY="$DISPLAY_ADDR"
|
||||
fluxbox >/tmp/fluxbox.log 2>&1 &
|
||||
pids+=($!)
|
||||
x11vnc -display "$DISPLAY_ADDR" -rfbauth /root/.vnc/pass -forever -shared -rfbport 5900 -quiet &
|
||||
pids+=($!)
|
||||
websockify --web=/usr/share/novnc/ 0.0.0.0:"$NOVNC_PORT" localhost:5900 >/tmp/websockify.log 2>&1 &
|
||||
pids+=($!)
|
||||
}
|
||||
|
||||
start_vpn_terminal() {
|
||||
# Start xterm with VPN script
|
||||
sleep 1
|
||||
xterm -fa 'Monospace' -fs 11 -bg black -fg white -geometry 120x35+50+50 \
|
||||
-T "Cistech VPN" -e /tmp/vpn-runner.sh &
|
||||
pids+=($!)
|
||||
}
|
||||
|
||||
start_cloudflared() {
|
||||
case "$CLOUDFLARED_MODE" in
|
||||
token)
|
||||
[ -n "$CLOUDFLARED_TOKEN" ] && cloudflared tunnel run --token "$CLOUDFLARED_TOKEN" >/tmp/cloudflared.log 2>&1 &
|
||||
pids+=($!)
|
||||
;;
|
||||
config)
|
||||
cloudflared --no-autoupdate --config /etc/cloudflared/config.yml tunnel run >/tmp/cloudflared.log 2>&1 &
|
||||
pids+=($!)
|
||||
;;
|
||||
off|*)
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
start_ssh_tunnel() {
|
||||
[ "$SSH_TUNNEL_ENABLE" = "1" ] || return 0
|
||||
IFS=',' read -ra LINES <<< "$SSH_FORWARDS"
|
||||
args=(-N -o StrictHostKeyChecking=no -o ServerAliveInterval=60)
|
||||
for m in "${LINES[@]}"; do args+=(-L "$m"); done
|
||||
ssh "${args[@]}" "$SSH_DEST" &
|
||||
pids+=($!)
|
||||
}
|
||||
|
||||
setup_nat() {
|
||||
(
|
||||
for i in {1..60}; do
|
||||
if ip link show "$OC_INTERFACE" >/dev/null 2>&1; then
|
||||
sysctl -w net.ipv4.ip_forward=1 >/dev/null
|
||||
iptables -t nat -C POSTROUTING -o "$OC_INTERFACE" -j MASQUERADE 2>/dev/null || \
|
||||
iptables -t nat -A POSTROUTING -o "$OC_INTERFACE" -j MASQUERADE
|
||||
echo "NAT enabled on $OC_INTERFACE"
|
||||
|
||||
# Trigger host routing service
|
||||
if [ -d /runtime ]; then
|
||||
touch /runtime/restart-routing
|
||||
echo "Host routing trigger sent"
|
||||
fi
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
) &
|
||||
}
|
||||
|
||||
trap 'kill 0' INT TERM
|
||||
|
||||
# Always start GUI now
|
||||
setup_keyring
|
||||
create_vpn_command
|
||||
create_vpn_script
|
||||
start_gui
|
||||
start_vpn_terminal
|
||||
setup_nat
|
||||
start_cloudflared
|
||||
start_ssh_tunnel
|
||||
|
||||
wait
|
||||
Reference in New Issue
Block a user