Tja... Das neue YADS Support Portal: Zwischen Paranoia, Data at Rest und Offline-Signing
Tja... wer hätte gedacht, dass wir im Jahr 2026 immer noch über Support-Portale reden müssen? Ich jedenfalls nicht. Wenn man sich die IT-Landschaft heute so ansieht, könnte man ja glatt meinen, dass alles automatisch, KI-gestützt und fehlerfrei läuft. HUST. Schön wär's. Die Realität ist da draußen leider eine ganz andere.
Software hat Bugs. Netzwerke haben Aussetzer. Und Nutzer... naja, manche Nutzer haben eben sehr "kreative" Vorstellungen davon, wie man Enterprise-Software konfiguriert oder hinter gigantischen Proxy-Monstern wie ZScaler versteckt. Irgendwann kommt der Moment, an dem das Ticket-System glüht und man als Entwickler da sitzt und sich fragt: "Warum tue ich mir das eigentlich an?"
Aber hey... so leicht bekommt man mich nicht klein. Früher lief unser Support für YADS (Yet Another Deployment System) über eine krude Mischung aus E-Mails, zusammengehackten Skripten und viel Hoffen und Beten. Das war ein absoluter Epic Fail, wenn ich ehrlich bin. Es war unübersichtlich, schwer zu warten und vor allem: Es entsprach überhaupt nicht dem, was ich unter einem "Secure By Design"-Ansatz verstehe. Wenn man eine Security-Lösung wie YADS entwickelt und released, dann kann man nicht hingehen und Kundendaten in einem unsicheren, 08/15-Wordpress-Plugin oder einer lahmen SaaS-Jira-Instanz verwalten, die gefühlt alle drei Monate durch irgendein neues CVE kompromittiert wird.
Also haben wir einen radikalen Schnitt gemacht. Wir haben das YADS Support Portal komplett neu geschrieben. Out-of-the-box, modern, schnell und vor allem: Kompromisslos sicher. Ich rede hier von End-to-End-Verschlüsselung, echter "Data at Rest"-Kryptographie und dem absoluten Endboss der Sicherheit: Offline-Signing auf einem komplett isolierten System. Aber der Reihe nach. Lasst uns mal unter die Haube schauen, was dieses Biest eigentlich kann.
📊 Das Dashboard: Telemetrie ohne Big Brother
Fangen wir mit dem ersten an, was man sieht: Das Dashboard.
![]()
Ein Dashboard, das nicht beim Laden schon die halbe CPU frisst.
Jeder, der schon mal ein Enterprise-Tool bedient hat, kennt diese vollgestopften, völlig überladenen Startseiten, auf denen tausend Charts blinken und am Ende doch keine einzige relevante Information übrig bleibt. Bei uns ist das anders. Pragmatismus steht hier an erster Stelle.
Das Dashboard zeigt genau das, was wir wissen müssen: Wie viele Installationen gibt es? Wie viele Tickets sind offen? Was dreht sich in der Infrastruktur? Wir haben hier auch endlich den lang ersehnten Download-Counter eingebaut, der direkt ins Dashboard integriert ist. Ihr glaubt gar nicht, wie oft ich manuell in den Logs nachschauen musste, ob ein bestimmtes Release überhaupt von den Leuten gezogen wurde. Dafür gibt es jetzt im Backend ein dediziertes Skript (update_downloads.py), das die Metriken einsammelt, aggregiert und sauber asynchron in unsere Datenbank schiebt.
Der Clou dabei: Wir sammeln keine personenbezogenen Daten für diesen Counter. Kein Tracking-Pixel, kein Google Analytics (Gott bewahre!). Nur die nackte Zahl der Abrufe. In Zeiten von DSGVO-Paranoia muss man aufpassen wie ein Schießhund. Wir wollen wissen, was genutzt wird, aber wir wollen nicht wissen, wer was wann gefrühstückt hat. Das ist ein schmaler Grat, aber ich denke, wir haben hier den perfekten Sweet-Spot zwischen nutzbarer Telemetrie und echtem Datenschutz gefunden.
🗄️ Container Registry: Der Müllschlucker für Docker-Images
Ein weiteres Feature, das mir persönlich massiv Nerven gerettet hat, ist die Container Registry Verwaltung.
![]()
Wenn die Festplatten vollaufen, ist das hier dein bester Freund.
Kennt ihr das? Man pusht jeden Tag neue Builds, taggt sie mit latest, v1.0.4, v1.0.5-rc1 und so weiter. Irgendwann platzt der Server aus allen Nähten. Die meisten Registries haben zwar irgendwelche Garbage-Collection-Routinen, aber oft genug schlagen die fehl oder man muss manuell eingreifen. Und manuelles Image-Löschen in der Docker-Welt ist ein absoluter Schmerz im Hintern.
Ich habe in das Support Portal ein Feature zur Bulk-Deletion eingebaut. Man markiert einfach den ganzen alten Schrott, drückt auf Löschen, und das Backend räumt asynchron auf. Keine Shell-Skripte mehr, die man per Cronjob laufen lässt und die dann irgendwann leise sterben. Ein Klick, weg ist der Müll. Graceful degradation, falls mal das Backend kurz hängt – die UI blockiert nicht, sondern zeigt sauber den Progress an. So muss das aussehen im Jahr 2026.
🎟️ Das Ticket-System: Schluss mit dem Chaos
Kommen wir zum Kern des Portals: Dem Kontakt- und Ticket-Management.
![]()
Die Übersicht aller Anfragen. Schlicht und ergreifend.
Früher hatten wir in der Datenbank Status-Werte wie "new", "read", "replied". Was für ein Bullshit. Das hat nie wirklich unseren Workflow abgebildet. Mit dem neuen Release (und einem lustigen kleinen Migration-Skript in unserer database.py) haben wir das glattgezogen. Aus "new" und "read" wurde "offen". Aus "replied" wurde "in_arbeit". Und wir haben eine Archiv-Funktion für Spam eingebaut. Ja, auch wir kriegen Spam. Wer hätte das gedacht.
![]()
Der erste Blick in ein geöffnetes Ticket.
Wenn man sich ein einzelnes Ticket ansieht (hier im Bild: Ein typischer Bug Report), dann sieht man sofort, wo der Schuh drückt. Die UI ist sauber strukturiert. Keine überladenen Menüs, keine nervigen Popups. Einfach nur das, was der Kunde geschrieben hat, und die Metadaten, die wir brauchen, um das Problem nachzustellen.
Was mir hier extrem wichtig war: Der Wechsel zwischen Markdown-Rendering und Raw-Code-Ansicht. Oft kopieren die Kunden wilde Stacktraces oder Log-Files in die Tickets.
![]()
Die Details eines Tickets mit sauberen Metadaten.
Und dann gibt es noch diese Momente, wo man einfach nur die nackten Fakten braucht: Welche YADS-Version läuft da? Welcher Tenant ist betroffen? Genau diese Metadaten extrahiert das Backend aus dem hochgeladenen (und – wie wir gleich noch sehen werden – kryptografisch verifizierten) Payload und zeigt sie übersichtlich an.
![]()
Sogar die Historie ist nachvollziehbar, ohne dass man sich durch Logs graben muss.
Es macht einfach Spaß, damit zu arbeiten. Ich habe früher Ticket-Systeme gehasst. Heute hasse ich sie immer noch, aber zumindest unseres tut jetzt exakt das, was ich ihm sage, ohne Widerworte und ohne monatliche Lizenzgebühren von hunderten Euro an irgendeinen Cloud-Provider.
📦 Installations & Aktivierungen: Wer hat was?
Wenn es um Lizenzen und Installationen geht, wird es oft hässlich. Enterprise-Kunden hassen "Phone Home"-Mechanismen. Sie wollen ihre Systeme in komplett isolierten, air-gapped Netzwerken betreiben, ohne dass ständig ein Ping an den Hersteller geht. Das kann ich völlig verstehen. Ich würde mir auch ungern eine Blackbox ins RZ stellen, die ungefragt nach Hause telefoniert.
![]()
Ein Blick auf die Installationen.
Trotzdem müssen wir als Hersteller den Überblick behalten. Wer hat Anspruch auf Support? Ist die Lizenz für dieses spezifische Deployment noch gültig? (Das gute alte End-Of-Support oder "EOS" Thema, das wir jetzt hart in der Datenbank verankert haben – is_eos und eos_since lassen grüßen).
![]()
Aktivierungsanfragen, sauber sortiert.
Das Portal verwaltet dieses Chaos absolut stressfrei. Kunden generieren lokal auf ihrer Maschine einen Request. Dieser wird uns übermittelt (meist über einen OOB-Kanal, also Out-Of-Band, wie E-Mail oder einen dedizierten Upload), und wir spielen den Key über das Portal zurück. Keine direkte Verbindung zwischen dem YADS-System des Kunden und unserem Portal nötig. Das ist Pragmatismus in seiner reinsten Form: Sicherheit durch Isolation, ohne dass die Usability komplett den Bach runtergeht. Naja, fast jedenfalls. ;)
(Kleiner Disclaimer unter uns: Um ganz ehrlich zu sein – aktuell haben wir noch überhaupt keine Installationen außerhalb unserer eigenen Infrastruktur laufen. Wir bereiten uns hier eigentlich nur auf den Ernstfall vor. Aber hey... wenn der erste echte wilde Enterprise-Kunde aufschlägt, dann sind wir verdammt nochmal bereit! Besser haben als brauchen.)
🔒 Data at Rest: DSGVO-Paranoia als Feature
Jetzt wird es technisch. Und hier scheidet sich die Spreu vom Weizen. Eines der größten Probleme vieler Support-Systeme: Was passiert, wenn die Datenbank geleakt wird? Was, wenn mal wieder irgendeine Zero-Day-Lücke in FastAPI oder XSS in der UI ausgenutzt wird (Gott bewahre, aber man muss realistisch bleiben)?
Wenn jemand unsere support.db (ja, wir nutzen schlichtes, aber extrem schnelles SQLite im WAL-Modus) in die Finger bekommt, dann sollte er im Idealfall damit absolut gar nichts anfangen können. Darum haben wir "Data at Rest" Verschlüsselung nicht nur als nettes Buzzword auf einer PowerPoint-Folie stehen, sondern knallhart auf Datenbankebene implementiert.
In unserer crypto.py passiert die Magie. Wenn ein sensibles Datum (wie ein Fehlerbericht voll mit internen IPs oder Kunden-Secrets) in die Datenbank geschrieben wird, bleibt es nicht im Klartext. Wir nutzen AES-256-GCM für die eigentliche Verschlüsselung. Aber wo kommt der Schlüssel her?
Wir nehmen einen Master-Key, der strikt in der Umgebungsvariable YADS_ENCRYPTION_KEY des Docker-Containers gebunden ist und nirgendwo im Code auftaucht. Für jeden einzelnen Speichervorgang generieren wir einen kryptografisch sicheren, zufälligen 16-Byte "Salt" und eine 12-Byte "Nonce" für das GCM-Zählwerk. Der eigentliche Verschlüsselungs-Key für diesen spezifischen Datensatz wird dann mittels PBKDF2HMAC unter Verwendung eines SHA256-Hashes mit geschmeidigen 100.000 Iterationen abgeleitet.
Do you really want to shot with a battleship gun onto a undefined target? Wenn es um DSGVO-relevante Kundendaten geht: JA! Hundertmal Ja!
Wenn unser SQLite-File in fremde Hände fällt, sieht der Angreifer nur Base64-kodierten Datenmüll (aufgebaut aus <Salt><Nonce><Ciphertext>). Ohne die Memory-Umgebung des laufenden Servers und ohne extrem viel Rechenpower für Bruteforce ist da kein Durchkommen. Punkt. Ende der Diskussion. Es kostet ein bisschen CPU-Zyklen beim Speichern und Lesen, aber das ist ein Preis, den ich für einen ruhigen Schlaf sehr, sehr gerne zahle.
🛡️ Der absolute Endboss: Offline-Signing und die Air-Gapped Festung
Kommen wir zum vielleicht wichtigsten und spannendsten Teil dieses ganzen Portals, und dem wahren Grund, warum ich dieses Blogpost schreibe. Die Überschrift sagt es ja schon: Wie verifizieren wir, dass ein Bugreport, eine Aktivierungsanfrage oder ein Compliance-Report "echt" ist?
In einer klassischen Server-Client-Architektur schickt der Client einfach ein API-Token mit. Das Portal prüft das Token gegen die Datenbank. Stimmt es, ist alles gut. Falsch!
Das ist ein gigantischer Designfehler für echte Hochsicherheitsanwendungen. Warum? Weil im Falle eines Server-Hacks der Angreifer genau diese Tokens fälschen oder abgreifen kann. Er könnte beliebige Lizenzen validieren oder gefälschte Bugreports einschleusen.
Wir spielen dieses Spiel anders.
![]()
Sichere Compliance- und Fehlerberichte. Aber wie?
Wer sich unsere Backend-Routinen in der verify_and_decrypt Methode ansieht, wird merken, was für ein kryptografisches Monster dort lauert. Die Kommunikation zwischen den YADS-Instanzen bei unseren Kunden und unserem Support-Portal ist nicht nur transportverschlüsselt (TLS/HTTPS), sondern auf Application-Layer noch einmal End-to-End extrem hart abgesichert.
Das absolute Kernfeature, auf das ich immens stolz bin, ist die Tatsache, dass das kryptografische Signing komplett offline auf einem anderen Gerät stattfindet!
Was heißt das konkret?
Wenn ein wichtiges Release, eine Lizenz oder ein kritischer Report signiert werden muss, hat unser Frontend / Backend überhaupt keinen Zugriff auf den passenden Private Key. Null. Nada.
Wir nutzen eine Kombination aus asymmetrischer und symmetrischer Kryptographie:
Das System empfängt einen Umschlag (den Payload). Zuerst prüfen wir die Ed25519-Signatur. In unserer Datenbank liegt lediglich der public_key_b64 (der öffentliche Schlüssel) des Kunden. Wenn also ein Report übermittelt wird, verifizieren wir diesen Public Key gegen die Signatur. Wurde die Signatur nicht vom Kunden erzeugt? Dann fliegt sofort eine saftige Exception (InvalidSignature) und der Request wird ins Datennirvana geschossen.
Aber das ist nur die Authentizität. Wie sieht es mit der Vertraulichkeit aus?
Hier kommt das Offline-Konzept ins Spiel: Die sensiblen Payload-Daten des Kunden werden mittels X25519 (Elliptic-curve Diffie-Hellman, ECDH) gegen unseren öffentlichen DEV-Schlüssel verschlüsselt. Das Support-Portal selbst (wenn es nur als Relais genutzt wird) hat in einigen Ausbaustufen nicht den Private Key unseres Master-Systems.
Für dieses spezifische Portal hier, wo wir die Reports lesen müssen, wird der Developer X25519 Private Key streng limitiert über eine injizierte Datei geladen (DEV_PRIVATE_KEY_FILE). Aus dem ephemeral (flüchtigen) Public Key des Senders und unserem Private Key wird ein Shared Secret ausgehandelt, jagt das durch HKDF-SHA256, generiert einen AES-32-Byte-Key und entschlüsselt den GCM-Ciphertext.
Doch zurück zum Offline-Signing: Wenn WIR wiederum ein Update für YADS herausgeben oder eine essenzielle Lizenz ausstellen, passiert dieser Prozess physisch getrennt. Das unterschriebene Artefakt wird auf einem Rechner ohne Internetzugang, auf einem dedizierten Krypto-Stick, erzeugt. Das resultierende Paket wird per USB (Sneakernet) übertragen und in das Portal eingespeist. Wenn also die russischen, chinesischen oder nordkoreanischen APT-Teams (oder einfach ein genervtes Script-Kiddie) unseren Webserver kapern, finden sie... genau... nichts. Sie können keine gefälschten Software-Updates signieren, weil der Private Key schlichtweg auf keinem Gerät existiert, das mit dem Internet verbunden ist.
Der Angreifer kann den Server niederbrennen, er kann die (ohnehin Data-at-Rest verschlüsselte) Datenbank stehlen. Aber er kann unsere Signaturen nicht kompromittieren. Das ist Paranoia auf Enterprise-Level. Und es ist verdammt beruhigend. Klar, es ist ein massiver SNAFU, wenn man schnell mal nachts um 3 Uhr ein Release pushen will und erst den dicken Tresorschlüssel für das air-gapped Notebook suchen muss. Aber hey... Life sucks. Security sucks even more. Und trotzdem lieben wir es.
🏁 Fazit & Ausblick
Ist das neue YADS Support Portal perfekt? Wahrscheinlich nicht. Irgendjemand wird garantiert versuchen, ein Emoji in den Download-Counter zu injecten oder sich darüber beschweren, dass die SQLite-Datenbank bei 10.000 gleichzeitigen Uploads langsam wird.
Aber es erfüllt seinen Zweck. Es ist schlank, schnell (dank FastAPI und asynchronem Python) und es geht keine Kompromisse bei der Sicherheit ein. Was die großen SaaS-Provider euch Monat für Monat als "Secure Enterprise Cloud" verkaufen, liefern wir hier in einem simplen, wasserdichten Docker-Container aus. Die Kombi aus Data at Rest und dem radikalen Offline-Signing für die kritische Infrastruktur zeigt, dass man Pragmatismus durchaus mit militärischer Sicherheit verbinden kann.
Wir sind auf jeden Fall startklar für die nächsten Jahre. YADS wächst, die Kunden werden mehr, die Tickets hoffentlich nicht. Und wenn doch... tja, dann drücke ich einfach den neuen Bulk-Delete Button. ;-)
Läuft... :)
Transparency Note (weil's ehrlich ist):
Dieser Post wurde mit kräftiger Unterstützung meiner KI-Peers (Antigravity/Claude/Gemini) geschrieben. Wir haben gemeinsam den Python-Code und die kryptografischen Interna analysiert, die ganzen Screenshots aus dem Repo gezogen und den Text dann zusammen mit einer amtlichen Portion Sarkasmus ("Vibecoding") in Form gegossen. KI ist das Werkzeug, der menschliche Wahnsinn beim Entwickeln der Crypto-Architektur bleibt echt. Wie immer... sonst wär's ja nicht ehrlich. ;-)
