Configure Jetson Orin with Tailscale client connecting to Headscale coordination server at tailscale.vayrette.com:8180. Device registers as 'saltylab-orin' with persistent auth key for unattended login. Features: - systemd auto-start and restart on WiFi drops - Persistent auth key storage at /opt/saltybot/tailscale-auth.key - SSH + HTTP access over Tailscale tailnet (encrypted WireGuard) - IP forwarding enabled for relay/exit node capability - WiFi resilience with aggressive restart policy - MQTT reporting of VPN status, IP, and connection type Components added: - jetson/scripts/setup-tailscale.sh: Tailscale package installation - jetson/scripts/headscale-auth-helper.sh: Auth key management utility - jetson/systemd/tailscale-vpn.service: systemd service unit - jetson/docs/headscale-vpn-setup.md: Comprehensive setup documentation - saltybot_cellular/vpn_status_node.py: ROS2 node for MQTT reporting Updated: - jetson/systemd/install_systemd.sh: Include tailscale-vpn.service - jetson/scripts/setup-jetson.sh: Add Tailscale setup steps Access patterns: - SSH: ssh user@saltylab-orin.tail12345.ts.net - HTTP: http://saltylab-orin.tail12345.ts.net:port - Direct IP: 100.x.x.x (Tailscale allocated address) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
132 lines
3.8 KiB
Bash
Executable File
132 lines
3.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# headscale-auth-helper.sh — Manage Headscale auth key persistence
|
|
# Generates, stores, and validates auth keys for unattended Tailscale login
|
|
# Usage:
|
|
# sudo bash headscale-auth-helper.sh generate
|
|
# sudo bash headscale-auth-helper.sh validate
|
|
# sudo bash headscale-auth-helper.sh show
|
|
# sudo bash headscale-auth-helper.sh revoke
|
|
|
|
set -euo pipefail
|
|
|
|
HEADSCALE_SERVER="https://tailscale.vayrette.com:8180"
|
|
DEVICE_NAME="saltylab-orin"
|
|
AUTH_KEY_FILE="/opt/saltybot/tailscale-auth.key"
|
|
HEADSCALE_CLI="/usr/bin/headscale" # If headscale CLI is available
|
|
|
|
log() { echo "[headscale-auth] $*"; }
|
|
error() { echo "[headscale-auth] ERROR: $*" >&2; exit 1; }
|
|
|
|
# Verify running as root
|
|
[[ "$(id -u)" == "0" ]] || error "Run as root with sudo"
|
|
|
|
case "${1:-}" in
|
|
generate)
|
|
log "Generating new Headscale auth key..."
|
|
log "This requires access to Headscale admin console."
|
|
log ""
|
|
log "Manual steps:"
|
|
log " 1. SSH to Headscale server"
|
|
log " 2. Run: headscale preauthkeys create --expiration 2160h --user default"
|
|
log " 3. Copy the key"
|
|
log " 4. Paste when prompted:"
|
|
read -rsp "Enter auth key: " key
|
|
echo ""
|
|
|
|
if [ -z "$key" ]; then
|
|
error "Auth key cannot be empty"
|
|
fi
|
|
|
|
mkdir -p "$(dirname "${AUTH_KEY_FILE}")"
|
|
echo "$key" > "${AUTH_KEY_FILE}"
|
|
chmod 600 "${AUTH_KEY_FILE}"
|
|
|
|
log "Auth key saved to ${AUTH_KEY_FILE}"
|
|
log "Next: sudo systemctl restart tailscale-vpn"
|
|
;;
|
|
|
|
validate)
|
|
log "Validating auth key..."
|
|
if [ ! -f "${AUTH_KEY_FILE}" ]; then
|
|
error "Auth key file not found: ${AUTH_KEY_FILE}"
|
|
fi
|
|
|
|
key=$(cat "${AUTH_KEY_FILE}")
|
|
if [ -z "$key" ]; then
|
|
error "Auth key is empty"
|
|
fi
|
|
|
|
if [[ ! "$key" =~ ^tskey_ ]]; then
|
|
error "Invalid auth key format (should start with tskey_)"
|
|
fi
|
|
|
|
log "✓ Auth key format valid"
|
|
log " File: ${AUTH_KEY_FILE}"
|
|
log " Key: ${key:0:10}..."
|
|
;;
|
|
|
|
show)
|
|
log "Auth key status:"
|
|
if [ ! -f "${AUTH_KEY_FILE}" ]; then
|
|
log " Status: NOT CONFIGURED"
|
|
log " Run: sudo bash headscale-auth-helper.sh generate"
|
|
else
|
|
key=$(cat "${AUTH_KEY_FILE}")
|
|
log " Status: CONFIGURED"
|
|
log " Key: ${key:0:15}..."
|
|
|
|
# Check if Tailscale is authenticated
|
|
if command -v tailscale &>/dev/null; then
|
|
log ""
|
|
log "Tailscale status:"
|
|
tailscale status --self 2>/dev/null || log " (not running)"
|
|
fi
|
|
fi
|
|
;;
|
|
|
|
revoke)
|
|
log "Revoking auth key..."
|
|
if [ ! -f "${AUTH_KEY_FILE}" ]; then
|
|
error "Auth key file not found"
|
|
fi
|
|
|
|
key=$(cat "${AUTH_KEY_FILE}")
|
|
read -rp "Revoke key ${key:0:15}...? [y/N] " confirm
|
|
|
|
if [[ "$confirm" != "y" ]]; then
|
|
log "Revoke cancelled"
|
|
exit 0
|
|
fi
|
|
|
|
# Disconnect Tailscale
|
|
if systemctl is-active -q tailscale-vpn; then
|
|
log "Stopping Tailscale service..."
|
|
systemctl stop tailscale-vpn
|
|
fi
|
|
|
|
# Remove key file
|
|
rm -f "${AUTH_KEY_FILE}"
|
|
log "Auth key revoked and removed"
|
|
log "Run: sudo bash headscale-auth-helper.sh generate"
|
|
;;
|
|
|
|
*)
|
|
cat << 'EOF'
|
|
Usage: sudo bash headscale-auth-helper.sh <command>
|
|
|
|
Commands:
|
|
generate - Prompt for new Headscale auth key and save it
|
|
validate - Validate existing auth key format
|
|
show - Display auth key status and Tailscale connection
|
|
revoke - Revoke and remove the stored auth key
|
|
|
|
Examples:
|
|
sudo bash headscale-auth-helper.sh generate
|
|
sudo bash headscale-auth-helper.sh show
|
|
sudo bash headscale-auth-helper.sh revoke
|
|
|
|
EOF
|
|
exit 1
|
|
;;
|
|
esac
|