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>
123 lines
5.0 KiB
Markdown
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. |
|