A TLS-secured control server and ratatui TUI client in Rust for firing predefined SSH commands on remote targets via a JSON protocol.
Find a file
Bengt c66121d683
Starting Point i guess (I always do these commits way to late)
- Raw TLS (no http bullshit just TCP+TLS with newline-delimited JSON
- Let's encrypt for TLS (not tested!)
- --self-signed (server) for in-memory certs
- --debug (server) for not using ssh but only posting them to stdout and returning them to the user.
- ratatui TUI client (config in ~/.config/killswitch/client.toml)
2026-03-09 19:57:12 +01:00
config Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00
src Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00
.gitignore Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00
Cargo.lock Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00
Cargo.toml Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00
killswitch.service Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00
README.md Starting Point i guess (I always do these commits way to late) 2026-03-09 19:57:12 +01:00

Killswitch

Zentraler TLS-JSON Kontrollserver + ratatui TUI-Client in Rust.

killswitch-server   Server: nimmt JSON-Verbindungen entgegen, führt SSH-Befehle aus
ks                  Client: interaktive ratatui TUI

Features

  • Raw TLS kein HTTP/WebSocket, echter TCP+TLS, newline-delimited JSON
  • ACME / Let's Encrypt automatische Zertifikate via HTTP-01 Challenge
  • Self-signed Modus --self-signed generiert ein In-Memory-Zertifikat (kein DNS nötig)
  • Debug-Modus --debug validiert Signale und printet sie, führt aber kein SSH aus
  • SSH-Killswitches vordefinierte Signale per SSH auf Zielmaschinen abfeuern
  • ratatui TUI interaktiver Client mit Targets/Signals-Navigation
  • Gespeicherte Session Token + Server werden in ~/.config/killswitch/client.toml gespeichert

Bauen

# Abhängigkeiten (Ubuntu/Debian)
sudo apt install libssl-dev libssh2-1-dev pkg-config

cargo build --release
# → target/release/killswitch-server
# → target/release/ks

Server starten

Entwicklung / LAN (self-signed, kein DNS nötig)

./killswitch-server --config config/config.toml --self-signed --debug
  • --self-signed → generiert Zertifikat in-memory für die konfigurierte Domain
  • --debug → Signale werden nur geloggt, kein SSH wird ausgeführt

Produktion (Let's Encrypt)

# Port 80 und 8443 müssen erreichbar sein
./killswitch-server --config config/config.toml

Client (ratatui TUI)

# Erster Start  fragt Host/Port und Login ab, speichert dann in ~/.config
./ks

# Self-signed Zertifikat akzeptieren (Dev/LAN mit --self-signed Server)
./ks --insecure

# Gespeicherte Session vergessen, neu einloggen
./ks --logout

Navigation im TUI

Key Aktion
j / k / ↑↓ Targets wechseln
h / l / ←→ Signals wechseln
Enter / Space Signal abfeuern (Bestätigung)
r Targets vom Server neu laden
L Ausloggen
q / Esc Beenden
Ctrl+C Sofort beenden

Gespeicherte Konfiguration (~/.config/killswitch/client.toml)

[server]
host = "meinserver.de"
port = 8443
insecure = false

[session]
username = "admin"
token = "..."
expires_at = "2025-01-01T12:00:00Z"

Server-Konfiguration

[server]
domain = "killswitch.example.com"
port = 8443
acme_port = 80

[acme]
email = "admin@example.com"
cert_dir = "certs"
staging = true   # false für Produktion

[auth]
token_ttl_secs = 3600
token_secret = "RANDOM-64-CHAR-SECRET"   # openssl rand -hex 32

[auth.users.admin]
password_hash = "sha256:8c6976..."   # echo -n pw | sha256sum → "sha256:..."
allowed_targets = ["web01", "web02"]
allowed_signals = ["*"]   # Alle Signale + raw exec

[auth.users.operator]
password_hash = "plain:geheim"   # Nur für Dev!
allowed_targets = ["web01"]
allowed_signals = ["stop_caddy", "reload_caddy"]

[targets.web01]
host = "192.168.1.10"
port = 22
user = "deploy"
ssh_key = "keys/web01_id_ed25519"
host_key_check = "insecure"   # oder "SHA256:<fingerprint>"

[targets.web01.signals]
stop_caddy    = "sudo systemctl stop caddy"
reload_caddy  = "sudo systemctl reload caddy"
restart_app   = "sudo systemctl restart myapp"
disk_usage    = "df -h"

JSON-Protokoll (für manuelle Tests)

# Mit openssl testen
openssl s_client -connect localhost:8443 -quiet 2>/dev/null

{"type":"ping"}
{"type":"auth","username":"admin","password":"admin"}
{"type":"list_targets","token":"..."}
{"type":"signal","token":"...","target":"web01","signal":"stop_caddy"}

Im Debug-Modus antwortet der Server auf Signale mit:

{"type":"signal_result","success":true,"stdout":"[debug] would run: sudo systemctl stop caddy","stderr":""}

Passwort-Hash generieren

echo -n "meinPasswort" | sha256sum
# abc123... → config: "sha256:abc123..."

SSH-Keys einrichten

mkdir -p keys
ssh-keygen -t ed25519 -f keys/web01_id_ed25519 -N ""
ssh-copy-id -i keys/web01_id_ed25519.pub deploy@web01