remoteadmin/README.md
2025-10-15 18:02:44 +02:00

262 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Remote Admin (Local Dev)
Lightweight Django + Channels app for live SSH command execution & streaming.
## Stack
- Python 3.12
- Django 5.x
- Channels 4 (InMemoryChannelLayer, single-process only)
- asyncssh for SSH
- HTMX + vanilla JS (no build toolchain)
- Tailwind via CDN
- SQLite
## Current Feature Set
- Hosts: CRUD for SSH target metadata
- Tasks: Fully editable reusable command tasks (custom only; static registry removed)
- Batch Scripts: Multi-step scripts with `cd` directory persistence and per-step progress
- Web Console:
- Connect/disconnect via WebSocket
- Run adhoc command OR select saved task OR run batch
- Real-time stdout/stderr streaming
- Batch progress events (STEP X/Y)
- Cancel running command/batch (graceful termination)
- Validation & UX safeguards:
- Empty commands prevented client-side
- Batch normalization (strip Windows newlines, trim trailing blanks, ignore comments/blank lines)
- Delete confirmations (hx-confirm)
- Logs:
- Status, exit code, duration, output tail
- Run type (`single` / `batch`)
- Failed step index (for batch failures / errors)
- Structured error events JSON: `{event:"error", type:"ssh|runtime", message:"..."}`
- Auth: Login required for all views
- Manual: `/manual/` in-app searchable documentation
- Tests: CRUD + WebSocket execution (success, failure, batch success/failure, cancel) 13 passing
## Setup
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # edit values
python manage.py migrate
python manage.py createsuperuser
```
Run (single process ONLY):
```bash
# Development (auto-reload for HTTP only; WS fine for single process)
python manage.py runserver 127.0.0.1:8000
# Production-like single-process (Channels ASGI via daphne)
python -m daphne -b 127.0.0.1 -p 8000 project.config.asgi:application
```
Visit: http://127.0.0.1:8000/
## Environment Variables (.env)
| Var | Purpose |
|-----|---------|
| DJANGO_SECRET_KEY | Django secret key |
| DJANGO_DEBUG | 0/1 toggle |
| ALLOWED_HOSTS | Comma list |
| SSH_KEY_DIR | Optional default key base path |
| KNOWN_HOSTS_PATH | Path to known_hosts file |
| STRICT_HOST_KEY_CHECKING | true/false enforce host key verification |
## SSH Setup (DE)
Ausführliche Anleitung zur Einrichtung einer funktionierenden SSH-Verbindung für die Web-Konsole.
### 1. Lokalen SSH-Key prüfen oder erzeugen
Prüfen ob bereits ein (modernen) Ed25519 Key existiert:
```bash
ls -l ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub 2>/dev/null || echo 'kein ed25519 key'
```
Falls nicht vorhanden erstellen:
```bash
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "$(whoami)@$(hostname)" -N ''
```
Sichere Rechte setzen:
```bash
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
```
### 2. Public Key auf Zielhost hinterlegen
Ersetzt `deploy@server1` durch Benutzer & Host.
```bash
cat ~/.ssh/id_ed25519.pub | ssh deploy@server1 '\
mkdir -p ~/.ssh && chmod 700 ~/.ssh && \
cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys'
```
Test (direkt):
```bash
ssh deploy@server1 'echo OK'
```
### 3. Host Key erfassen (bei Strict Checking)
Nur nötig wenn `STRICT_HOST_KEY_CHECKING=true` (empfohlen Production).
```bash
ssh-keyscan -T 5 -t rsa,ecdsa,ed25519 server1 >> ~/.ssh/known_hosts
```
Bei Key-Änderung (Rotation / Reprovisioning) vorher entfernen:
```bash
ssh-keygen -R server1
```
### 4. Authentifizierungs-Methode wählen
| Methode | Wann nutzen | Voraussetzungen |
|---------|-------------|-----------------|
| ssh_key | Fester Schlüsselpfad | Privater Key-Dateipfad existiert & Rechte korrekt |
| agent | Temporäre Nutzung / Passphrase-Key | `ssh-agent` läuft & `ssh-add` ausgeführt |
Agent starten (falls nicht aktiv):
```bash
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
```
### 5. Host in der Web-App anlegen
Formularfelder:
- Name: frei, z.B. `prod-app-1`
- Hostname: DNS / IP, z.B. `10.10.10.15`
- Port: Standard 22
- Username: z.B. `deploy`
- Auth Method: `SSH Key` oder `Agent`
- Key Path (nur bei SSH Key): Absoluter Pfad, z.B. `/home/deploy/.ssh/id_ed25519`
- Strict Host Key Checking: Aktiv lassen außer im lokalen Test-Lab
### 6. Verbindung testen
In der Console:
1. Host wählen
2. Connect klicken (Status-Badge -> CONNECTED)
3. Ad-hoc Command `uname -a` eingeben → Run
4. Ausgabe sollte erscheinen; bei Fehlern → Fehlermeldung lesen (structured error event)
### 7. Typische Fehler & Lösungen
| Meldung | Ursache | Lösung |
|---------|---------|-------|
| Host key not trusted | Host Key fehlt / weicht ab | Key mit `ssh-keyscan` sammeln oder Strict deaktivieren (nur dev) |
| Permission denied | Key / User passt nicht | User/Key prüfen, Rechte kontrollieren, ggf. Agent laden |
| Connection lost | Netzwerk/Firewall | Direkten SSH Versuch testen, Port offen? |
| Unknown action | Falsches WebSocket Payload | Seite neu laden |
### 8. Beispiel: Zwei Hosts (Prod & Staging)
```
Name: prod-api Host: prod-api.company.internal User: deploy Auth: ssh_key Key Path: /home/deploy/.ssh/id_ed25519
Name: staging-api Host: staging.company.internal User: deploy Auth: agent Key Path: (leer, via ssh-agent)
```
### 9. Sicherheit
- Keine Passwörter im Modell gespeichert
- Private Keys verbleiben ausschließlich im Dateisystem
- Strict Checking schützt vor Man-in-the-Middle
> Password Auth ist aktuell deaktiviert nutze SSH Key oder Agent.
## Console Usage Overview
1. Select host, Connect.
2. Choose EITHER a saved task, ad-hoc command, or batch.
3. Press Run / Run Batch.
4. Observe live output; stderr in red.
5. For batch: status badge shows `STEP X/Y`.
6. Cancel to terminate; status becomes Canceling then Canceled.
7. On completion badge shows exit code.
8. View history under Logs.
## Tasks
Custom tasks only (registry removed). Fields:
- name (unique key)
- label (display)
- command (shell executed exactly as typed)
- description (optional)
Example:
```
Name: restart_app
Label: Restart App Service
Command: sudo systemctl restart app.service
```
## Batch Scripts
One line per step. Rules:
- Blank lines & lines starting with `#` ignored.
- `cd path` lines set persistent working directory for subsequent steps.
- On failure (non-zero exit) batch stops; failed step recorded.
Example:
```
# Deploy
cd /srv/app
./stop.sh
./deploy.sh
./start.sh
```
## Structured Events (WebSocket)
| Event | Payload Fields | Notes |
|-------|----------------|-------|
| connected | session | Initial handshake |
| started | log_id, command | Run started |
| chunk | stream, data | Output chunk (stdout/stderr) |
| progress | current, total, step | Batch step progress |
| canceling | | Cancel requested |
| completed | status, exit_code | Terminal status |
| error | type, message | type = ssh | runtime |
Status -> final badge mapping:
- ok -> green
- failed -> red (shows failed step when batch)
- error -> red (darker)
- canceled -> yellow
## Logs
Fields now include:
- run_type (single|batch)
- failed_step (nullable)
- duration (derived) & timestamps
- output_tail (last 32K)
## Manual
Accessible at `/manual/` or nav link “Manual” contains full user guide & examples (browser searchable).
## Tests
```bash
pytest -q
```
Coverage includes model CRUD and WebSocket execution scenarios (success, fail, batch fail, cancel).
## Troubleshooting (Quick Table)
| Symptom | Cause | Fix |
|---------|-------|-----|
| Host key not trusted | Missing known_hosts entry | ssh-keyscan >> known_hosts or disable (dev) |
| Permission denied | Wrong user/key / permissions | Fix key path, permissions, agent add |
| Invalid task | Name not found | Refresh tasks, re-create |
| Batch stops early | Non-zero exit | Inspect failed step in log, tail output |
| No output | Command buffers | Use unbuffered flags (e.g. python -u) |
## Security Notes
- Keys referenced by path only; never stored or uploaded.
- Use strict host key checking in production.
- Single-process Channels (in-memory layer) not for multi-worker production.
## Roadmap / Future Ideas
- Redis channel layer for scaling
- Parameterized tasks (templated inputs)
- Role-based access control
- Stream-to-disk full log archiving
- ANSI color pass-through
## Development Aids
Formatting / lint:
```bash
ruff check .
black .
```
Tailwind is loaded via CDN (see `remotectl/base.html`).
---