Die laufenden Installationen hiessen "tesm-opus" und "tesm-license-opus" -- ein Instanzname aus der Zeit, in der sie neben der Fassung 1.x getestet wurden. Jetzt heissen sie "tesm" und "tesm-license". Umbenennen ist mehr als ein verschobenes Verzeichnis, und drei Stellen sind leicht zu uebersehen: * SITE_KEY in der Umgebungsdatei -- daraus entsteht der Name des Sitzungscookies. Bleibt er alt, heisst das Cookie weiter wie die alte Instanz: unauffaellig und falsch. * web_cert_path/web_key_path/web_acme_webroot in der Datenbank enthalten den Namen. Ein Zertifikat unter dem alten Pfad findet nginx nicht mehr. * server_name der nginx-Site. install.sh schreibt die Datei aus seiner Vorlage neu, sobald sich die alias-Pfade aendern -- und die aendern sich hier zwangslaeufig. Ohne den Namen aus der Datenbank stehen danach zwei Sites mit "server_name _" auf Port 80, und die erste gewinnt. web-setup braucht dafuer --apply; ohne ihn speichert es nur. Zwei Fehler hat erst der Lauf am System gezeigt: * Das venv wandert nicht mit. Seine Konsolenskripte tragen den absoluten Pfad im Shebang, und danach zeigt venv/bin/gunicorn auf einen Interpreter, den es nicht mehr gibt -- systemd meldet "No such file or directory" fuer eine Datei, die sichtbar da ist. Es wird jetzt verworfen und neu gebaut. * Den Zielnamen belegt nicht nur /srv/<name>, sondern auch /var/log/<name>, der ACME-Pfad und die logrotate-Datei. Der Umzug brach mitten drin ab. Jetzt wandert alles, was den Namen belegt, in ein Archiv -- geloescht wird nichts, die Units und die Site der alten Fassung liegen darin unter systemd-alt/. Ein Test vergleicht die Pfade, die install.sh unter dem Namen anlegt, mit denen, die rename.sh kennt. Genau diese Luecke war der zweite Fehler; ohne den Test faellt der naechste erst wieder auf einem Server auf. Version 2.0.6. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 | TESM selbst |
| 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
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
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
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
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,
seqgegen 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 | Installation, Update, HTTPS, Sicherung, Fehlersuche |
| 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.