Auf einer 1.2.8 liegt nichts von dieser Fassung -- upgrade.sh verlangte aber
ein install.sh daneben und brach sonst ab. Das war die falsche Voraussetzung
fuer genau den Fall, fuer den das Skript gedacht ist. Beide Skripte holen sich
das Release jetzt selbst:
curl -fsSLO .../raw/branch/main/deploy/upgrade.sh
sudo bash upgrade.sh --app tesm
Liegt das Skript in einem entpackten Release, wird dessen install.sh benutzt
statt eines Downloads: wer ein Paket ausgepackt hat, will nicht, dass ungefragt
ein anderes geladen wird. Mit --tag laesst sich eine Version festlegen.
Der Bootstrap steht wortgleich in beiden Dateien -- zwei eigenstaendige
Skripte koennen sich keine Datei teilen, und beide sollen allein genuegen. Ein
Hygienetest vergleicht die Bloecke, ein zweiter prueft, dass upgrade.sh kein
entpacktes Release mehr verlangt, ein dritter fuehrt den Block mit leerem PATH
aus und erwartet, dass er das fehlende Werkzeug benennt.
update.sh ruft install.sh nicht mehr per exec auf: dadurch lief die
Aufraeumfalle nie, und jedes Update liess ein entpacktes Release unter /tmp
liegen.
Ausserdem "opus" aus allen Beispielen genommen. Das war der Name der
Testinstanz neben der Fassung 1.x; seit dem Umbenennen heissen die
Installationen wie ihre Anwendung, und in einer Hilfe, die jemand anders liest,
ist "opus" ein Raetsel. In BETRIEB.md stand dabei zweimal /opt statt /srv.
Geprueft am System, nicht behauptet: die einzelne upgrade.sh hat eine echte
1.2.8 (Kopie des Archivs) **in dasselbe Verzeichnis** auf 2.0.8 gebracht --
Release geladen, 4 Clients, 2 Zugangsdaten und die DHCP-Konfiguration
uebernommen, Dienst laeuft, /login 200. Die Sicherung enthaelt die 1.2.8 samt
sqlite.db und fernet.key (Verzeichnis 0700, Passphrase 0600), und /tmp bleibt
leer. Danach dieselbe Probe mit der einzelnen update.sh.
Version 2.0.9.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
154 lines
5.4 KiB
Markdown
154 lines
5.4 KiB
Markdown
# TESM-Lizenzserver
|
|
|
|
Ausgabe und Verwaltung der Lizenzen für TESM: Kunde -> Ticket -> Lizenz,
|
|
Aktivierung online und offline, Kundenportal, Selbstbedienung, Versand über
|
|
MS Graph und eine Hierarchie aus Unter-Lizenzservern.
|
|
|
|
**Dieses Repository enthält genau das, was zum Installieren und Betreiben des
|
|
Lizenzservers gebraucht wird** -- nichts darüber hinaus:
|
|
|
|
```
|
|
apps/tesm-license die Anwendung
|
|
packages/tesm-core gemeinsamer Kern (Anmeldung, Rechte, Sicherung, nginx, ...)
|
|
packages/tesm-licensing Lizenzprotokoll, gemeinsame Hälfte
|
|
packages/tesm-licensing-server Lizenzprotokoll, Serverhälfte: ausstellen, erneuern, antworten
|
|
deploy/ install.sh, update.sh, release.sh, systemd, privilegierter Helfer
|
|
docs/ Betrieb und Sicherheit
|
|
```
|
|
|
|
Die verwaltete Anwendung liegt hier **nicht** mit drin.
|
|
|
|
| Wo sonst noch | |
|
|
|---|---|
|
|
| [alientim/tesm](https://gitea.int.eertmoed.net/alientim/tesm) | TESM selbst |
|
|
| [alientim/TESM-DEV](https://gitea.int.eertmoed.net/alientim/TESM-DEV) | Entwicklung: beide Anwendungen, Tests, Architekturdoku |
|
|
|
|
## Zweige
|
|
|
|
| Zweig | Inhalt |
|
|
|---|---|
|
|
| `main` | dieser Neubau (Version 2.0.0) |
|
|
| `SONNET5` | der Stand davor, unverändert aufbewahrt |
|
|
|
|
---
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
sudo bash deploy/install.sh --app tesm-license --https --domain lizenz.firma.de
|
|
sudo -u tesm-license tesm-license-admin init-key
|
|
sudo -u tesm-license tesm-license-admin bootstrap
|
|
sudo -u tesm-license tesm-license-admin create-admin
|
|
```
|
|
|
|
**`init-key` erzeugt den Signaturschlüssel dieses Servers. Sichern Sie ihn
|
|
sofort.** Ohne ihn lässt sich keine ausgestellte Lizenz mehr erneuern, und
|
|
Kunden müssten einen Ausstellerwechsel bestätigen.
|
|
|
|
Zielzustand: **Port 443 mit TLS, Port 80 leitet dorthin um** -- ausser dem
|
|
ACME-Pfad, der erreichbar bleiben muss, sonst kann Let's Encrypt nie erneuern.
|
|
Sitzt ein eigener Reverse Proxy davor, der TLS beendet, läuft der Dienst ohne
|
|
`--https` schlicht auf Port 80.
|
|
|
|
Der Lizenzserver darf neben TESM auf demselben Host laufen; nginx unterscheidet
|
|
die beiden am Servernamen, und jede Installation hat ihren eigenen `SITE_KEY`
|
|
für nginx-Site, logrotate, Zertifikate und Sitzungscookie.
|
|
|
|
### Aktualisieren
|
|
|
|
```bash
|
|
sudo bash deploy/update.sh --app tesm-license
|
|
```
|
|
|
|
Vor jedem Update entsteht ein vollständiges Backup, danach läuft ein
|
|
Health-Check mit automatischem Rollback.
|
|
|
|
---
|
|
|
|
## Betrieb von der Kommandozeile
|
|
|
|
```bash
|
|
sudo -u tesm-license tesm-license-admin status
|
|
sudo -u tesm-license tesm-license-admin init-key # Signaturschlüssel
|
|
sudo -u tesm-license tesm-license-admin bootstrap # Grunddaten
|
|
sudo -u tesm-license tesm-license-admin create-admin
|
|
sudo -u tesm-license tesm-license-admin migrate-legacy # Altbestand übernehmen
|
|
```
|
|
|
|
`migrate-legacy` liest die SQLite-Datei eines alten Lizenzservers **nur
|
|
lesend**, übernimmt dessen Signaturschlüssel und stellt die Lizenzen mit ihrer
|
|
restlichen Laufzeit neu aus. Wird der Schlüssel nicht übernommen, müssen
|
|
Kunden den Ausstellerwechsel einmal bestätigen.
|
|
|
|
---
|
|
|
|
## Release bauen
|
|
|
|
```bash
|
|
git tag -a v2.0.0 -m "TESM-Lizenzserver 2.0.0" && git push origin v2.0.0
|
|
bash deploy/release.sh v2.0.0
|
|
```
|
|
|
|
Heraus kommt `tesm-license-v2.0.0.tar.gz` samt SHA-256. Der Name kommt aus dem
|
|
Repository -- ein Lizenzserver-Release, das `tesm-...` heisst, verwechselt man
|
|
genau einmal.
|
|
|
|
---
|
|
|
|
## Lizenzprotokoll in Kurzform
|
|
|
|
* Ed25519, getrennte Signaturkontexte je Nachrichtenart
|
|
(`tesm/license-file/v2\0`) -- eine Signatur aus einem Kontext ist in einem
|
|
anderen nicht verwendbar.
|
|
* Kanonisches JSON, damit dieselbe Aussage genau eine Signatur hat.
|
|
* Nonce gegen Wiedereinspielung, `seq` gegen das Zurückrollen auf eine ältere
|
|
Lizenz.
|
|
* Aussteller wird beim ersten Kontakt gemerkt (TOFU); ein Wechsel muss
|
|
ausdrücklich bestätigt werden.
|
|
* Der Fingerabdruck der Maschine enthält **keinen** Hostnamen -- Umbenennen
|
|
brach im Vorgänger die Bindung.
|
|
* Offline-Aktivierung über einen kurzen Code in beide Richtungen; die Lizenz
|
|
bleibt auf dem Server als "Aktivierung offen" markiert, bis sie zurückkommt.
|
|
* Keine Lizenz ohne `master_endpoint`: eine Ausstellung ohne Endpunkt wird
|
|
abgelehnt statt eine Lizenz zu erzeugen, die sich nie aktivieren kann.
|
|
|
|
---
|
|
|
|
## Dokumentation
|
|
|
|
| | |
|
|
|---|---|
|
|
| [docs/BETRIEB.md](docs/BETRIEB.md) | Installation, Update, HTTPS, Sicherung, Fehlersuche |
|
|
| [docs/SICHERHEIT.md](docs/SICHERHEIT.md) | Anmeldung, Sitzungen, CSRF, Geheimnisse, Rechtetrennung |
|
|
|
|
Aufbau und Entwurfsentscheidungen stehen in `docs/ARCHITEKTUR.md` im
|
|
Entwicklungsrepository, ebenso die Tests.
|
|
|
|
---
|
|
|
|
## Was diese Fassung anders macht
|
|
|
|
* **Keine doppelte `licensing.py`.** Ein Paket, das beide Anwendungen
|
|
installieren -- statt zweier Dateien, die byte-identisch bleiben sollen.
|
|
* **Kein root für die Anwendung.** Ein einziger allowlisted Helfer mit
|
|
Argumentprüfung.
|
|
* **CSRF-Schutz überhaupt.** Der Vorgänger hatte keinen.
|
|
* **Rechte werden serverseitig geprüft**, nicht nur im Template ausgeblendet.
|
|
* **Verschachtelte Datenbankverbindungen sind ein Fehler**, kein Deadlock.
|
|
|
|
---
|
|
|
|
## Von einer Installation der Fassung 1.x
|
|
|
|
Eine einzelne Datei genügt -- sie lädt das Release selbst:
|
|
|
|
```bash
|
|
curl -fsSLO https://gitea.int.eertmoed.net/alientim/tesm-license/raw/branch/main/deploy/upgrade.sh
|
|
sudo bash upgrade.sh --app tesm-license
|
|
```
|
|
|
|
Sichert die alte Installation, schaltet sie ab, installiert diese Fassung und
|
|
übernimmt die Daten. Einzelheiten und was **nicht** mitkommt:
|
|
[docs/BETRIEB.md](docs/BETRIEB.md).
|
|
|