Kein Auth-Server: Offline verifizierbare Tokens, Rollen und Scopes in Zaris
Die meisten Wege, einem verteilten Datenspeicher eine Authentifizierung vorzuschalten, enden damit, ein zweites verteiltes System zu seinem Betrieb hinzuzufügen: einen Auth-Dienst, den man aufrufen muss, eine Session-Datenbank, die repliziert werden muss, einen Token-Introspection-Endpunkt, den jeder Node auf dem Hot Path erreichen muss. Sie haben den Store gesichert und sich eine neue Verfügbarkeitsabhängigkeit und eine neue Latenzquelle eingekauft.
Zaris geht einen anderen Weg, und zwar einen bewusst langweiligen: ein Signaturschlüssel pro Cluster und Tokens, die jeder Node selbst verifizieren kann. Ein Token ist ein JWT, signiert mit dem privaten Schlüssel des Clusters; jeder Manager und jeder Node hält die öffentliche Hälfte und prüft die Signatur offline — kein Aufruf an einen Auth-Server, kein Quorum, kein Datenbank-Lookup. Security ist standardmäßig aus, und ein Cluster mit ausgeschalteter Security verhält sich exakt wie ein ungesicherter. Dieser Beitrag handelt davon, was sich einschaltet, wenn Sie sie aktivieren: die Form des Tokens, das Rollen-und-Scope-Modell, die beiden Ebenen, auf denen die Durchsetzung tatsächlich stattfindet, und — weil das Gegenteil vorzutäuschen der Weg zu einem falschen Sicherheitsgefühl ist — die betrieblichen Grenzen, die man leicht falsch macht.
Das Token ist die ganze Geschichte
Jedes Zaris-Token ist ein JWT. Es benennt ein Subject — einen Benutzer oder eine Anwendung — und trägt eine oder mehrere role @ scope-Grants. Es wird mit dem privaten RS256-Schlüssel des Clusters signiert, der nur auf den Managern liegt; alles, was ein Token prüfen muss, hält nur den öffentlichen Schlüssel.
Diese eine Designentscheidung nimmt den Auth-Server aus dem Bild:
- Jeder Manager kann ein Token ausstellen. Es gibt keinen primären Auth-Node, keine Wahl, keinen gemeinsamen veränderlichen Session-Zustand zu koordinieren. Das Ausstellen ist eine lokale Signaturoperation.
- Jeder Manager und jeder Node kann ein Token verifizieren, nur mit dem öffentlichen Schlüssel. Die Verifikation ist eine Signaturprüfung plus eine Ablauf- und Scope-Prüfung — reine CPU, kein Netzwerk. Das Token ist selbstenthaltend: Rolle und Scope sind darin eingebettet, ein Node, der eine Verbindung autorisiert, braucht also nichts außer dem öffentlichen Schlüssel. Es gibt auf dem Node keine Policy-Datenbank, die synchron gehalten werden müsste.
Der praktische Gewinn zeigt sich auf dem Datenpfad. Ein Client legt sein Token einmal vor, wenn die Verbindung aufgebaut wird — das „Hello". Der Node verifiziert es, autorisiert die Verbindung für den Store und vertraut dieser Verbindung dann für ihre gesamte Lebensdauer. Tokens werden auf dem Per-Operation-Hot-Path nie erneut geprüft, das Einschalten von Security kostet Sie also pro Get oder Set nichts. Sie zahlen für die Authentifizierung einmal beim Verbindungsaufbau und für diese Verbindung nie wieder.
Rollen und Scopes
Berechtigungen sind ein kleiner vordefinierter Katalog von Rollen, die jeweils auf einem Scope vergeben werden, der festlegt, wo sie gelten.
| Rolle | Scope-Ebene | Was sie gewährt |
|---|---|---|
ClusterAdmin | Cluster | alles — sämtliche Berechtigungen der Steuerungs- und Datenebene |
StoreOperator | Store | Store starten/stoppen, Konfiguration bearbeiten, Nodes starten/stoppen, Diagnose, Metriken |
Observer | Store | Diagnose und Metriken, nur lesend |
DataWriter | Store | Daten lesen / schreiben / löschen / scannen |
DataReader | Store | Daten lesen / scannen |
Ein Scope ist hierarchisch, und ein breiterer Scope deckt alles darunter ab:
zaris:cluster— der gesamte Cluster, für clusterweite Administration.zaris:store:<name>— ein einzelner Store, z. B.zaris:store:orders.- root (der leere Scope) — deckt alles ab; dem Bootstrap-Admin vorbehalten.
Die Enthaltenseinsbeziehung ist root ⊃ cluster ⊃ store: Ein DataWriter, der auf zaris:cluster vergeben wurde, kann in jeden Store schreiben, einer auf zaris:store:orders nur dort. Aus diesen zwei Achsen setzen Sie Least Privilege zusammen: die kleinste Rolle wählen, die den Job erledigt, und sie an den engsten Scope binden, den die Identität braucht.
Einschalten, ohne sich auszusperren
Das eine, was ein Sicherheitssystem nie tun darf, ist, Sie aus dem eigenen Cluster auszusperren. Zaris löst das, indem es Initialisieren und Aktivieren zu einem einzigen Schritt macht: Die Durchsetzung schaltet sich erst ein, sobald der erste Admin existiert.
Connect-ZrManager -Managers mgr-01:7801, mgr-02:7801, mgr-03:7801
Initialize-ZrSecurity -AdminSubject admin -AdminPassword (Read-Host -AsSecureString)
# creates the 'admin' login, generates the shared RS256 key on the first manager,
# copies the SAME key to the rest, turns enforcement on, and signs this session in.
Der Admin ist eine echte Login-Identität — Benutzername und Passwort, wie ein Cloud-Root-Konto —, kein frei schwebendes Token, das Sie ewig hüten müssen. Danach melden sich Operatoren mit Zugangsdaten an und erhalten ein kurzlebiges Session-Token. Die Durchsetzung selbst ist ein Laufzeit-Schalter, pro Manager persistiert, der ohne Neustart oder Konfigurationsänderung umschaltet:
Enable-ZrSecurity # control-plane enforcement ON (requires an initialized admin)
Disable-ZrSecurity # OFF — keeps the key and policy, so you can re-enable instantly
Beide wirken auf jeden Manager im Workspace, sodass der Cluster konsistent bleibt.
Zwei Arten von Identität: Menschen und Anwendungen
Nach demselben Muster wie bei AWS IAM, Kubernetes und Vault gehört jedes Token zu einer registrierten Identität — Sie können kein Token für einen beliebigen Namen ausstellen. Es gibt genau zwei Arten, plus den einen Bootstrap-Admin.
Benutzer sind Menschen. Sie werden mit einem Passwort angelegt (nur als gesalzener PBKDF2-Hash in users.json auf jedem Manager gespeichert — nie im Klartext, keine externe Datenbank) und melden sich an, um ein Session-Token zu erhalten:
New-ZrUser -Name alice -Password (Read-Host -AsSecureString) `
-Role StoreOperator -Scope zaris:store:orders
Service-Accounts sind Anwendungen. Kein Passwort; das Anlegen eines solchen liefert ein selbstenthaltendes Token, das die App vorlegt und erneuert:
New-ZrServiceAccount -Name orders-svc -Role DataWriter `
-Scope zaris:store:orders -LifetimeMinutes 1440
# prints the application token once — store it in the app's secret manager.
New-ZrToken -Subject <name> gibt es weiterhin, um ein Token auszustellen oder zu rotieren, aber das Subject muss bereits ein registrierter Benutzer oder Service-Account sein. Es gibt keine Ad-hoc-Tokens für nicht existierende Namen — diese Eigenschaft macht „wer darf diesen Store anfassen?" zu einer beantwortbaren Frage.
Ein Token verwenden
Auf der Datenebene fließt das Token direkt in die Connection-String ein — und Sie müssen nie ein Klartext-Secret hineinschreiben, weil die Indirektion über env: und file: erstklassig ist:
Connect-ZrStore -ConnectionString "zaris://node-a:7861,node-b:7861/orders?token=env:ZARIS_TOKEN"
Set-ZrItem -Key customer:42 -Value '{"name":"Ada"}'
Aus .NET ist es dieselbe Zeichenfolge, oder im Code ein TokenProvider, wenn Sie Rotation wollen:
var services = new ServiceCollection()
.AddClustronZarisConnectionString("orders",
"zaris://node-a:7861,node-b:7861/orders?token=env:ZARIS_TOKEN")
.BuildServiceProvider();
var client = await services
.GetRequiredService<IZarisClientProvider>()
.GetAsync("orders"); // token presented once, at the connection Hello
Fehlt das Token, ist es abgelaufen, ungültig oder nicht auf diesen Store gescoped, wird die Verbindung mit dem Status Unauthorized abgelehnt — Sie erfahren es beim Verbinden, nicht drei Operationen tief in einer Transaktion. Wenn Sie lieber kein Token von Hand ausstellen und einfügen möchten, kann Connect-ZrStore auch eine Benutzername-/Passwort-Zugangsdaten gegen eines beim Management Service tauschen und es im Hintergrund erneuern.
Erneuerung, die nie eine Verbindung kappt
Hier zahlt sich „nur beim Verbinden verifiziert" doppelt aus. Weil ein Node das Token nur beim Öffnen der Verbindung prüft, wird eine laufende Verbindung nie unterbrochen, wenn ihr Token abläuft. Die Erneuerung muss nur sicherstellen, dass der Client beim nächsten Öffnen einer Verbindung ein aktuell gültiges Token hat — bei einem Reconnect, einem neuen Node, einem Node-Neustart.
Der Client liest sein Token daher bei jedem (Re-)Connect über einen Provider. Solange dieser Provider frische Tokens liefert, ist die Erneuerung völlig nahtlos:
var renewer = new ZarisRenewingTokenProvider(initialToken, "http://mgr-01:7801");
renewer.Start(); // renews itself at 80% of lifetime, before expiry
var options = new ZarisClientOptions {
StoreName = "orders",
Mode = ZarisClientMode.Remote,
TokenProvider = renewer.Token, // read on every (re)connect
};
Der Renew-Endpunkt (POST /security/token/renew) ist zustandslos — er verifiziert Ihr aktuelles Token offline gegen den gemeinsamen Schlüssel und liefert ein neues mit demselben Subject und denselben Rollen und frischem Ablauf zurück, sodass jeder Manager ihn bedienen kann und er Neustarts übersteht. Ein abgelaufenes Token kann nicht erneuert werden (erneuern Sie vor Ablauf — der eingebaute Provider tut das), und ein widerrufenes Token oder Subject wird abgelehnt. Die daraus folgende Empfehlung ist einfach: Bevorzugen Sie kurze Lebensdauern mit automatischer Erneuerung gegenüber einem langlebigen Token. Sie erhalten dieselbe Nahtlosigkeit bei weit geringerer Angriffsfläche.
Wollen Sie Client-Code gar nicht in der Schleife haben, zeigen Sie den Provider auf eine Umgebungsvariable oder eine Datei und lassen einen externen Rotator — einen Secret Manager, einen Sidecar, einen Cron, der neu ausstellt — sie außerhalb des Bandes aktualisieren:
options.TokenProvider = ZarisTokenProviders.FromEnvironment("ZARIS_TOKEN");
// or ZarisTokenProviders.FromFile("/etc/zaris/token");
Der ehrliche Teil: zwei Ebenen bedeuten zwei Schalter
Dieses Detail beißt die Leute, deshalb bekommt es einen eigenen Abschnitt. „Security ist an" ist nicht ein Fakt — es sind zwei, weil es zwei Durchsetzungspunkte gibt.
Die Steuerungsebene — der Management Service auf Port 7801, über den Sie Stores anlegen, Nodes starten und stoppen und Grants verwalten — setzt durch, sobald Sie Security initialisiert und aktiviert haben. Das ist der Schalter, den Enable-ZrSecurity umlegt.
Die Datenebene — die eigentlichen Zaris-Nodes, die Ihre Schlüssel bedienen — ist ein eigener Schalter. Ein Node setzt Tokens erst durch, wenn er den gemeinsamen öffentlichen Schlüssel in seiner Konfiguration hat, und den stellen Sie pro Store bereit:
Enable-ZrStoreSecurity -Store orders # write the public key into every node's config
Enable-ZrStoreSecurity -Store orders -Restart # ...and rolling-restart to activate now
Bis Sie das tun, laufen die Nodes des Stores mit einem AllowAll-Authenticator und akzeptieren jede Verbindung — mit oder ohne Token. Das ist Absicht: So können Sie zuerst die Steuerungsebene einschalten und die Durchsetzung auf der Datenebene Store für Store mit einem geplanten Neustart ausrollen, statt den ganzen Cluster auf einmal umzulegen. Es bedeutet aber, dass das Aktivieren der Steuerungsebene allein Ihre Daten nicht sichert. Die beiden passenden Fallen:
Get-ZrSecurityStatusmeldet die Steuerungsebene. Seine FelderEnabled/Initialized/Issuerbeschreiben die Durchsetzung auf der Management-Ebene. EinTruedort beweist nicht, dass die Nodes eines bestimmten Stores Tokens verifizieren — das ist die Aufgabe vonEnable-ZrStoreSecurity, getrennt zu bestätigen. Akzeptiert ein „gesicherter" Store weiterhin Clients ohne Token, fehlt in der Node-Konfiguration der Schlüssel oder der Node wurde nicht neu gestartet.- Der Widerruf ist auf dem Datenpfad nicht sofort wirksam. Weil Daten-Tokens selbstenthaltend sind und nur beim Verbinden geprüft werden, wird
Revoke-ZrTokenvon der Steuerungsebene und von der Erneuerung sofort beachtet (ein widerrufenes Subject kann nicht erneuern), eine bereits offene Datenverbindung funktioniert aber weiter, bis sie schließt. Der saubere Weg, eine Anwendung auf der Datenebene abzuschneiden, ist, Daten-Tokens mit einer bescheidenen-LifetimeMinutesauszustellen und das aktuelle ablaufen zu lassen oder ihre Verbindungen nach dem Widerruf neu zu starten. Brauchen Sie ein nahezu sofortiges Abschneiden, sind kurze Lebensdauern der Hebel — nicht die Erwartung, dass der Hot Path erneut prüft.
Keines davon ist ein Bug; es sind die direkten Folgen von „offline, einmal, ohne Auth-Server verifizieren". Es ist nur der Teil, den Sie bewusst betreiben müssen. Der empfohlene Rollout ergibt sich genau daraus: Steuerungsebene initialisieren und aktivieren, mit Get-ZrSecurityStatus prüfen, Operator- und Anwendungs-Tokens ausstellen und deren Funktion bestätigen, dann Enable-ZrStoreSecurity pro Store mit geplantem Neustart, und schließlich Anwendungen auf kurzlebige Tokens mit automatischer Erneuerung umstellen.
Wo es im Stack sitzt
Token-Authentifizierung beantwortet, wer diesen Store anfassen darf und was er darf. Sie fügt sich mit den anderen beiden Hälften eines abgesicherten Zaris zusammen und ersetzt keine davon:
- Pluggable TLS Trust verschlüsselt die Leitung und authentifiziert die Endpunkte — es ist der Transport
zariss://unter dem Token, orthogonal dazu, wer das Token hält. - Die sichere Helm-Anleitung bringt beides auf Kubernetes Ende-zu-Ende zusammen, wo die Details von Connection-String und Zertifikat tatsächlich geübt werden.
Es lohnt sich, die Form der Kernidee zu behalten. Ein RS256-Schlüssel, JWTs, die ihre eigene Autorität einbetten, eine Verifikation, die reine Offline-CPU ist, und ein Token, das pro Verbindung genau einmal geprüft wird. Das kauft Ihnen Authentifizierung und rollenbasierte Autorisierung über einen ganzen Cluster hinweg, ohne einen Auth-Server, einen Session-Store oder einen einzigen zusätzlichen Netzwerk-Hop auf dem Pfad, auf dem Ihre Anwendung tatsächlich läuft. Der Preis ist die Disziplin, der dieser Beitrag seine zweite Hälfte gewidmet hat: Denken Sie daran, dass die Datenebene ein eigener Schalter ist, und halten Sie Ihre Tokens kurzlebig. Tun Sie das, wird „gesichert" zu einer Eigenschaft, die Sie präzise benennen können, statt auf sie zu hoffen.