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:
27
docs/architecture.md
Normal file
27
docs/architecture.md
Normal 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
56
docs/install.md
Normal 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.
|
||||
Reference in New Issue
Block a user