Cleanup: Remove reverse SSH tunnel code, fix documentation accuracy
Agent-Logs-Url: https://github.com/naturallaw777/staging_alpha/sessions/3941ead1-cb20-4686-92bb-46e447791ae3 Co-authored-by: naturallaw777 <99053422+naturallaw777@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
af14622e45
commit
3ca15d0da4
@@ -44,7 +44,7 @@ This guide covers the Sovran Systems remote deployment system built on [Headscal
|
|||||||
**Components:**
|
**Components:**
|
||||||
- **`sovran-provisioner.nix`** — NixOS module deployed on a separate VPS; runs Headscale + provisioning API + Caddy.
|
- **`sovran-provisioner.nix`** — NixOS module deployed on a separate VPS; runs Headscale + provisioning API + Caddy.
|
||||||
- **Live ISO** (`iso/common.nix`) — Auto-registers with the provisioning server and joins the Tailnet on boot.
|
- **Live ISO** (`iso/common.nix`) — Auto-registers with the provisioning server and joins the Tailnet on boot.
|
||||||
- **`remote-deploy.nix`** — Post-install NixOS module that uses Tailscale/Headscale for ongoing access (plus the existing reverse SSH tunnel as a fallback).
|
- **`remote-deploy.nix`** — Post-install NixOS module that uses Tailscale/Headscale for ongoing access.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -83,9 +83,6 @@ Add the following to your VPS's `/etc/nixos/configuration.nix`:
|
|||||||
domain = "prov.yourdomain.com";
|
domain = "prov.yourdomain.com";
|
||||||
headscaleDomain = "hs.yourdomain.com";
|
headscaleDomain = "hs.yourdomain.com";
|
||||||
|
|
||||||
# Optional: set a static token instead of auto-generating one
|
|
||||||
# enrollToken = "your-secret-token-here";
|
|
||||||
|
|
||||||
# Optional: customise defaults
|
# Optional: customise defaults
|
||||||
headscaleUser = "sovran-deploy"; # namespace for deploy machines
|
headscaleUser = "sovran-deploy"; # namespace for deploy machines
|
||||||
adminUser = "admin"; # namespace for your workstation
|
adminUser = "admin"; # namespace for your workstation
|
||||||
@@ -114,7 +111,7 @@ Caddy will automatically obtain TLS certificates via Let's Encrypt.
|
|||||||
cat /var/lib/sovran-provisioner/enroll-token
|
cat /var/lib/sovran-provisioner/enroll-token
|
||||||
```
|
```
|
||||||
|
|
||||||
Keep this token secret — it is used to authenticate ISO registrations. If you set `enrollToken` statically in `configuration.nix`, that value is used directly (but avoid committing secrets to version control).
|
Keep this token secret — it is used to authenticate ISO registrations. The token is auto-generated on first boot and stored at this path. You never need to set it manually. Just `cat` it from the VPS and copy it to `iso/secrets/enroll-token` before building the ISO.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -209,19 +206,18 @@ The resulting ISO is in `./result/iso/`.
|
|||||||
```
|
```
|
||||||
|
|
||||||
5. **Run the headless installer**:
|
5. **Run the headless installer**:
|
||||||
```bash
|
|
||||||
# Basic install (relay tunnel)
|
|
||||||
sudo sovran-install-headless.sh \
|
|
||||||
--disk /dev/sda \
|
|
||||||
--role server \
|
|
||||||
--deploy-key "ssh-ed25519 AAAA..." \
|
|
||||||
--relay-host relay.yourdomain.com
|
|
||||||
|
|
||||||
# With Tailscale for post-install access
|
The `--deploy-key` is your SSH public key that gets injected into `root`'s `authorized_keys` on the deployed machine. This grants full root access for initial setup. Generate it once on your workstation if you haven't already:
|
||||||
|
```bash
|
||||||
|
ssh-keygen -t ed25519 -f ~/.ssh/sovran-deploy -C "sovran-deploy"
|
||||||
|
```
|
||||||
|
After deployment is complete and you disable deploy mode, this key is removed.
|
||||||
|
|
||||||
|
```bash
|
||||||
sudo sovran-install-headless.sh \
|
sudo sovran-install-headless.sh \
|
||||||
--disk /dev/sda \
|
--disk /dev/sda \
|
||||||
--role server \
|
--role server \
|
||||||
--deploy-key "ssh-ed25519 AAAA..." \
|
--deploy-key "$(cat ~/.ssh/sovran-deploy.pub)" \
|
||||||
--headscale-server "https://hs.yourdomain.com" \
|
--headscale-server "https://hs.yourdomain.com" \
|
||||||
--headscale-key "$(headscale preauthkeys create --user sovran-deploy --expiration 2h --output json | jq -r '.key')"
|
--headscale-key "$(headscale preauthkeys create --user sovran-deploy --expiration 2h --output json | jq -r '.key')"
|
||||||
```
|
```
|
||||||
@@ -229,15 +225,17 @@ The resulting ISO is in `./result/iso/`.
|
|||||||
6. **Machine reboots into Sovran_SystemsOS** — `deploy-tailscale-connect.service` runs:
|
6. **Machine reboots into Sovran_SystemsOS** — `deploy-tailscale-connect.service` runs:
|
||||||
- Reads `/var/lib/secrets/headscale-authkey`
|
- Reads `/var/lib/secrets/headscale-authkey`
|
||||||
- Joins the Tailnet with a deterministic hostname (`sovran-<hostname>`)
|
- Joins the Tailnet with a deterministic hostname (`sovran-<hostname>`)
|
||||||
- The reverse SSH tunnel also activates if `relayHost` was set
|
|
||||||
|
|
||||||
7. **Post-install SSH and RDP**:
|
7. **Post-install SSH and RDP**:
|
||||||
```bash
|
```bash
|
||||||
# SSH over Tailnet
|
# SSH over Tailnet
|
||||||
ssh root@<tailscale-ip>
|
ssh root@<tailscale-ip>
|
||||||
|
|
||||||
# RDP over Tailnet (if desktop role)
|
# RDP over Tailnet (desktop role) — Sovran_SystemsOS uses GNOME Remote Desktop (native Wayland RDP)
|
||||||
xfreerdp /v:<tailscale-ip> /u:free /p:free
|
# Retrieve the auto-generated RDP password:
|
||||||
|
ssh root@<tailscale-ip> cat /var/lib/gnome-remote-desktop/rdp-password
|
||||||
|
# Then connect with any RDP client (Remmina, GNOME Connections, Microsoft Remote Desktop):
|
||||||
|
# Host: <tailscale-ip>:3389 User: sovran Password: <from above>
|
||||||
```
|
```
|
||||||
|
|
||||||
8. **Disable deploy mode** — edit `/etc/nixos/custom.nix` on the target, set `enable = false`, then:
|
8. **Disable deploy mode** — edit `/etc/nixos/custom.nix` on the target, set `enable = false`, then:
|
||||||
@@ -254,18 +252,20 @@ The resulting ISO is in `./result/iso/`.
|
|||||||
```bash
|
```bash
|
||||||
# Over Tailnet
|
# Over Tailnet
|
||||||
ssh root@100.64.x.x
|
ssh root@100.64.x.x
|
||||||
|
|
||||||
# Over reverse tunnel (if configured)
|
|
||||||
ssh -p 2222 root@relay.yourdomain.com
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### RDP (desktop/server roles)
|
### RDP (desktop/server roles)
|
||||||
|
|
||||||
|
Sovran_SystemsOS uses **GNOME Remote Desktop** (native Wayland RDP — not xfreerdp). The RDP service auto-generates credentials on first boot.
|
||||||
|
|
||||||
|
**Username:** `sovran`
|
||||||
|
**Password:** auto-generated — retrieve it via SSH:
|
||||||
```bash
|
```bash
|
||||||
# Over Tailnet
|
ssh root@<tailscale-ip> cat /var/lib/gnome-remote-desktop/rdp-password
|
||||||
xfreerdp /v:100.64.x.x /u:free /p:free /dynamic-resolution
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Connect using any RDP client (Remmina, GNOME Connections, Microsoft Remote Desktop) to `<tailscale-ip>:3389`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Security Model
|
## Security Model
|
||||||
@@ -355,7 +355,7 @@ Then rebuild:
|
|||||||
nixos-rebuild switch
|
nixos-rebuild switch
|
||||||
```
|
```
|
||||||
|
|
||||||
This stops the reverse tunnel and Tailscale connect services.
|
This stops the Tailscale connect service.
|
||||||
|
|
||||||
### Revoke All Active Pre-Auth Keys
|
### Revoke All Active Pre-Auth Keys
|
||||||
|
|
||||||
|
|||||||
@@ -10,10 +10,6 @@ Options:
|
|||||||
--data-disk /dev/sdb Data disk for Bitcoin (optional)
|
--data-disk /dev/sdb Data disk for Bitcoin (optional)
|
||||||
--role server|desktop|node Installation role (default: server)
|
--role server|desktop|node Installation role (default: server)
|
||||||
--deploy-key "ssh-ed25519 AAAA..." SSH pubkey for remote access after install
|
--deploy-key "ssh-ed25519 AAAA..." SSH pubkey for remote access after install
|
||||||
--relay-host HOST Reverse tunnel relay hostname
|
|
||||||
--relay-user USER Relay username (default: deploy)
|
|
||||||
--relay-port PORT Relay SSH port (default: 22)
|
|
||||||
--tunnel-port PORT Reverse tunnel port on relay (default: 2222)
|
|
||||||
--headscale-server URL Headscale login server for post-install Tailnet
|
--headscale-server URL Headscale login server for post-install Tailnet
|
||||||
--headscale-key KEY Headscale pre-auth key for the installed OS
|
--headscale-key KEY Headscale pre-auth key for the installed OS
|
||||||
USAGE
|
USAGE
|
||||||
@@ -26,10 +22,6 @@ DISK=""
|
|||||||
DATA_DISK=""
|
DATA_DISK=""
|
||||||
ROLE="server"
|
ROLE="server"
|
||||||
DEPLOY_KEY=""
|
DEPLOY_KEY=""
|
||||||
RELAY_HOST=""
|
|
||||||
RELAY_USER="deploy"
|
|
||||||
RELAY_PORT="22"
|
|
||||||
TUNNEL_PORT="2222"
|
|
||||||
HEADSCALE_SERVER=""
|
HEADSCALE_SERVER=""
|
||||||
HEADSCALE_KEY=""
|
HEADSCALE_KEY=""
|
||||||
|
|
||||||
@@ -58,10 +50,6 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--data-disk) DATA_DISK="$2"; shift 2 ;;
|
--data-disk) DATA_DISK="$2"; shift 2 ;;
|
||||||
--role) ROLE="$2"; shift 2 ;;
|
--role) ROLE="$2"; shift 2 ;;
|
||||||
--deploy-key) DEPLOY_KEY="$2"; shift 2 ;;
|
--deploy-key) DEPLOY_KEY="$2"; shift 2 ;;
|
||||||
--relay-host) RELAY_HOST="$2"; shift 2 ;;
|
|
||||||
--relay-user) RELAY_USER="$2"; shift 2 ;;
|
|
||||||
--relay-port) RELAY_PORT="$2"; shift 2 ;;
|
|
||||||
--tunnel-port) TUNNEL_PORT="$2"; shift 2 ;;
|
|
||||||
--headscale-server) HEADSCALE_SERVER="$2"; shift 2 ;;
|
--headscale-server) HEADSCALE_SERVER="$2"; shift 2 ;;
|
||||||
--headscale-key) HEADSCALE_KEY="$2"; shift 2 ;;
|
--headscale-key) HEADSCALE_KEY="$2"; shift 2 ;;
|
||||||
-h|--help)
|
-h|--help)
|
||||||
@@ -220,21 +208,17 @@ EOF
|
|||||||
# ── Step 10: Write custom.nix with deploy config ──────────────────────────────
|
# ── Step 10: Write custom.nix with deploy config ──────────────────────────────
|
||||||
log "=== Writing custom.nix ==="
|
log "=== Writing custom.nix ==="
|
||||||
|
|
||||||
if [[ -n "$DEPLOY_KEY" ]]; then
|
if [[ -n "$DEPLOY_KEY" || -n "$HEADSCALE_SERVER" ]]; then
|
||||||
cat > /mnt/etc/nixos/custom.nix <<EOF
|
{
|
||||||
{ config, lib, ... }:
|
echo '{ config, lib, ... }:'
|
||||||
{
|
echo '{'
|
||||||
sovran_systemsOS.deploy = {
|
echo ' sovran_systemsOS.deploy = {'
|
||||||
enable = true;
|
echo ' enable = true;'
|
||||||
authorizedKey = "${DEPLOY_KEY}";
|
[[ -n "$DEPLOY_KEY" ]] && echo " authorizedKey = \"${DEPLOY_KEY}\";"
|
||||||
relayHost = "${RELAY_HOST}";
|
[[ -n "$HEADSCALE_SERVER" ]] && echo " headscaleServer = \"${HEADSCALE_SERVER}\";"
|
||||||
relayUser = "${RELAY_USER}";
|
echo ' };'
|
||||||
relayPort = ${RELAY_PORT};
|
echo '}'
|
||||||
reverseTunnelPort = ${TUNNEL_PORT};
|
} > /mnt/etc/nixos/custom.nix
|
||||||
$([ -n "${HEADSCALE_SERVER}" ] && echo " headscaleServer = \"${HEADSCALE_SERVER}\";")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
else
|
else
|
||||||
cp /mnt/etc/nixos/custom.template.nix /mnt/etc/nixos/custom.nix
|
cp /mnt/etc/nixos/custom.template.nix /mnt/etc/nixos/custom.nix
|
||||||
fi
|
fi
|
||||||
@@ -265,7 +249,5 @@ nixos-install \
|
|||||||
log "=== Installation complete! ==="
|
log "=== Installation complete! ==="
|
||||||
log "You can now reboot into Sovran_SystemsOS."
|
log "You can now reboot into Sovran_SystemsOS."
|
||||||
log "After reboot, the machine will be accessible via SSH on port 22 (if --deploy-key was provided)."
|
log "After reboot, the machine will be accessible via SSH on port 22 (if --deploy-key was provided)."
|
||||||
[[ -n "$RELAY_HOST" ]] && \
|
|
||||||
log "Reverse tunnel will connect to ${RELAY_USER}@${RELAY_HOST}:${RELAY_PORT} — forward port ${TUNNEL_PORT} maps to the machine's SSH."
|
|
||||||
[[ -n "$HEADSCALE_SERVER" ]] && \
|
[[ -n "$HEADSCALE_SERVER" ]] && \
|
||||||
log "Tailscale will connect to Headscale at ${HEADSCALE_SERVER} on first boot."
|
log "Tailscale will connect to Headscale at ${HEADSCALE_SERVER} on first boot."
|
||||||
|
|||||||
@@ -8,30 +8,6 @@ in
|
|||||||
options.sovran_systemsOS.deploy = {
|
options.sovran_systemsOS.deploy = {
|
||||||
enable = lib.mkEnableOption "Remote deploy mode";
|
enable = lib.mkEnableOption "Remote deploy mode";
|
||||||
|
|
||||||
relayHost = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = "SSH relay server hostname or IP for the reverse tunnel";
|
|
||||||
};
|
|
||||||
|
|
||||||
relayPort = lib.mkOption {
|
|
||||||
type = lib.types.port;
|
|
||||||
default = 22;
|
|
||||||
description = "SSH port on the relay server";
|
|
||||||
};
|
|
||||||
|
|
||||||
relayUser = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "deploy";
|
|
||||||
description = "Username on the relay server";
|
|
||||||
};
|
|
||||||
|
|
||||||
reverseTunnelPort = lib.mkOption {
|
|
||||||
type = lib.types.port;
|
|
||||||
default = 2222;
|
|
||||||
description = "Port on the relay that maps back to this machine's SSH (port 22)";
|
|
||||||
};
|
|
||||||
|
|
||||||
authorizedKey = lib.mkOption {
|
authorizedKey = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "";
|
default = "";
|
||||||
@@ -120,29 +96,6 @@ in
|
|||||||
path = [ pkgs.tailscale pkgs.coreutils ];
|
path = [ pkgs.tailscale pkgs.coreutils ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# ── Reverse tunnel service (only when relayHost is configured) ───────────
|
|
||||||
systemd.services.deploy-reverse-tunnel = lib.mkIf (cfg.relayHost != "") {
|
|
||||||
description = "Deploy reverse SSH tunnel to ${cfg.relayHost}";
|
|
||||||
wantedBy = [ "multi-user.target" ];
|
|
||||||
after = [ "network-online.target" "sshd.service" ];
|
|
||||||
wants = [ "network-online.target" ];
|
|
||||||
serviceConfig = {
|
|
||||||
Restart = "always";
|
|
||||||
RestartSec = "10s";
|
|
||||||
ExecStart = "${pkgs.openssh}/bin/ssh"
|
|
||||||
+ " -o StrictHostKeyChecking=accept-new"
|
|
||||||
+ " -o ServerAliveInterval=30"
|
|
||||||
+ " -o ServerAliveCountMax=3"
|
|
||||||
+ " -o ExitOnForwardFailure=yes"
|
|
||||||
+ " -i /var/lib/secrets/deploy-relay-key"
|
|
||||||
+ " -N"
|
|
||||||
+ " -R ${toString cfg.reverseTunnelPort}:localhost:22"
|
|
||||||
+ " -p ${toString cfg.relayPort}"
|
|
||||||
+ " ${cfg.relayUser}@${cfg.relayHost}";
|
|
||||||
};
|
|
||||||
path = [ pkgs.openssh ];
|
|
||||||
};
|
|
||||||
|
|
||||||
# ── Safety auto-expiry service ────────────────────────────────────────────
|
# ── Safety auto-expiry service ────────────────────────────────────────────
|
||||||
systemd.services.deploy-auto-expire = {
|
systemd.services.deploy-auto-expire = {
|
||||||
description = "Auto-expire remote deploy mode after 48 hours";
|
description = "Auto-expire remote deploy mode after 48 hours";
|
||||||
@@ -155,7 +108,7 @@ in
|
|||||||
script = ''
|
script = ''
|
||||||
# 48 hours = 172800 seconds
|
# 48 hours = 172800 seconds
|
||||||
sleep $((48 * 60 * 60))
|
sleep $((48 * 60 * 60))
|
||||||
systemctl stop deploy-reverse-tunnel || true
|
systemctl stop deploy-tailscale-connect || true
|
||||||
mkdir -p /etc/sovran
|
mkdir -p /etc/sovran
|
||||||
echo "expired" > /etc/sovran/deploy-mode
|
echo "expired" > /etc/sovran/deploy-mode
|
||||||
'';
|
'';
|
||||||
|
|||||||
@@ -151,12 +151,6 @@ in
|
|||||||
description = "Domain for the Headscale coordination server (e.g. hs.sovransystems.com)";
|
description = "Domain for the Headscale coordination server (e.g. hs.sovransystems.com)";
|
||||||
};
|
};
|
||||||
|
|
||||||
enrollToken = lib.mkOption {
|
|
||||||
type = lib.types.str;
|
|
||||||
default = "";
|
|
||||||
description = "Static enrollment token. If empty, one is auto-generated on first boot.";
|
|
||||||
};
|
|
||||||
|
|
||||||
headscaleUser = lib.mkOption {
|
headscaleUser = lib.mkOption {
|
||||||
type = lib.types.str;
|
type = lib.types.str;
|
||||||
default = "sovran-deploy";
|
default = "sovran-deploy";
|
||||||
@@ -251,17 +245,13 @@ in
|
|||||||
script = ''
|
script = ''
|
||||||
mkdir -p ${cfg.stateDir}
|
mkdir -p ${cfg.stateDir}
|
||||||
|
|
||||||
# Generate enrollment token if not exists and not set statically
|
# Auto-generate enrollment token on first boot if not already present
|
||||||
TOKEN_FILE="${cfg.stateDir}/enroll-token"
|
TOKEN_FILE="${cfg.stateDir}/enroll-token"
|
||||||
${if cfg.enrollToken != "" then ''
|
|
||||||
echo "${cfg.enrollToken}" > "$TOKEN_FILE"
|
|
||||||
'' else ''
|
|
||||||
if [ ! -f "$TOKEN_FILE" ]; then
|
if [ ! -f "$TOKEN_FILE" ]; then
|
||||||
${pkgs.openssl}/bin/openssl rand -hex 32 > "$TOKEN_FILE"
|
${pkgs.openssl}/bin/openssl rand -hex 32 > "$TOKEN_FILE"
|
||||||
chmod 600 "$TOKEN_FILE"
|
chmod 600 "$TOKEN_FILE"
|
||||||
echo "Generated new enrollment token: $(cat $TOKEN_FILE)"
|
echo "Generated new enrollment token: $(cat $TOKEN_FILE)"
|
||||||
fi
|
fi
|
||||||
''}
|
|
||||||
|
|
||||||
# Ensure headscale users exist
|
# Ensure headscale users exist
|
||||||
${pkgs.headscale}/bin/headscale users create ${cfg.headscaleUser} 2>/dev/null || true
|
${pkgs.headscale}/bin/headscale users create ${cfg.headscaleUser} 2>/dev/null || true
|
||||||
|
|||||||
Reference in New Issue
Block a user