From d7e776b3de151fe28d41ee53b71215343cec09b4 Mon Sep 17 00:00:00 2001
From: ValueOn AG
Date: Wed, 15 Oct 2025 12:33:46 +0200
Subject: [PATCH] admin tool doku
---
.../appdoc/doc_admin_encrypt_env_secret.md | 131 ++++++++++++++++++
...On NDA 2025.docx => PowerOn NDA 2026.docx} | Bin 15607 -> 15553 bytes
2 files changed, 131 insertions(+)
create mode 100644 poweron/appdoc/doc_admin_encrypt_env_secret.md
rename poweron/testdata-wait/{PowerOn NDA 2025.docx => PowerOn NDA 2026.docx} (51%)
diff --git a/poweron/appdoc/doc_admin_encrypt_env_secret.md b/poweron/appdoc/doc_admin_encrypt_env_secret.md
new file mode 100644
index 0000000..5be3eef
--- /dev/null
+++ b/poweron/appdoc/doc_admin_encrypt_env_secret.md
@@ -0,0 +1,131 @@
+### Admin-Leitfaden: *_SECRET-Werte in Env-Dateien verschlüsseln
+
+Diese Anleitung beschreibt, wie das PowerOn-Gateway-Tool `tool_security_encrypt_all_env_files.py` alle unverschlüsselten `*_SECRET`-Variablen in `env_dev.env`, `env_int.env` und `env_prod.env` verschlüsselt.
+
+---
+
+### 1) Einsatz in beliebigen Repositories & Voraussetzungen
+
+Das Tool kann in jedem Repository eingesetzt werden, sofern die untenstehenden Vorbedingungen erfüllt sind. Standardmäßig ist es im Ordner `gateway` integriert und erwartet dort seine Abhängigkeiten. In anderen Repos müssen Sie die Gateway-Komponenten bereitstellen oder den `PYTHONPATH` entsprechend setzen.
+
+- **Ausführungspfad**: Entweder im Verzeichnis, das die Gateway-Module `modules/shared` enthält (z. B. `gateway`), oder mit gesetztem `PYTHONPATH`, sodass `modules/shared/configuration.py` importiert werden kann.
+- **Python**: Python 3.10+ mit Abhängigkeiten (siehe Kapitel „Vorbedingungen“). Installation z. B.:
+ - Windows PowerShell im Repo-Root: `python -m venv .venv && .\.venv\Scripts\Activate.ps1`
+ - `pip install -r requirements.txt`
+- **Dateien**:
+ - Eine `config.ini` (im gleichen Projektteil wie die `modules`), die zumindest `APP_ENV_TYPE` und `APP_KEY_SYSVAR` enthält.
+ - Die zu verarbeitenden Env-Dateien: `env_dev.env`, `env_int.env`, `env_prod.env` (oder eine Teilmenge via `--files`).
+- **Rechte**: Schreibrechte auf die Env-Dateien, Leserechte auf die Masterkey-Quelle (siehe Punkt 2).
+
+Hinweis: Das Tool importiert `encrypt_value` aus `modules/shared/configuration.py`. Stellen Sie sicher, dass dieser Pfad importierbar ist (Start im Gateway-Verzeichnis oder `PYTHONPATH` setzen).
+
+---
+
+### Vorbedingungen
+
+1. `requirements.txt` im Projekt (Minimalbeispiel):
+ ```
+ cryptography>=42.0.0
+ ```
+ Falls Sie das Tool im bestehenden Gateway verwenden, nutzen Sie stattdessen die dortige Datei `gateway/requirements.txt`.
+
+2. Notwendige Gateway-Komponenten (sofern außerhalb von `gateway` verwendet):
+ - `modules/shared/configuration.py` (liefert `APP_CONFIG`, `_get_master_key`, `encrypt_value`, `decrypt_value`)
+ - Optional, aber unterstützt: `modules/shared/auditLogger.py` (Audit-Events; Ausfall ist toleriert)
+ - `config.ini` im gleichen Baum wie `modules`, mit mindestens:
+ - `APP_ENV_TYPE = dev|int|prod` (kann pro Env-Datei zusätzlich gesetzt werden)
+ - `APP_KEY_SYSVAR = `
+
+3. Struktur/Importpfade sicherstellen:
+ - Entweder das Tool im Ordner ausführen, der die `modules`-Struktur enthält (z. B. `gateway`).
+ - Oder `PYTHONPATH` so setzen, dass `modules` auflösbar ist, z. B. PowerShell:
+ ```powershell
+ $env:PYTHONPATH = (Resolve-Path .)
+ python tool_security_encrypt_all_env_files.py --dry-run
+ ```
+
+---
+
+### 2) Masterkey: Herkunft pro Umgebung
+
+Die Verschlüsselung verwendet pro Umgebung einen Masterkey, der in `modules/shared/configuration.py` über `_get_master_key(env_type)` ermittelt wird. Quelle des Keys:
+
+1. `APP_KEY_SYSVAR` (aus `config.ini` oder `.env`) gibt entweder
+ - den **Namen einer OS-Umgebungsvariablen** an, die den Masterkey direkt enthält, oder
+ - einen **Dateipfad** zu einer Key-Datei an.
+
+2. Auflösung in dieser Reihenfolge:
+ - Wenn eine OS-Umgebungsvariable mit dem Namen `APP_KEY_SYSVAR` existiert, wird deren Wert direkt als Masterkey verwendet.
+ - Wenn keine OS-Variable gefunden wird, wird der Wert als Pfad interpretiert. Existiert die Datei, wird sie gelesen. Erwartetes Format je Zeile: `env = key`, z. B.:
+ - `dev = `
+ - `int = `
+ - `prod = `
+ Für die Zielumgebung (z. B. `prod`) wird die passend benannte Zeile verwendet.
+
+3. Der abgeleitete Key wird per PBKDF2 in einen 32-Byte-Schlüssel umgewandelt und für Fernet genutzt. Der verschlüsselte Wert erhält ein Präfix gemäß Umgebung: `DEV_ENC:`, `INT_ENC:`, `PROD_ENC:` (weitere unterstützt: `TEST_ENC:`, `STAGING_ENC:`).
+
+Wichtig: Die Umgebung für die Verschlüsselung wird pro Datei aus der jeweiligen Datei selbst gelesen (`APP_ENV_TYPE=`). D. h. `env_prod.env` wird mit `prod`-Key verschlüsselt, unabhängig von der aktuellen Prozess-Umgebung.
+
+---
+
+### 3) Anwendung und Verhalten
+
+Tool: `gateway/tool_security_encrypt_all_env_files.py`
+
+- Standardlauf (alle drei Dateien, mit Backup):
+ ```bash
+ python tool_security_encrypt_all_env_files.py
+ ```
+ Wirkung:
+ - Liest je Datei `APP_ENV_TYPE`.
+ - Findet alle Schlüssel, deren Name auf `_SECRET` endet, und deren Werte noch kein `*_ENC:`-Präfix haben.
+ - Unterstützt einzeilige und mehrzeilige JSON-Werte (Klammer-Auf/Zu wird erkannt).
+ - Verschlüsselt die Werte mit dem passenden Umgebungs-Key und ersetzt die Originalwerte in der Datei durch `ENV_ENC:`.
+ - Legt vor Änderungen eine Backup-Datei mit Zeitstempel neben der Originaldatei an, z. B. `env_prod.env.20251015_101530.backup`.
+
+- Trockenlauf (nur anzeigen, nichts schreiben):
+ ```bash
+ python tool_security_encrypt_all_env_files.py --dry-run
+ ```
+ Wirkung: Listet, welche Zeilen/Keys verschlüsselt würden. Es werden keine Änderungen vorgenommen und keine Backups erstellt.
+
+- Ohne Backups ausführen:
+ ```bash
+ python tool_security_encrypt_all_env_files.py --no-backup
+ ```
+ Wirkung: Schreibt Änderungen ohne vorherige Backup-Datei.
+
+- Nur bestimmte Dateien verarbeiten:
+ ```bash
+ python tool_security_encrypt_all_env_files.py --files env_dev.env env_prod.env
+ ```
+
+Ausgabe/Ergebnis:
+- Pro Datei: Anzahl gefundener Secrets, Anzahl verschlüsselter Secrets, ggf. Backup-Datei, Fehler.
+- Zusammenfassung am Ende über alle verarbeiteten Dateien.
+
+Was wird als „bereits verschlüsselt“ erkannt?
+- Alle Werte, die mit einem der Präfixe beginnen: `DEV_ENC:`, `INT_ENC:`, `PROD_ENC:`, `TEST_ENC:`, `STAGING_ENC:`. Diese werden übersprungen.
+
+Fehlerbilder und Checks:
+- Fehlt `APP_KEY_SYSVAR` in `config.ini`/`.env` oder zeigt er auf eine nicht existierende OS-Variable/Datei, schlägt die Verschlüsselung fehl.
+- Fehlt in einer Key-Datei der passende Eintrag für die Zielumgebung, wird ein Fehler gemeldet.
+- Schreibfehler (z. B. fehlende Rechte) verhindern das Aktualisieren der Env-Datei.
+
+---
+
+### Best Practices
+
+- Änderungen zuerst mit `--dry-run` prüfen.
+- Vor Produktivläufen sicherstellen, dass `APP_KEY_SYSVAR` korrekt auf OS-Variable oder Key-Datei zeigt und die Datei einen Eintrag für die Zielumgebung enthält.
+- Backups beibehalten, um bei Bedarf Änderungen zurückzurollen.
+- JSON-Secrets in Env-Dateien korrekt mit `{ ... }` kapseln; das Tool erkennt und ersetzt mehrzeilige JSON-Blöcke vollständig.
+
+---
+
+### Referenz
+
+- Schlüsselauflösung und Verschlüsselung: `gateway/modules/shared/configuration.py` (`_get_master_key`, `_derive_encryption_key`, `encrypt_value`).
+- Batch-Tool: `gateway/tool_security_encrypt_all_env_files.py` (`encrypt_all_secrets_in_file`, `process_all_env_files`).
+
+
diff --git a/poweron/testdata-wait/PowerOn NDA 2025.docx b/poweron/testdata-wait/PowerOn NDA 2026.docx
similarity index 51%
rename from poweron/testdata-wait/PowerOn NDA 2025.docx
rename to poweron/testdata-wait/PowerOn NDA 2026.docx
index 66ea0b504e2bb53407e38042f9f4a8f1b8c68a22..364fb2646efcca46779b5365ac293fbc49f6eade 100644
GIT binary patch
delta 5190
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