rebreak-monorepo/ops/mdm/ARCHITECTURE.md
chahinebrini 5d6c322129 wip: KeyboardAwareSheet migrations + Snake/Tetris UI + iron.png + useMe live-update
Sheets via neuer KeyboardAwareSheet-Composable (in Modal pattern, auto-grow
mit Tastatur, paddingBottom-Lift): EditMail, AddDomain, CreateRoom, ConnectMail.
GameOverScreen behält Spring-Slide-In, nutzt RN Keyboard.addListener für Lift.

- KeyboardAwareSheet.tsx — universal modal with sheet-grow + keyboard-padding
- react-native-keyboard-controller installiert + KeyboardProvider in Root
- Snake: time + ScoreProgressBar + useSnakeSounds (haptic, audio TODO)
- Tetris: title weg, Buttons zentriert, kein Pressable mit style-fn
- DPad-Buttons 60→48, more bg, no scale
- useMe: pub-sub listener pattern für app-weite avatar/nickname-Updates
- dm.tsx: resolveAvatar wrap (iron.png-Warning)
- Mail-error-humanizer + locales

Recovery-Doc-Update in docs/internal/RECOVERY_LOG_2026-05-10.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 23:59:25 +02:00

123 lines
5.0 KiB
Markdown

# MDM Server — Technische Architektur
## Server
- **Hostname:** rebreak-mdm
- **IP:** 178.105.101.137
- **Provider:** Hetzner Cloud
- **OS:** Ubuntu 24.04
- **SSH:** `ssh rebreak-mdm` (via ~/.ssh/config Alias)
## DNS
- **Domain:** mdm.rebreak.org
- **Registrar:** IONOS
- **Record:** A-Record, 178.105.101.137
- **TTL:** Standard (300-3600s)
## Stack-Komponenten
### nginx (System-Service)
- Version: nginx/1.24.0
- Port 80: HTTP-zu-HTTPS-Redirect (301)
- Port 443: SSL/TLS mit HTTP/2, reverse proxy zu nanomdm
- Config: `/etc/nginx/sites-available/mdm.rebreak.org` (symlinked in sites-enabled)
- TLS: Let's Encrypt via certbot, auto-renewal via systemd-Timer
### NanoMDM (Docker-Container)
- Image: `ghcr.io/micromdm/nanomdm:latest` (v0.9.0 zum Zeitpunkt Setup)
- Container-Name: `nanomdm`
- Compose-File: `/opt/nanomdm/docker-compose.yml`
- Netzwerk-Mode: `host` (kein Bridge-Netzwerk — direkter Zugriff auf localhost:5432)
- Lauscht: `127.0.0.1:9000` (nur localhost, nginx proxiet)
- Restart-Policy: `unless-stopped`
- Volumes:
- `/opt/nanomdm/certs:/certs:ro` (CA-cert + Push-cert)
- `nanomdm-data:/data` (Docker-Volume)
### PostgreSQL (System-Service)
- Version: PostgreSQL 16
- Socket: `127.0.0.1:5432` (localhost only)
- Datenbank: `nanomdm`
- User: `nanomdm`
- Passwort: in `/root/.nanomdm_db_pass` (chmod 600)
- pg_hba: scram-sha-256 für localhost + 172.17.0.0/16 + 172.18.0.0/16 (Docker-Netze)
### Certbot (System-Service)
- Cert-Pfad: `/etc/letsencrypt/live/mdm.rebreak.org/`
- Auto-Renewal: systemd-Timer (certbot.timer), prüft 2x täglich
- Renewal: nginx-Reload nach Renewal via Hook
## Port-Übersicht
| Port | Bind | Service | Beschreibung |
|------|--------------|-----------|------------------------------------|
| 80 | 0.0.0.0 | nginx | HTTP → HTTPS redirect |
| 443 | 0.0.0.0 | nginx | HTTPS, TLS termination, MDM-proxy |
| 9000 | 127.0.0.1 | nanomdm | MDM-Protokoll (intern only) |
| 5432 | 127.0.0.1 | postgres | DB (intern only) |
| 22 | 0.0.0.0 | sshd | Admin-SSH |
UFW-Regeln: 22/tcp, 80/tcp, 443/tcp erlaubt. Alles andere denied by default.
## Zertifikat-Pfade
| Datei | Inhalt | Permissions |
|------------------------------------|---------------------|-------------|
| `/opt/nanomdm/certs/ca.crt` | MDM CA (self-signed)| 644 |
| `/opt/nanomdm/certs/ca.key` | MDM CA Private Key | 600 |
| `/opt/nanomdm/certs/push.csr` | Apple Push CSR | 644 |
| `/opt/nanomdm/certs/push.key` | Apple Push Priv-Key | 600 |
| `/opt/nanomdm/certs/push.pem` | Apple Push Cert (*) | 600 geplant |
| `/root/.nanomdm_db_pass` | Postgres-Passwort | 600 |
(*) `push.pem` existiert noch nicht — warte auf Apple-Portal-Upload (Phase D.1)
## Apple Push Zertifikat — Ablauf
Apple-Geräte erhalten MDM-Befehle via Apple Push Notification Service (APNS). Dafür braucht NanoMDM ein von Apple signiertes Push-Zertifikat.
Ablauf (einmal jährlich zu erneuern):
```
1. Server generiert push.key + push.csr (einmalig, Key bleibt gleich bei Renewal)
2. Admin lädt push.csr auf identity.apple.com/pushcert hoch
3. Apple signiert und stellt push.pem aus (Download)
4. push.pem wird auf Server kopiert: /opt/nanomdm/certs/push.pem
5. nanomdm via -apns-cert oder Umgebungsvariable konfigurieren
6. docker compose restart nanomdm
```
Wichtig: Bei Renewal (jährlich) den GLEICHEN push.key verwenden. Wenn ein neuer Key generiert wird, müssen alle enrollten Geräte re-enrollen.
## Trust-Modell
```
Chahine (Device-Owner)
- enrolled freiwillig
- hat KEINEN MDM-Admin-Zugriff
- kann Profil NICHT selbst entfernen
Olfa (Co-Admin)
- hat SSH-Zugriff auf rebreak-mdm
- kennt MDM-Admin-API-Key (nach Phase E generiert)
- kann Profil entfernen via nanomdm API
Ina Wittek (Trustee, ina.wittek@gmx.de)
- bekommt Notfall-Credentials per Email (Phase E)
- kann Profil entfernen wenn weder Chahine noch Olfa erreichbar
- hat kein Server-Zugriff, nur Credentials für nanomdm-Endpoint
```
## Recovery-Szenarien
| Szenario | Lösung |
|-----------------------------------|-------------------------------------------------------------|
| Profil-Entfernung nötig | Olfa oder Ina nutzen MDM-API oder nanomdm-UI |
| Server down | `ssh rebreak-mdm``docker compose -f /opt/nanomdm/docker-compose.yml up -d` |
| Apple Push Cert abgelaufen | Neues Push Cert via identity.apple.com, gleicher push.key |
| DB korrupt | Backup einspielen (pg_dump), dann nanomdm restart |
| Server kompromittiert | Apple Push Cert revoken auf identity.apple.com, neuer Server, neues Enrollment |
| Device verloren (gestohlen) | MDM-remote-wipe triggern (löscht Gerät), nicht MDM-Profil |
| Factory-Reset vom User | Nuclear option: alle Daten weg, aber MDM-Profil auch weg. Dann re-enroll. |