diff --git a/apps/rego-tunnel-linux/config.json b/apps/rego-tunnel-linux/config.json index 8feeaa8..6cea3ef 100755 --- a/apps/rego-tunnel-linux/config.json +++ b/apps/rego-tunnel-linux/config.json @@ -1,15 +1,15 @@ { - "name": "Rego Tunnel", + "name": "Rego Tunnel Linux", "id": "rego-tunnel-linux", "available": true, - "short_desc": "Rego VPN client container with noVNC.", + "short_desc": "Cisco Secure Client VPN with noVNC.", "author": "alexz", "port": 8806, "categories": [ "utilities", "network" ], - "description": "OpenConnect-SSO VPN running in an isolated namespace with noVNC for first-time SSO reconnects.", + "description": "Cisco Secure Client VPN running in a container with noVNC for GUI access.", "tipi_version": 1, "version": "latest", "source": "local", @@ -17,37 +17,15 @@ "dynamic_config": true, "no_gui": false, "form_fields": [ - { - "label": "VPN URL", - "type": "text", - "env_variable": "OC_URL", - "required": true, - "default": "https://vpn.rego.net/Employees" - }, { "label": "VNC Password", "type": "password", "env_variable": "VNC_PASSWORD", "required": true, - "default": "Az@83278327$$@@" - }, - { - "label": "Server Certificate", - "type": "text", - "env_variable": "OC_SERVERCERT", - "required": true, - "default": "pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0=" - }, - { - "label": "Username", - "type": "text", - "env_variable": "OC_USER", - "required": true, - "default": "alex.zaw@rego.net" + "default": "vpnpass" } ], "supported_architectures": [ - "arm64", "amd64" ] -} \ No newline at end of file +} diff --git a/apps/rego-tunnel-linux/docker-compose.json b/apps/rego-tunnel-linux/docker-compose.json index 898cc2d..dca7df7 100755 --- a/apps/rego-tunnel-linux/docker-compose.json +++ b/apps/rego-tunnel-linux/docker-compose.json @@ -1,42 +1,20 @@ { - "schemaVersion": 2, "services": [ { "name": "rego-tunnel-linux", "image": "rego-vpn:latest", - "environment": [ - { - "key": "VNC_PASSWORD", - "value": "${VNC_PASSWORD}" - }, - { - "key": "NOVNC_PORT", - "value": "8806" - } - ], - "internalPort": 8806, - "volumes": [ - { - "hostPath": "${APP_DATA_DIR}/data", - "containerPath": "/data", - "readOnly": false, - "shared": false, - "private": false - } - ], - "devices": [ - "/dev/net/tun:/dev/net/tun" - ], - "privileged": true, - "capAdd": [ - "NET_ADMIN" - ], "isMain": true, - "extraLabels": { - "generated": true, - "runtipi.managed": true, - "runtipi.appurn": "rego-tunnel-linux:runtipi" - } + "internalPort": 8806, + "privileged": true, + "capAdd": ["NET_ADMIN"], + "devices": ["/dev/net/tun:/dev/net/tun"], + "environment": { + "VNC_PASSWORD": "${VNC_PASSWORD}", + "NOVNC_PORT": "8806" + }, + "volumes": [ + { "hostPath": "${APP_DATA_DIR}/data", "containerPath": "/data" } + ] } ] -} \ No newline at end of file +} diff --git a/apps/rego-tunnel-linux/docker-compose.yml b/apps/rego-tunnel-linux/docker-compose.yml index 4a68b70..76a7fd0 100755 --- a/apps/rego-tunnel-linux/docker-compose.yml +++ b/apps/rego-tunnel-linux/docker-compose.yml @@ -2,11 +2,11 @@ services: rego-tunnel-linux: image: rego-vpn:latest restart: unless-stopped - networks: - rego-tunnel-linux_runtipi_network: - gw_priority: 0 - tipi_main_network: - gw_priority: 1 + privileged: true + devices: + - /dev/net/tun:/dev/net/tun + cap_add: + - NET_ADMIN environment: VNC_PASSWORD: ${VNC_PASSWORD} NOVNC_PORT: "8806" @@ -14,35 +14,9 @@ services: - ${APP_PORT}:8806 volumes: - ${APP_DATA_DIR}/data:/data + networks: + - tipi_main_network labels: - generated: true traefik.enable: true - traefik.docker.network: runtipi_tipi_main_network - traefik.http.middlewares.rego-tunnel-linux-runtipi-web-redirect.redirectscheme.scheme: https - traefik.http.services.rego-tunnel-linux-runtipi.loadbalancer.server.port: "8806" - traefik.http.routers.rego-tunnel-linux-runtipi-insecure.rule: Host(`${APP_DOMAIN}`) - traefik.http.routers.rego-tunnel-linux-runtipi-insecure.entrypoints: web - traefik.http.routers.rego-tunnel-linux-runtipi-insecure.service: rego-tunnel-linux-runtipi - traefik.http.routers.rego-tunnel-linux-runtipi-insecure.middlewares: rego-tunnel-linux-runtipi-web-redirect - traefik.http.routers.rego-tunnel-linux-runtipi.rule: Host(`${APP_DOMAIN}`) - traefik.http.routers.rego-tunnel-linux-runtipi.entrypoints: websecure - traefik.http.routers.rego-tunnel-linux-runtipi.service: rego-tunnel-linux-runtipi - traefik.http.routers.rego-tunnel-linux-runtipi.tls.certresolver: myresolver + traefik.http.services.rego-tunnel-linux.loadbalancer.server.port: "8806" runtipi.managed: true - runtipi.appurn: rego-tunnel-linux:runtipi - cap_add: - - NET_ADMIN - devices: - - /dev/net/tun:/dev/net/tun - privileged: true -networks: - tipi_main_network: - name: runtipi_tipi_main_network - external: true - rego-tunnel-linux_runtipi_network: - name: rego-tunnel-linux_runtipi_network - external: false - ipam: - config: - - subnet: 10.128.23.0/24 - diff --git a/apps/rego-tunnel-linux/source/Dockerfile b/apps/rego-tunnel-linux/source/Dockerfile index 4d4aff3..5c59c7d 100755 --- a/apps/rego-tunnel-linux/source/Dockerfile +++ b/apps/rego-tunnel-linux/source/Dockerfile @@ -1,20 +1,11 @@ FROM ubuntu:24.04 ENV DEBIAN_FRONTEND=noninteractive \ - PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \ - VIRTUAL_ENV=/opt/venv \ - PATH=/opt/venv/bin:$PATH \ - QTWEBENGINE_DISABLE_SANDBOX=1 \ - QTWEBENGINE_CHROMIUM_FLAGS="--no-sandbox --disable-gpu" \ - OC_URL="https://vpn.rego.net/Employees" \ - OC_SERVERCERT="pin-sha256:HyHob3LiVmIp8ch9AzHJ9jMYqI43tO5N13oWeBLiZ/0=" \ - OC_USER="alex.zaw@rego.net" \ - OC_TOTP_SECRET="t6ypnjqvyx2yvw2l" \ - VNC_PASSWORD="Az@83278327\$\$@@" + VNC_PASSWORD="vpnpass" \ + NOVNC_PORT=8806 RUN apt-get update && apt-get install -y \ - openconnect iproute2 iptables ca-certificates \ - python3 python3-pip python3-venv \ - vpnc-scripts curl wget openssh-client \ + iproute2 iptables ca-certificates \ + curl wget openssh-client \ x11vnc xvfb fluxbox novnc websockify xterm nano oathtool \ xauth libnss3 libatk1.0-0 libatk-bridge2.0-0 \ libx11-6 libx11-xcb1 libxcomposite1 libxrandr2 libgbm1 libxdamage1 \ @@ -22,23 +13,22 @@ RUN apt-get update && apt-get install -y \ libegl1 libgl1 libopengl0 libdbus-1-3 libglib2.0-0 \ libxkbcommon0 libxkbcommon-x11-0 \ libxcb1 libxcb-cursor0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render0 libxcb-render-util0 libxcb-shm0 libxcb-xfixes0 libxcb-xinerama0 libxcb-randr0 libxcb-glx0 \ + xdotool xclip \ + libwebkit2gtk-4.1-0 libgtk-3-0 libxml2 libxss1 libcairo2 libgdk-pixbuf2.0-0 \ sudo && rm -rf /var/lib/apt/lists/* RUN apt-get update && (apt-get install -y libasound2t64 || apt-get install -y libasound2) && rm -rf /var/lib/apt/lists/* -# Python venv + Playwright + openconnect-sso -RUN python3 -m venv "$VIRTUAL_ENV" -RUN pip install --no-cache-dir openconnect-sso playwright keyring keyrings.alt && \ - python -m playwright install --with-deps chromium +COPY cisco-secure-client-linux64-5.1.11.388-core-vpn-webdeploy-k9.sh /tmp/cisco-install.sh +RUN chmod +x /tmp/cisco-install.sh && \ + /tmp/cisco-install.sh && \ + rm /tmp/cisco-install.sh -# Cloudflared (amd64) -RUN arch=$(dpkg --print-architecture) && \ - if [ "$arch" = "amd64" ]; then \ - curl -fsSL https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb -o /tmp/cloudflared.deb && \ - apt-get update && apt-get install -y /tmp/cloudflared.deb && rm -f /tmp/cloudflared.deb ; \ - else \ - echo "Install cloudflared manually for arch=$arch" && exit 1 ; \ - fi +COPY hostscan /root/.cisco/hostscan +RUN chmod -R 755 /root/.cisco/hostscan + +COPY vpn-sso.sh /root/vpn-sso.sh +RUN chmod +x /root/vpn-sso.sh COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh diff --git a/apps/rego-tunnel-linux/source/entrypoint.sh b/apps/rego-tunnel-linux/source/entrypoint.sh index c7f6c1c..5e25dc3 100755 --- a/apps/rego-tunnel-linux/source/entrypoint.sh +++ b/apps/rego-tunnel-linux/source/entrypoint.sh @@ -1,109 +1,12 @@ #!/usr/bin/env bash set -euo pipefail -: "${OC_URL:?OC_URL required}" -: "${OC_SERVERCERT:?OC_SERVERCERT required}" - -NOVNC_PORT="${NOVNC_PORT:-6901}" -VNC_PASSWORD="${VNC_PASSWORD:-changeme}" +NOVNC_PORT="${NOVNC_PORT:-8806}" +VNC_PASSWORD="${VNC_PASSWORD:-vpnpass}" DISPLAY_ADDR="${DISPLAY:-:1}" -OC_INTERFACE="${OC_INTERFACE:-tun0}" -OC_USER="${OC_USER:-}" -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_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..." - -# openconnect-sso reads TOTP from keyring automatically -if [[ -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 " Rego 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 @@ -120,63 +23,38 @@ start_gui() { 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 "Rego VPN" -e /tmp/vpn-runner.sh & +start_vpnagent() { + /opt/cisco/secureclient/bin/vpnagentd -execv_instance & 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_tun() { + mkdir -p /dev/net + if [ ! -c /dev/net/tun ]; then + mknod /dev/net/tun c 10 200 + chmod 600 /dev/net/tun + fi } 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" - break - fi - sleep 2 - done - ) & + sysctl -w net.ipv4.ip_forward=1 >/dev/null 2>&1 || true +} + +start_terminal() { + sleep 1 + xterm -fa 'Monospace' -fs 11 -bg black -fg white -geometry 120x35+50+50 \ + -T "Rego VPN" -e bash & + pids+=($!) } trap 'kill 0' INT TERM -# Always start GUI now -setup_keyring -create_vpn_command -create_vpn_script -start_gui -start_vpn_terminal +echo "Starting Rego VPN container..." +setup_tun setup_nat -start_cloudflared -start_ssh_tunnel +start_gui +start_vpnagent +start_terminal +echo "All services started. noVNC available on port $NOVNC_PORT" wait