Zum Inhalt

Krywerk Server betreiben

Anleitung für Betreiber (IT-Administration einer Organisation oder eines Dienstleisters): Installation, Anmeldedienst, Sicherung, Updates, Überwachung, Datenschutz. Stand F8 (2026-10-14).

Krywerk Server ist der Schlüsselserver für Team-Ordner: Er verteilt die verschlüsselten Tresorschlüssel an berechtigte Personen und Geräte. Er ist kompatibel mit den Cryptomator-Apps (Hub-Protokoll) und mit der Krywerk-App. Die Dateien selbst liegen nicht auf dem Server, sondern im Cloud-Speicher der Organisation (OneDrive, SharePoint, Nextcloud …).

  Krywerk-App / Cryptomator-App ──HTTPS──▶ Reverse Proxy (Caddy) ──▶ krywerk-server ──▶ SQLite (/data)
          │                                                              │
          └──── Anmeldung im Browser (OIDC) ──▶ Keycloak ──(optional)──▶ Entra ID / anderer Anbieter
          └──── verschlüsselte Dateien ───────▶ Cloud-Speicher (OneDrive, …)

1. Was der Server speichert – und was nicht

Gespeichert (SQLite-Datei) Nie auf dem Server
Nutzer: ID aus dem Anmeldedienst, Anzeigename, E-Mail, Vor-/Nachname Passwörter (Anmeldung macht der Anmeldedienst)
Gruppen aus dem Token (Name, Mitgliedschaften) Masterkeys der Tresore im Klartext
öffentliche Schlüssel, verschlüsselte private Schlüssel der Nutzer Freischaltcodes (Account Keys)
Geräte: Name, Typ, öffentlicher Schlüssel, letzter Zugriff, letzte IP-Adresse Dateien, Dateinamen, Inhalte
Team-Ordner: Name, Beschreibung, Mitglieder/Rollen, Archiv-Status
Freigaben: Tresorschlüssel, verschlüsselt für jede berechtigte Person

Wer nur die Datenbank besitzt, kann keinen Team-Ordner entschlüsseln: Dafür braucht es zusätzlich den Freischaltcode bzw. einen freigeschalteten Geräteschlüssel einer berechtigten Person. Trotzdem ist die Datenbank vertraulich (Mitgliederlisten, E-Mail-Adressen, IP-Adressen) – Sicherungen entsprechend schützen.

Das Zugriffsprotokoll (Standardausgabe) enthält Zeit, Methode, Pfad (mit Tresor- bzw. Geräte-ID) und Status – nie Tokens, Schlüssel, Header oder Inhalte. Abschalten mit KRYWERK_SERVER_QUIET=1.

2. Voraussetzungen

  • Linux-Server (oder VM) mit Docker Engine ≥ 24 und Compose-Plugin; 1 vCPU und 512 MB RAM genügen für den Server, mit eigenem Keycloak eher 2 GB RAM.
  • Ein DNS-Name für den Schlüsselserver, z. B. schluessel.example.org, mit eigenem Keycloak ein zweiter, z. B. login.example.org. Ports 80 und 443 von außen erreichbar (Let's Encrypt).
  • Ein Anmeldedienst (OIDC). Empfohlen: Keycloak – vorhanden oder über compose.keycloak.yaml mitgeliefert. Konten aus Microsoft Entra ID (Microsoft 365) oder einem anderen Anbieter werden dort angebunden (Abschnitt 4).

Warum nicht direkt Entra ID? Die offizielle Cryptomator-Desktop-App meldet sich über eine Loopback-Adresse mit zufälligem Pfad an (http://127.0.0.1:<Port>/<zufällig>). Entra ID verlangt nach unserem Kenntnisstand, dass der Pfad registriert ist, und lehnt solche Anmeldungen ab; außerdem senden die Apps keinen scope. Keycloak erlaubt beliebige Loopback-Ports und Pfade (RFC 8252) und dient als Broker vor Entra ID – so macht es auch der Cryptomator Hub. Siehe Abschnitt 5 für die experimentelle Direktanbindung.

3. Installation mit Docker (empfohlen)

Die Dateien liegen in crates/kw-server/deploy/:

Datei Zweck
compose.yaml Krywerk Server + Caddy (automatisches TLS über Let's Encrypt)
compose.keycloak.yaml Ergänzung: eigener Keycloak mit Postgres
Caddyfile, Caddyfile.keycloak Reverse Proxy (HSTS, Sicherheits-Header; Keycloak-Verwaltung nur aus internen Netzen)
keycloak/realm-krywerk.json Realm-Vorlage: Client cryptomator, Rollen, Gruppen-Claim
krywerk.env.example Einstellungen des Servers
backup.sh, restore.sh Sicherung und Wiederherstellung
krywerk-server.service, krywerk-server.toml Betrieb ohne Docker (Abschnitt 6)

3.1 Image

Ohne Registry wird das Image auf dem Server aus dem Quellcode gebaut (Rust-Toolchain im Build-Container, ~1 min):

git clone <repo> /opt/krywerk && cd /opt/krywerk/crates/kw-server/deploy
docker compose build

Das Image (ghcr.io/mzilinski/krywerk-server:<Version>, lokal gebaut krywerk-server) enthält nur das Programm und CA-Zertifikate, läuft als Nutzer ohne Rechte (UID 10001), mit nur lesbarem Dateisystem; Daten liegen im Volume data (/data). Eigene CAs (z. B. ein interner Keycloak mit eigener CA): Zertifikatsdatei einbinden und SSL_CERT_FILE=/pfad/ca.pem setzen.

3.2 Mit eigenem Keycloak

cp krywerk.env.example krywerk.env          # Variante A ist voreingestellt: Domains anpassen
cat > .env <<EOF
KRYWERK_DOMAIN=schluessel.example.org
KEYCLOAK_DOMAIN=login.example.org
KEYCLOAK_ADMIN_PASSWORD=$(openssl rand -base64 24)
KEYCLOAK_DB_PASSWORD=$(openssl rand -base64 24)
EOF
chmod 600 .env
alias kc='docker compose -f compose.yaml -f compose.keycloak.yaml'
kc up -d                                     # erster Start ~1 min (Realm-Import)
kc run --rm server check                     # Konfiguration + Anmeldedienst prüfen

krywerk.env (Variante A): KRYWERK_SERVER_OIDC_ISSUER=https://login.example.org/realms/krywerk und KRYWERK_SERVER_OIDC_INTERNAL_URL=http://keycloak:8080/realms/krywerk (Discovery/JWKS intern; die Apps bekommen trotzdem die öffentlichen Adressen).

Danach in Keycloak (https://login.example.org/admin/, Benutzer admin, Passwort aus .env; die Konsole ist nur aus privaten Netzen erreichbar – Regel in Caddyfile.keycloak anpassen):

  1. Realm krywerk wählen. Konten anlegen oder einen Identitätsanbieter anbinden (Abschnitt 4).
  2. Rollen: jeder Nutzer hat user (Standardrolle). Wer Team-Ordner anlegen darf: Rolle create-vaults (am besten über eine Gruppe, z. B. „Team-Ordner anlegen“ → Role mapping). admin darf alle Team-Ordner ansehen und archivieren.
  3. Gruppen: Gruppen in Keycloak erscheinen in den Apps zum Teilen (Claim groups, voller Pfad, /Bereich/Team wird zu verschachtelten Gruppen). Eine Gruppe kennt der Server, sobald sich ein Mitglied einmal angemeldet hat.

3.3 Mit vorhandenem Keycloak

Nur compose.yaml verwenden. Im vorhandenen Realm einen Client anlegen (Werte wie in keycloak/realm-krywerk.json): Client-ID cryptomator, öffentlich (Client authentication aus), Standard Flow an, PKCE S256, Redirect-URIs http://127.0.0.1/*, org.cryptomator.ios:/hub/auth, org.cryptomator.android:/hub/auth, Web Origins +; Mapper „Group Membership“ (Claim groups, Full group path an, Add to access token an); Rollen user, create-vaults, admin als Realm-Rollen. Läuft im selben Realm ein Cryptomator Hub, den Gruppen-Claim nicht groups nennen (der Hub liest ihn als Rollenliste → 403), sondern z. B. krywerk_groups und KRYWERK_SERVER_GROUPS_CLAIM=krywerk_groups setzen.

3.4 Web-Verwaltung

Im Browser unter https://schluessel.example.org/verwaltung/: Übersicht, Team-Ordner, Personen (sperren), eigene Gruppen, Notfallanträge, Protokoll. Einschalten mit KRYWERK_SERVER_WEB=1 in krywerk.env (Vorlage: an).

  • Client krywerk-verwaltung: Bei der Realm-Vorlage (3.2) ist er schon angelegt. Bei vorhandenem Keycloak (3.3) einen öffentlichen Client anlegen: Standard Flow, PKCE S256, Redirect-URI https://schluessel.example.org/verwaltung/*, Post-Logout-Redirect +, derselbe Gruppen-Mapper wie bei cryptomator.
  • Die Rolle admin macht zur IT-Administration (alle Team-Ordner, Personen, Gruppen, Protokoll). Wer Team-Ordner verwaltet, sieht dort nur die eigenen.
  • Nur aus dem internen Netz: Die Caddy-Vorlagen sperren /verwaltung für öffentliche Adressen (Block @verwaltung_extern, Bereiche anpassen oder entfernen).
  • TZ=Europe/Berlin in krywerk.env sorgt für Uhrzeiten in Ortszeit.

Einzelheiten, Sicherheit und Grenzen (z. B. „Zugriff gewähren“ bleibt in der App): docs/web-verwaltung.md.

3.5 Prüfen

curl https://schluessel.example.org/health             # → ok
curl https://schluessel.example.org/api/config          # apiLevel 4, öffentliche Anmelde-Endpunkte

Dann in der Krywerk-App „Organisationskonto → Adresse des Schlüsselservers“ eintragen und anmelden, oder mit krywerk-hub --server https://schluessel.example.org konto-einrichten.

4. Konten aus Entra ID (Microsoft 365) über Keycloak

In Entra ID (Microsoft Entra Admin Center → Anwendungen → App-Registrierungen → Neue Registrierung):

  1. Name „Krywerk Anmeldung“, Kontotyp „Nur Konten in diesem Organisationsverzeichnis“.
  2. Umleitungs-URI (Web): https://login.example.org/realms/krywerk/broker/entra/endpoint.
  3. Zertifikate & Geheimnisse → neuer geheimer Clientschlüssel (Ablaufdatum notieren!).
  4. Optional Gruppen: Tokenkonfiguration → Gruppenanspruch hinzufügen → „Sicherheitsgruppen“ bzw. „Der Anwendung zugewiesene Gruppen“ (empfohlen, hält das Token klein). Entra ID liefert Objekt-IDs (GUIDs).
  5. Optional: Unternehmensanwendungen → „Krywerk Anmeldung“ → Eigenschaften → „Zuweisung erforderlich“ = Ja, dann nur zugewiesene Personen/Gruppen zulassen.

In Keycloak (Realm krywerk → Identity providers → „Microsoft“ oder „OpenID Connect v1.0“):

  1. Alias entra, Client-ID = Anwendungs-ID, Client Secret = Schlüssel aus Schritt 3; bei „OpenID Connect“ Discovery-URL https://login.microsoftonline.com/<Tenant-ID>/v2.0/.well-known/openid-configuration.
  2. „Sync mode“ = Force (Name/E-Mail bei jeder Anmeldung aktualisieren), „Trust email“ an.
  3. Gruppen: je Entra-Gruppe ein Mapper „Advanced Claim to Group“ (Claim groups enthält die GUID → Keycloak- Gruppe „Fachbereich Finanzen“ o. Ä.). Alternativ Gruppen nur in Keycloak pflegen.
  4. Rolle create-vaults: Mapper „Advanced Claim to Role“ für eine Entra-Gruppe oder direkt in Keycloak zuweisen.
  5. Direkt zu Microsoft weiterleiten (ohne Keycloak-Anmeldeseite): in krywerk.env KRYWERK_SERVER_OIDC_AUTH_ENDPOINT=https://login.example.org/realms/krywerk/protocol/openid-connect/auth?kc_idp_hint=entra – die Apps übernehmen vorhandene Query-Parameter.

Andere Anbieter (Google Workspace, landesweite Bildungs-/Verwaltungs-Logins, SAML-IdPs) bindet man in Keycloak genauso als Identity Provider an.

5. Entra ID direkt (experimentell, ungetestet)

Nur für Umgebungen, in denen ausschließlich die Krywerk-App genutzt wird und Keycloak nicht in Frage kommt. Bekannte Hürden: (1) Loopback-Redirect mit zufälligem Pfad (siehe Abschnitt 2) – die offizielle Desktop-App wird scheitern; (2) Entra ID verlangt scope – über die Query des Authorization Endpoints lösbar (KRYWERK_SERVER_OIDC_AUTH_ENDPOINT=…/oauth2/v2.0/authorize?scope=api%3A%2F%2F<Client-ID>%2FTresore.Zugriff%20openid%20profile); (3) Tokens ohne eigenen API-Scope sind für Microsoft Graph ausgestellt und nicht prüfbar – daher in der App-Registrierung „Eine API verfügbar machen“ (Scope Tresore.Zugriff), Manifest accessTokenAcceptedVersion: 2, App-Rollen Tresore.Anlegen und Krywerk.Admin; Plattform „Mobile und Desktop“ mit Redirect http://127.0.0.1. Einstellungen: Block „Variante B“ in krywerk.env.example. Gruppen erscheinen als GUIDs; ab ~200 Gruppen sendet Entra ID einen Überlauf-Verweis (Mitgliedschaften bleiben dann unverändert).

6. Ohne Docker (systemd)

cargo build --release -p kw-server          # im Wurzelverzeichnis; reines Rust, kein OpenSSL

Dann wie im Kopf von deploy/krywerk-server.service beschrieben installieren (eigener Systemnutzer, Daten in /var/lib/krywerk, Konfiguration /etc/krywerk/krywerk-server.toml, gehärtete Unit). TLS über einen Reverse Proxy vor 127.0.0.1:8380 (Caddy: schluessel.example.org { reverse_proxy 127.0.0.1:8380 }) mit trust_proxy = true. Sicherung: sudo -u krywerk krywerk-server --config … backup <ziel> per Timer/cron.

7. Laufender Betrieb

7.1 Befehle

Befehl Zweck
krywerk-server check Konfiguration, Datenbank und Anmeldedienst prüfen (vor Start/Update)
krywerk-server backup <ziel> konsistente Sicherung im laufenden Betrieb, danach geprüft (Datei 0600)
krywerk-server verify <datei> Sicherung prüfen: Integrität, Schema-Version, Anzahlen (ohne Konfiguration)
krywerk-server restore <datei\|-> [--force] Sicherung zurückspielen (Server muss gestoppt sein)
krywerk-server healthcheck GET /health am lokalen Server (Docker-HEALTHCHECK)

Im Docker-Betrieb mit docker compose run --rm server <befehl> bzw. docker compose exec server krywerk-server <befehl>.

7.2 Sicherung

Was sichern: die Datenbank des Servers (enthält alles) – mit eigenem Keycloak zusätzlich dessen Datenbank (docker compose … exec keycloak-db pg_dump -U keycloak keycloak > keycloak.sql) – sowie krywerk.env/.env. Die Team-Ordner selbst sichert der Cloud-Speicher.

# täglich 02:15, 30 Tage aufbewahren (crontab des Betriebsnutzers)
15 2 * * *  /opt/krywerk/crates/kw-server/deploy/backup.sh /var/backups/krywerk 30 >>/var/log/krywerk-backup.log 2>&1

backup.sh nutzt docker compose im Ordner deploy/; mit Keycloak-Ergänzung vorher COMPOSE_FILE=compose.yaml:compose.keycloak.yaml setzen. Sicherungen regelmäßig außer Haus kopieren und mindestens vierteljährlich eine Wiederherstellung üben (krywerk-server verify auf der Kopie genügt nicht als Übung – einmal in eine Testinstanz zurückspielen und einen Team-Ordner öffnen).

7.3 Wiederherstellen

./restore.sh /var/backups/krywerk/krywerk-server-<Zeit>.sqlite3

stoppt den Server, prüft die Sicherung, spielt sie zurück (bisherige Datenbank bleibt als krywerk-server.sqlite3.vor-restore-<Zeit> im Volume) und startet neu. Folgen: Was nach der Sicherung entstand, fehlt: neue Team-Ordner sind nicht mehr bekannt (Öffnen → „Kein Zugriff“), neu freigeschaltete Geräte müssen erneut freigeschaltet werden, neue Freigaben erneut gewährt werden. Team-Ordner, deren Schlüssel nur auf dem Server lagen, sind ohne Sicherung verloren – außer es gibt einen Wiederherstellungsschlüssel (F9). Deshalb: regelmäßig sichern.

7.4 Updates

cd /opt/krywerk && git pull
cd crates/kw-server/deploy
./backup.sh /var/backups/krywerk 30                 # vorher sichern
docker compose build && docker compose run --rm server check
docker compose up -d                                # Datenbank-Migrationen laufen beim Start automatisch

Ein Zurück auf eine ältere Version ist nach einer Schema-Änderung nur mit der Sicherung von vorher möglich (ältere Server verweigern neuere Datenbanken mit einer klaren Meldung). Caddy/Keycloak/Postgres-Images regelmäßig aktualisieren (docker compose pull && docker compose up -d; Keycloak-Hauptversionen nach dessen Upgrade-Anleitung).

7.5 Überwachung

  • GET https://schluessel.example.org/health → 200 ok (Datenbank erreichbar), sonst 503. Erfolgreiche Abfragen werden nicht protokolliert.
  • Docker meldet den Zustand (docker compose ps → healthy).
  • Protokolle: docker compose logs -f server. Häufige 401 → Anmeldedienst/Uhrzeit prüfen; 403 → fehlende Rolle oder Freigabe (normal, wenn Personen ohne Zugriff Ordner öffnen).
  • Ablauf des Entra-Client-Secrets (Keycloak-Broker) im Kalender vormerken.

7.6 Fehlerbehebung

Symptom Ursache / Lösung
check: „Discovery meldet issuer … statt …“ KRYWERK_SERVER_OIDC_ISSUER muss exakt dem iss der Tokens entsprechen (ohne / am Ende)
check: Anbieter nicht erreichbar OIDC_INTERNAL_URL prüfen; Server braucht ausgehenden Zugriff zum Anbieter; eigene CA → SSL_CERT_FILE
Apps: „Server nicht vertrauenswürdig“ public_url/KRYWERK_DOMAIN muss HTTPS sein; Apps akzeptieren HTTP nur für localhost
Alle Anfragen 401 Uhrzeit des Servers (NTP), Issuer, ggf. OIDC_AUDIENCE falsch gesetzt; Tokens eines anderen Clients (azp) – dann OIDC_CLIENT_ID bzw. OIDC_ALLOWED_CLIENTS prüfen
Alle Anfragen 403 Rolle user fehlt (Standardrolle im Realm) bzw. ROLE_USER leeren, wenn der Anbieter keine Rollen liefert
„Darf keine Team-Ordner anlegen“ Rolle create-vaults zuweisen
Gruppe nicht auffindbar Mitglied muss sich einmal angemeldet haben; Gruppen-Claim im Token? (GROUPS_CLAIM)
restore: „antwortet noch“ Server zuerst stoppen (restore.sh macht das)
Web-Verwaltung: „Invalid parameter: redirect_uri“ beim Anmeldedienst Rücksprung https://<KRYWERK_DOMAIN>/verwaltung/anmeldung am Client krywerk-verwaltung eintragen
Web-Verwaltung: „Sitzung abgelaufen“ bei jedem Formular Proxy überschreibt Referrer-Policy mit no-referrer (Browser senden dann Origin: null) – in Caddy ?Referrer-Policy verwenden
Web-Verwaltung: 403 „nur aus dem internen Netz“ Caddy-Block @verwaltung_extern anpassen
Web-Verwaltung: kein Menü „Personen“ Rolle admin fehlt im Token (Rollen-Claim)

8. Sicherheit und Datenschutz

  • Härtung: nur Caddy ist von außen erreichbar; Server als Nutzer ohne Rechte, nur lesbares Dateisystem, keine Capabilities. Keycloak-Verwaltung nur intern. Updates zeitnah einspielen.
  • Rollen trennen: Betreiber des Servers ≠ Mitglied aller Team-Ordner. Der Betreiber sieht Metadaten, aber keine Inhalte. Die Rolle admin erlaubt Ansehen/Archivieren aller Team-Ordner, aber kein Entschlüsseln.
  • Zugriff entziehen wirkt für künftige Abrufe; wer den Schlüssel schon einmal hatte, könnte ältere Kopien weiter entschlüsseln (Tresorformat 8 kennt keine Schlüsselrotation). Bei Austritten mit Risiko „Schlüssel erneuern“ (F10).
  • DSGVO: Verarbeitung im Verzeichnis der Verarbeitungstätigkeiten aufnehmen (Zweck: Zugriffssteuerung auf verschlüsselte Team-Ordner; Daten: siehe Abschnitt 1; Löschung: Konten verschwinden nicht automatisch, wenn sie im Anmeldedienst gelöscht werden – derzeit manuell). Letzte IP-Adresse je Gerät wird gespeichert (Anzeige „zuletzt benutzt“); Zugriffsprotokolle mit Docker-Log-Rotation begrenzen (/etc/docker/daemon.json: log-opts max-size). Protokoll (krywerk_event, Web-Verwaltung → Protokoll): wer wann Mitglieder, Geräte, Ordner geändert und Schlüssel abgerufen hat; keine Inhalte, Schlüssel oder Tokens. Aufbewahrung KRYWERK_SERVER_AUDIT_RETENTION_DAYS (Standard 365 Tage), IP-Adressen nur mit KRYWERK_SERVER_AUDIT_RECORD_IP=true. Im Verzeichnis der Verarbeitungstätigkeiten aufführen; Zugriff hat nur die IT-Administration (verwaltende Personen sehen ihre Ordner).
  • Notfall: Ohne Datenbank und ohne Wiederherstellungsschlüssel sind Team-Ordner nicht mehr zu öffnen. Für jeden wichtigen Team-Ordner mindestens zwei verwaltende Personen und (ab F9) einen versiegelt hinterlegten Wiederherstellungsschlüssel bzw. Notfallzugriff einrichten.

9. Checkliste Inbetriebnahme

  • [ ] DNS-Einträge, Ports 80/443, Server mit automatischen Sicherheitsupdates
  • [ ] Anmeldedienst eingerichtet, Testkonto meldet sich an, Rollen create-vaults vergeben
  • [ ] docker compose run --rm server check ohne Fehler, /health → ok
  • [ ] Krywerk-App: Organisationskonto verbinden, Konto einrichten, Team-Ordner anlegen und mit Testperson teilen
  • [ ] Web-Verwaltung: /verwaltung/ aus dem internen Netz erreichbar, von außen 403; Anmeldung mit admin-Konto
  • [ ] backup.sh per cron, erste Sicherung geprüft (verify), Wiederherstellung in Testinstanz geübt
  • [ ] Docker-Log-Rotation, Überwachung von /health, Ablaufdatum des Entra-Secrets notiert
  • [ ] Eintrag im Verzeichnis der Verarbeitungstätigkeiten, Information der Nutzer