WP-40/41/42: dashboard, security hardening, deployment and operations docs

Dashboard endpoint and page aggregating inventory, vulnerabilities, cluster
health, backups and recent jobs. Security headers (CSP, nosniff, DENY,
referrer policy), 1 MB body limit, configurable login rate limit, audit
steps in CI. Installer script, systemd unit, install/architecture docs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-02 23:26:01 +02:00
parent a89395ae18
commit 9234e1ba47
29 changed files with 851 additions and 21 deletions

27
docs/architecture.md Normal file
View File

@ -0,0 +1,27 @@
# Architecture
Single Rust binary (axum) serving the API and the built Vue SPA; SQLite for state; host tools
(`apt-get`, `dpkg-query`, `snap`, `microk8s kubectl`, `trivy`, `smbclient`, `curl`, `tar`,
`openssl`) are invoked as subprocesses behind ports so every use case is testable with fakes.
```
backend/crates/
domain/ entities, validation, ports (traits) no I/O
application/ use cases: auth, users, settings, jobs, depends on domain
scheduler, inventory, upgrade, cluster,
vulnerabilities, backups
infrastructure/ SQLite repos, Argon2/JWT/AES-GCM, lettre, implements the ports
Debian inspector/updater, kube-rs gateway,
Trivy, smbclient/curl storage, collectors
api/ axum routes, auth extractors, OpenAPI, wires everything
security headers, config, main
frontend/ Vue 3 + TypeScript + Tailwind, Pinia stores, Playwright e2e
```
Cross-cutting: a `JobRunner` executes long-running work (refresh, upgrade, scan, backup) as
persisted job runs with live logs; a `Scheduler` ticks every 30 s and starts due jobs from cron
expressions (settings) and backup strategies. Secrets at rest are AES-256-GCM encrypted with
`MASTER_KEY`. Authentication: Argon2id passwords, 15-minute JWT access tokens, rotating refresh
tokens in an HttpOnly, SameSite=Strict cookie scoped to `/api/auth`, reuse detection revokes the
token family. `FAKE_HOST=true` swaps all host/cluster/scanner/storage adapters for fakes so the
app runs on a developer machine and in the UI tests.

56
docs/install.md Normal file
View File

@ -0,0 +1,56 @@
# Installation and operation
## Build a release
On a machine with Docker (cross-compiles a static x86_64 binary) and Node:
```bash
cd frontend && npm ci && npm run build && cd ..
docker run --rm -v "$PWD/backend":/home/rust/src -v cargo-registry-musl:/root/.cargo/registry \
messense/rust-musl-cross:x86_64-musl cargo build --release -p api
mkdir -p release && cp backend/target/x86_64-unknown-linux-musl/release/monitoring-server deploy/install.sh deploy/monitoring.service release/
cp -r frontend/dist release/dist
tar -C release -czf monitoring-release.tar.gz .
```
## Install or update on the Debian host
```bash
scp monitoring-release.tar.gz root@server:/tmp/
ssh root@server 'mkdir -p /tmp/rel && tar -C /tmp/rel -xzf /tmp/monitoring-release.tar.gz && cd /tmp/rel && ./install.sh --port 8080'
```
The installer installs `smbclient`, `curl`, `openssl` and Trivy, copies the files to
`/opt/monitoring`, creates `/opt/monitoring/.env` with random secrets and a bootstrap admin on
the first run, and (re)starts the `monitoring.service` systemd unit. Re-running it keeps the
existing `.env` and database.
For the quick test deployment used during development see `deploy/deploy-test.sh`.
## Configuration
All settings live in `/opt/monitoring/.env` (see `.env.example`). Relevant keys:
| Key | Purpose |
|-----|---------|
| `JWT_SECRET` | signs access tokens; changing it logs everyone out |
| `MASTER_KEY` | encrypts stored SMTP/SMB/FTP passwords and backup passphrases. **Back it up**: without it stored secrets cannot be read |
| `BIND` | listen address, e.g. `0.0.0.0:8080` |
| `COOKIE_SECURE` | set `true` behind HTTPS |
| `KUBECONFIG` / `KUBECTL` | defaults to the microk8s client config and `microk8s kubectl` |
| `CONTAINERD_ADDRESS` | image scans read local images from this socket first |
| `LOGIN_RATE_LIMIT` | login attempts per IP and minute |
Put the app behind a TLS-terminating reverse proxy (e.g. the cluster's ingress or nginx on the host)
for production use and set `COOKIE_SECURE=true`.
## Operations
- Logs: `journalctl -u monitoring.service -f`
- Database: SQLite at `/opt/monitoring/data/monitoring.db`. Back it up together with `.env` by
creating a backup strategy of type "Directory on the host" for `/opt/monitoring` (the `.env`
contains the `MASTER_KEY`, so encrypt that strategy or store it on a trusted target).
- Scheduled jobs: package refresh hourly, vulnerability scan daily at 03:00, backups per strategy;
all adjustable in Settings. Failed or interrupted runs appear on the Jobs page and on the dashboard.
- Restore procedures: `docs/restore.md`.
- The service runs as root because it drives `apt-get`, `microk8s kubectl` and reads volume data.