Der mitgelieferte Objektspeicher kann keine Dokumente aufnehmen #42

Closed
opened 2026-09-01 13:42:19 +00:00 by florian.wilde · 1 comment
Owner

Symptom

Beim Ablegen eines Schreibens scheitert die Anwendung:

[schreiben] Ablegen fehlgeschlagen: [NotImplemented: Server side encryption
specified but KMS is not configured (KMS not configured for a server side
encrypted objects)]

Kein Dokument lässt sich ablegen. Wer der INSTALLATION.md exakt folgt, landet zwangsläufig hier — es ist kein Konfigurationsfehler des Betreibers, sondern der Auslieferungszustand.

Ursache

src/lib/speicher/s3.ts setzt bei jedem PutObject:

ServerSideEncryption: 'AES256',

Das mitgelieferte MinIO (docker-compose.yml, Dienst minio) läuft ohne KMS und lehnt serverseitige Verschlüsselung mit NotImplemented ab.

Warum die Zeile überflüssig geworden ist

Seit v1.11.0 verschlüsselt die Anwendung jede Datei selbst, bevor sie den Server verlässt (src/lib/speicher/umschlag.ts, AES-256-GCM, Schlüssel aus der Umgebung). Serverseitige Verschlüsselung schützt vor nichts, was der eigene Umschlag nicht schon abdeckt.

Im Kommentar von v1.11.0 steht dazu „bleibt zusätzlich stehen; sie kostet nichts". Das ist falsch: Auf MinIO ohne KMS kostet sie die gesamte Funktion. Der Kommentar gehört mit korrigiert.

Umsetzung

ServerSideEncryption nur senden, wenn ausdrücklich konfiguriert — etwa S3_SSE=AES256, Standard leer und damit aus. Wer einen Anbieter nutzt, der SSE anbietet und verlangt, schaltet es per .env dazu.

Der Umweg über MINIO_KMS_SECRET_KEY in einer docker-compose.override.yml ist als Notlösung auf dem Livesystem im Einsatz. Er soll wieder verschwinden: Er handelt sich einen zweiten unverzichtbaren Schlüssel ein, dessen Verlust die Objekte unlesbar macht.

Akzeptanzkriterien

  • Ohne gesetztes S3_SSE enthält die PutObject-Anfrage keinen ServerSideEncryption-Kopf.
  • Mit gesetztem S3_SSE enthält sie ihn mit dem konfigurierten Wert.
  • Unit-Test deckt beide Fälle ab und wird rot, wenn der Kopf wieder fest gesendet wird.
  • .env.example und INSTALLATION.md erklären, wann man den Wert setzt — und dass der mitgelieferte Stack ihn nicht braucht.
  • Der irreführende Kommentar in s3.ts ist korrigiert.
## Symptom Beim Ablegen eines Schreibens scheitert die Anwendung: ``` [schreiben] Ablegen fehlgeschlagen: [NotImplemented: Server side encryption specified but KMS is not configured (KMS not configured for a server side encrypted objects)] ``` Kein Dokument lässt sich ablegen. Wer der `INSTALLATION.md` exakt folgt, landet zwangsläufig hier — es ist kein Konfigurationsfehler des Betreibers, sondern der Auslieferungszustand. ## Ursache `src/lib/speicher/s3.ts` setzt bei jedem `PutObject`: ```ts ServerSideEncryption: 'AES256', ``` Das mitgelieferte MinIO (`docker-compose.yml`, Dienst `minio`) läuft ohne KMS und lehnt serverseitige Verschlüsselung mit `NotImplemented` ab. ## Warum die Zeile überflüssig geworden ist Seit v1.11.0 verschlüsselt die Anwendung jede Datei selbst, bevor sie den Server verlässt (`src/lib/speicher/umschlag.ts`, AES-256-GCM, Schlüssel aus der Umgebung). Serverseitige Verschlüsselung schützt vor nichts, was der eigene Umschlag nicht schon abdeckt. Im Kommentar von v1.11.0 steht dazu „bleibt zusätzlich stehen; sie kostet nichts". Das ist falsch: Auf MinIO ohne KMS kostet sie die gesamte Funktion. Der Kommentar gehört mit korrigiert. ## Umsetzung `ServerSideEncryption` nur senden, wenn ausdrücklich konfiguriert — etwa `S3_SSE=AES256`, Standard leer und damit aus. Wer einen Anbieter nutzt, der SSE anbietet und verlangt, schaltet es per `.env` dazu. Der Umweg über `MINIO_KMS_SECRET_KEY` in einer `docker-compose.override.yml` ist als Notlösung auf dem Livesystem im Einsatz. Er soll wieder verschwinden: Er handelt sich einen zweiten unverzichtbaren Schlüssel ein, dessen Verlust die Objekte unlesbar macht. ## Akzeptanzkriterien - Ohne gesetztes `S3_SSE` enthält die `PutObject`-Anfrage **keinen** `ServerSideEncryption`-Kopf. - Mit gesetztem `S3_SSE` enthält sie ihn mit dem konfigurierten Wert. - Unit-Test deckt beide Fälle ab und wird rot, wenn der Kopf wieder fest gesendet wird. - `.env.example` und `INSTALLATION.md` erklären, wann man den Wert setzt — und dass der mitgelieferte Stack ihn nicht braucht. - Der irreführende Kommentar in `s3.ts` ist korrigiert.
florian.wilde added the in-arbeit label 2026-09-01 14:04:44 +00:00
florian.wilde started working 2026-09-01 14:04:58 +00:00
florian.wilde worked for 3 minutes 2026-09-01 14:08:37 +00:00
Author
Owner

🚀 Umgesetzt und nach main übernommen.

Vorgehen

  1. env.s3.serverseitigeVerschluesselung ergänzt — liest S3_SSE, leer bedeutet aus. Auch eine Zeile mit Leerzeichen zählt als leer.
  2. Im Treiber wird der Kopf nur noch bedingt in den Befehl gestreut.
  3. Den falschen Kommentar aus v1.11.0 richtiggestellt: „kostet nichts" → auf MinIO ohne KMS kostete sie die gesamte Funktion.
  4. .env.example und INSTALLATION.md erklären, wann man den Wert braucht — und dass der mitgelieferte Stack ihn nicht verträgt.
  5. Neue Testdatei tests/speicher-s3.test.ts.

Der eigentliche Gewinn sind die Tests. Der S3-Pfad lief in keinem Test — weder in den 731 Unit-Tests noch in den 95 E2E-Tests, weil in der Entwicklung der Dateitreiber arbeitet. Genau deshalb ist dieser Fehler bis in den Betrieb durchgerutscht, und zwar zweimal: erst beim Einbau der Verschlüsselung, dann beim Stehenlassen der SSE-Zeile.

Die neuen Tests fangen den Befehl ab, bevor er das Netz sieht. Damit ist jetzt belegt statt angenommen, was an den Objektspeicher geht: kein SSE-Kopf ohne Konfiguration, verschlüsselter Inhalt mit BCD1-Kopf, Klartext nicht auffindbar, application/octet-stream als Typ.

Geprüft: 731 Unit-Tests · tsc sauber · Lint sauber · drei Mutationen (SSE fest verdrahtet, leere Angabe nicht abgefangen, Inhalt unverschlüsselt) — jede wird rot.

Für das Livesystem — die Notlösung kann weg

⚠️ Vorher das vorhandene Dokument einmal herunterladen und prüfen, ob es sich öffnen lässt. Es liegt mit SSE abgelegt im Speicher, und MinIO braucht den KMS-Schlüssel, um es herauszugeben.

Danach:

  1. MINIO_KMS_SECRET_KEY aus docker-compose.override.yml und .env entfernen
  2. docker compose up -d
  3. Ein Dokument ablegen — muss funktionieren

Damit verschwindet ein Schlüssel, dessen Verlust die Objekte unlesbar gemacht hätte.

Pull Request: #49 (gemergt)

🚀 **Umgesetzt und nach `main` übernommen.** <!-- claude-status pr: 49 --> **Vorgehen** 1. `env.s3.serverseitigeVerschluesselung` ergänzt — liest `S3_SSE`, leer bedeutet aus. Auch eine Zeile mit Leerzeichen zählt als leer. 2. Im Treiber wird der Kopf nur noch bedingt in den Befehl gestreut. 3. Den falschen Kommentar aus v1.11.0 richtiggestellt: „kostet nichts" → auf MinIO ohne KMS kostete sie die gesamte Funktion. 4. `.env.example` und `INSTALLATION.md` erklären, wann man den Wert braucht — und dass der mitgelieferte Stack ihn nicht verträgt. 5. Neue Testdatei `tests/speicher-s3.test.ts`. **Der eigentliche Gewinn sind die Tests.** Der S3-Pfad lief in keinem Test — weder in den 731 Unit-Tests noch in den 95 E2E-Tests, weil in der Entwicklung der Dateitreiber arbeitet. Genau deshalb ist dieser Fehler bis in den Betrieb durchgerutscht, und zwar zweimal: erst beim Einbau der Verschlüsselung, dann beim Stehenlassen der SSE-Zeile. Die neuen Tests fangen den Befehl ab, **bevor er das Netz sieht**. Damit ist jetzt belegt statt angenommen, was an den Objektspeicher geht: kein SSE-Kopf ohne Konfiguration, verschlüsselter Inhalt mit `BCD1`-Kopf, Klartext nicht auffindbar, `application/octet-stream` als Typ. **Geprüft:** 731 Unit-Tests · `tsc` sauber · Lint sauber · drei Mutationen (SSE fest verdrahtet, leere Angabe nicht abgefangen, Inhalt unverschlüsselt) — jede wird rot. **Für das Livesystem — die Notlösung kann weg** ⚠️ **Vorher** das vorhandene Dokument einmal herunterladen und prüfen, ob es sich öffnen lässt. Es liegt mit SSE abgelegt im Speicher, und MinIO braucht den KMS-Schlüssel, um es herauszugeben. Danach: 1. `MINIO_KMS_SECRET_KEY` aus `docker-compose.override.yml` und `.env` entfernen 2. `docker compose up -d` 3. Ein Dokument ablegen — muss funktionieren Damit verschwindet ein Schlüssel, dessen Verlust die Objekte unlesbar gemacht hätte. **Pull Request:** #49 (gemergt)
florian.wilde removed the in-arbeit label 2026-09-01 14:09:27 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 3 minutes
florian.wilde
3 minutes
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: florian.wilde/betreuungs-cockpit#42