Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09aaf1b2b5 | ||
|
|
337dbe85ac | ||
|
|
e462980dac | ||
|
|
79db6a8e49 | ||
|
|
25d1742d61 | ||
|
|
736c39a413 | ||
|
|
22a0823b7e | ||
|
|
3054037480 | ||
|
|
8f1d39b7a8 | ||
|
|
edf224e450 | ||
|
|
b32920c48f |
@@ -8,3 +8,4 @@ resources:
|
||||
- certificate.yaml
|
||||
- authentik.yaml
|
||||
- ingress.yaml
|
||||
- networkpolicy.yaml
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# Default-deny ingress for the authentik namespace, with explicit allow rules for the
|
||||
# traffic paths that actually need to reach in: Traefik (kube-system) for the public
|
||||
# auth.axion1337.chat endpoint and ACME HTTP-01 challenges, and MAS (matrix namespace)
|
||||
# for upstream OIDC calls. Egress is intentionally untouched (federation-equivalent
|
||||
# outbound calls like SMTP aren't restricted here).
|
||||
#
|
||||
# Note: authentik-postgresql already has its own NetworkPolicy from the Bitnami
|
||||
# postgresql subchart (port 5432, no source restriction) - left alone, not duplicated,
|
||||
# since it would get reset on the next Helm upgrade anyway.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-ingress
|
||||
namespace: authentik
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-authentik-server
|
||||
namespace: authentik
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: authentik
|
||||
app.kubernetes.io/component: server
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: matrix
|
||||
ports:
|
||||
# NetworkPolicy matches the pod's actual container port, not the Service's
|
||||
# external port - the authentik-server Service maps 80->9000, 443->9443.
|
||||
- protocol: TCP
|
||||
port: 9000
|
||||
- protocol: TCP
|
||||
port: 9443
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-acme-solver
|
||||
namespace: authentik
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
acme.cert-manager.io/http01-solver: "true"
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8089
|
||||
@@ -59,6 +59,14 @@ spec:
|
||||
enabled: true
|
||||
ingress:
|
||||
host: mrtc.axion1337.chat
|
||||
# Chart default (20Mi request+limit) OOM-killed the authorisation service after
|
||||
# ~74 days of uptime (2026-07-28) - too tight for a long-running Go service.
|
||||
resources:
|
||||
requests:
|
||||
memory: 64Mi
|
||||
cpu: 50m
|
||||
limits:
|
||||
memory: 128Mi
|
||||
|
||||
# Element Web
|
||||
elementWeb:
|
||||
@@ -66,7 +74,7 @@ spec:
|
||||
image:
|
||||
registry: rohana.axion1337.de
|
||||
repository: sorb/threadnet-web
|
||||
tag: v0.2.1-elementcall-noquotavp9
|
||||
tag: v0.2.3-elementcall-h264
|
||||
ingress:
|
||||
host: axion1337.chat
|
||||
|
||||
|
||||
Regular → Executable
+2
-1
@@ -29,4 +29,5 @@ resources:
|
||||
# HelmRelease (muss ganz unten stehen, damit die ConfigMaps vorher da sind!)
|
||||
- element-server-suite.yaml
|
||||
# Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat
|
||||
- apex-ingress.yaml # Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat
|
||||
- apex-ingress.yaml # Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat
|
||||
- networkpolicy.yaml
|
||||
@@ -0,0 +1,293 @@
|
||||
# Default-deny ingress for the matrix namespace, with explicit allow rules per component.
|
||||
# Egress is intentionally untouched (federation to arbitrary Matrix servers, ACME, SMTP,
|
||||
# DNS all stay unrestricted).
|
||||
#
|
||||
# Lesson learned deploying the authentik namespace's equivalent policy: NetworkPolicy
|
||||
# filters on the pod's actual container port, not the Service's external port (e.g.
|
||||
# authentik-server's Service maps 80->9000). Wherever a Service here uses a *named*
|
||||
# targetPort, this file references that name directly instead of guessing a number -
|
||||
# Kubernetes resolves it from the pod spec, which is safer than a hardcoded port.
|
||||
#
|
||||
# matrix-stack-postgres already effectively has no dedicated chart NetworkPolicy of its
|
||||
# own (unlike authentik-postgresql's Bitnami one) - the rules below are the only gate.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny-ingress
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
---
|
||||
# axion1337.chat (root) -> Element Web
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-element-web
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: element-web
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: element
|
||||
---
|
||||
# admin.axion1337.chat -> Element Admin
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-element-admin
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: element-admin
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: http
|
||||
---
|
||||
# axion1337.chat/docs/setup -> Element desktop setup docs (our own nginx)
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-element-web-docs
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app: element-web-docs
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
---
|
||||
# matrix.axion1337.chat AND the well-known delegation both front through haproxy
|
||||
# (matrix-stack-synapse and matrix-stack-well-known Services both target haproxy's
|
||||
# named ports, not synapse-main directly).
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-haproxy
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: haproxy
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: haproxy-synapse
|
||||
- protocol: TCP
|
||||
port: haproxy-403
|
||||
- protocol: TCP
|
||||
port: haproxy-wkd
|
||||
---
|
||||
# account.axion1337.chat (Traefik) + matrix.axion1337.chat (also routes to MAS for some
|
||||
# paths) + synapse-main calling MAS's internal port for session/token introspection.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-mas
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: matrix-authentication-service
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: synapse-main
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: synapse-main
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8081
|
||||
---
|
||||
# Synapse itself: reached via haproxy (same namespace), calls from MAS (provisioning),
|
||||
# metrics scraped by Alloy (monitoring namespace).
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-synapse
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: synapse-main
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: haproxy
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: matrix-authentication-service
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: synapse-http
|
||||
- protocol: TCP
|
||||
port: synapse-health
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: monitoring
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: synapse-metrics
|
||||
---
|
||||
# mrtc.axion1337.chat (Traefik) for the auth handshake, plus Alloy scraping metrics.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-rtc-authorisation-service
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: matrix-rtc-authorisation-service
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: matrix-rtc-sfu
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: http
|
||||
---
|
||||
# The SFU: mrtc.axion1337.chat (Traefik) for signalling, Alloy for metrics, and the
|
||||
# NodePort-exposed WebRTC media ports need to stay open to the internet by design -
|
||||
# that's the actual point of a TURN/SFU media relay, not a mistake.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-rtc-sfu
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: matrix-rtc-sfu
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: http
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: monitoring
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: metrics
|
||||
- from:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 30001
|
||||
- protocol: UDP
|
||||
port: 30002
|
||||
---
|
||||
# Postgres: only Synapse and MAS need data access; Alloy scrapes the exporter.
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-postgres
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: postgres
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: synapse-main
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: matrix-authentication-service
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5432
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: monitoring
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 9187
|
||||
---
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-ingress-acme-solver
|
||||
namespace: matrix
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
acme.cert-manager.io/http01-solver: "true"
|
||||
policyTypes:
|
||||
- Ingress
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
kubernetes.io/metadata.name: kube-system
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8089
|
||||
|
||||
# Note: coturn runs with hostNetwork: true, so NetworkPolicy does not apply to it at all -
|
||||
# it's already gated by the Hetzner Cloud Firewall instead. Nothing to write here.
|
||||
+66
-57
@@ -1,7 +1,7 @@
|
||||
# aXion1337.Chat – Task List & Meilensteine
|
||||
|
||||
**Last Updated**: 2026-07-28
|
||||
**Statusübersicht**: [✅ 12 Abgeschlossen] [🔄 0 In Progress] [📋 9+ Pending] [🔒 10 Security]
|
||||
**Statusübersicht**: [✅ 13 Abgeschlossen] [🔄 0 In Progress] [📋 8+ Pending] [🔒 10 Security]
|
||||
|
||||
---
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
|
||||
| Kategorie | Count | Status | Details |
|
||||
|-----------|-------|--------|---------|
|
||||
| **Completed** | 12 | ✅ Done | K3S, Flux, ESS, Themes, Desktop, Monitoring, TURN, Authentik (Deploy+Enrollment/Recovery/2FA), Firewall, SSH, coturn Fix, Element Call Fork |
|
||||
| **Completed** | 13 | ✅ Done | K3S, Flux, ESS, Themes, Desktop, Monitoring, TURN, Authentik (Deploy+Enrollment/Recovery/2FA), Firewall, SSH, coturn Fix, Element Call Fork, NetworkPolicies |
|
||||
| **In Progress** | 0 | 🔄 — | — |
|
||||
| **Backlog** | 9+ | 📋 Pending | DB Backups, PostgreSQL Migration, NetworkPolicies, MAS-Template-Link, VP9-Retry |
|
||||
| **Backlog** | 8+ | 📋 Pending | DB Backups, PostgreSQL Migration, MAS-Template-Link, VP9-Retry |
|
||||
| **Security Tasks** | 5 | 🔒 Pending | auditd, Kernel hardening, CrowdSec, Falco, WAF |
|
||||
|
||||
### Priority Distribution
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 🗓️ Session-Zusammenfassung 2026-07-27/28 (weiter morgen)
|
||||
## 🗓️ Session-Zusammenfassung 2026-07-27/28 (fortlaufend aktualisiert)
|
||||
|
||||
Nach längerer Pause wiederaufgenommen — Mac war neu aufgesetzt, Zugriff (SSH, Kubeconfig,
|
||||
age-Key, Homebrew/flux/helm/sops/age) komplett wiederhergestellt und dauerhaft in `~/.zshrc`
|
||||
@@ -43,14 +43,37 @@ verankert. Was in dieser Session erledigt wurde:
|
||||
**Wichtig**: erzwungenes `video_codec: vp9` hat Calls kurzzeitig live komplett kaputt gemacht
|
||||
(kein Bild/Ton) — sofort zurückgerollt, ohne Codec-Zwang läuft's. Root Cause dafür nicht
|
||||
abschließend isoliert, nur umgangen.
|
||||
4. **Identitäts-Aufräumarbeiten**: `sorB`'s Authentik-E-Mail korrigiert (`thorec@hotmail.de`),
|
||||
MAS OIDC-Link (`upstream_oauth_links`) von `sorB` zeigte fest auf den alten MAS-User
|
||||
`akadmin`/`@akadmin:axion1337.chat` (Sub-Hash ist stabil über Username-Renames, daher blieb
|
||||
die Verknüpfung nach dem Rename "akadmin"→"sorB" bestehen) — umgehängt auf `sorb`/
|
||||
`@sorb:axion1337.chat`. Neue Identität `elbojoloco` angelegt (E-Mail `cfx@riot.8shield.net`),
|
||||
verknüpft mit dem alten `akadmin`-MAS-User. **Übrig**: ein leeres, unverknüpftes
|
||||
`@bojeledoggo:axion1337.chat`-Konto (Tippfehler-Artefakt) — User räumt das selbst auf.
|
||||
5. **NetworkPolicies** (Issue #10 ✅ geschlossen) — siehe "Network Security" Abschnitt unten.
|
||||
Zwei Live-Incidents beim Rollout (Port-Verwechslungen), beide binnen Minuten live gepatcht
|
||||
und danach committed. Nebenbei: `matrixRTC`-Authorisation-Service OOM-Fix (20Mi→128Mi).
|
||||
6. **Element Call Qualität nachgeschärft** — 720p-Zwischen-Simulcast-Layer ergänzt (sonst
|
||||
harter Sprung von 1440p auf blockiges 360p bei kleinsten Netzwerkschwankungen), und
|
||||
`video_codec: h264` statt VP8 (klassisches Simulcast wie VP8, kein SVC-Risiko wie bei
|
||||
VP9, oft hardwarebeschleunigt v.a. auf iOS). Live verifiziert: 7/8 Tracks nativ H.264,
|
||||
1 sauberer VP8-Fallback. Deployed als `v0.2.3-elementcall-h264`.
|
||||
7. **Backlog nach Gitea migriert** — restlicher offener Backlog (VP9-Retry, ThreadNet-Web-Bug,
|
||||
MAS-Template-Link, WAF und 17 weitere Security-/Infra-Punkte) als Issues #11–#31 angelegt,
|
||||
veraltete erledigte Punkte (Authentik Stage 2/E2E-Test/Invite-Links, Hetzner-Firewall,
|
||||
SSH-Hardening) aus dieser Datei entfernt bzw. als done markiert.
|
||||
|
||||
### Offene Punkte für morgen
|
||||
- **VP9-Retry**: Root Cause des Call-Ausfalls isolieren (Browser-Konsolen-Repro nötig), bevor
|
||||
wieder versucht wird — siehe Backlog "Element Call Enhancement".
|
||||
### Offene Punkte
|
||||
- **VP9-Retry**: vermutete Ursache jetzt bekannt (LiveKit nutzt SVC für vp9/av1, Fork-Code
|
||||
setzt aber immer Simulcast-Layer) — braucht einen Code-Fix in `buildPublishOptions()`
|
||||
(`src/livekit/options.ts`) bevor erneut versucht wird. Stattdessen H.264 probiert (siehe
|
||||
unten) — läuft gut, kein SVC-Risiko, hardwarebeschleunigt auf mehr Geräten.
|
||||
- **`ThreadNet-Web` Build-Bug**: `scripts/docker-link-repos.sh`/`docker-package.sh` nicht
|
||||
ausführbar committet + veralteter `matrix-js-sdk#develop`-Pin im Lockfile blockiert
|
||||
vollständigen Neu-Build des Web-Forks. Noch nicht gefixt, User hat noch nicht final
|
||||
entschieden ob gewünscht.
|
||||
- **Verwaistes `@bojeledoggo:axion1337.chat`**: leeres Matrix-Konto ohne OIDC-Link, User räumt
|
||||
das selbst auf (braucht dafür seinen eigenen Access-Token für die Admin-API).
|
||||
- **MAS-Template-Link**: 2FA/Passkey-Setup-Links direkt auf `account.axion1337.chat/account/`
|
||||
statt nur über `docs/setup/security.html` — braucht MAS Custom-Template-Override
|
||||
(`templates.path`), größerer separater Task.
|
||||
@@ -247,31 +270,22 @@ verankert. Was in dieser Session erledigt wurde:
|
||||
- [x] **matrix-recovery Flow gebaut** – war komplett leer (0 Stages); Passwort-Reset funktioniert jetzt, verlinkt von der echten Login-Seite
|
||||
- [x] **Brand.default_application gesetzt** – behebt mehrere Dead-Ends, wenn eingeloggte User `/` ohne Ziel aufrufen
|
||||
- [x] **2FA/Passkey Selbst-Einrichtung** – Links zu `default-authenticator-totp-setup`/`-webauthn-setup` (2FA bleibt optional, `not_configured_action=skip`), dokumentiert unter `axion1337.chat/docs/setup/security.html`
|
||||
- [ ] **Backlog**: MAS Custom-Template-Override, um den 2FA/Passkey-Link direkt auf `account.axion1337.chat/account/` anzuzeigen (statt nur über die Doku-Seite) – erfordert Forken der MAS Tera/Askama-Templates via `templates.path`, höherer Aufwand/Risiko, bei MAS-Updates zu pflegen
|
||||
- [ ] **Backlog**: → **Issue #13** (MAS Custom-Template-Override für 2FA/Passkey-Link auf `account.axion1337.chat/account/`)
|
||||
|
||||
---
|
||||
|
||||
## 📋 Backlog (Weitere Aufgaben)
|
||||
|
||||
### Authentik Completion
|
||||
- [ ] **Finish Authentik Stage 2 – MAS Integration**
|
||||
- Prerequisites: Authentik OIDC Provider vollständig konfiguriert
|
||||
- Task: Update `mas-secret.yaml`, enable password login disable
|
||||
- Commit: `enable-authentik-oidc-integration-in-mas`
|
||||
- Est. Effort: 30 min (manual + scripted)
|
||||
|
||||
- [ ] **Test End-to-End Login Flow**
|
||||
- Element Web login → MAS → Authentik → Matrix User Creation
|
||||
- Create test users via Authentik
|
||||
- Verify password reset flow
|
||||
- Commit: (implicit in Stage 2)
|
||||
- Est. Effort: 20 min
|
||||
|
||||
- [ ] **Create Invite Links für neue User**
|
||||
- Authentik Admin UI → Invitations → Create
|
||||
- Set expiry dates (7d) + use limits
|
||||
- Document procedure
|
||||
- Est. Effort: 15 min
|
||||
**Ab 2026-07-28 in Gitea-Issues gepflegt statt hier** (eine Quelle der Wahrheit) — offene Issues:
|
||||
[#6](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/issues/6) DB-Backup-Strategie,
|
||||
[#9](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/issues/9) Externe PostgreSQL-Migration,
|
||||
[#11](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/issues/11)–[#31](https://rohana.axion1337.de/sorb/axion1337.chat-gitops/issues/31)
|
||||
(VP9-Retry, ThreadNet-Web-Build-Bug, MAS-Template-Link, WAF, Media-PVC-Backups, Pod Security
|
||||
Admission, Federation-Allowlist, Mjolnir/Draupnir, Content-Scanner, External-Secrets,
|
||||
Renovate/Trivy, Security-Advisory-Monitoring, automountServiceAccountToken,
|
||||
unattended-upgrades, K3s-API-Security, auditd, Kernel-Hardening, Lynis, CrowdSec, Falco).
|
||||
Die detaillierten Beschreibungen unten sind das historische Original, aus dem die Issues
|
||||
entstanden sind — nicht mehr getrennt pflegen, stattdessen die Issues aktuell halten.
|
||||
|
||||
### Element Call Enhancement
|
||||
- [x] **Element Call Fork für Custom Constraints** (2026-07-28, Closes #8)
|
||||
@@ -334,18 +348,29 @@ verankert. Was in dieser Session erledigt wurde:
|
||||
- Priority: **HIGH** (data preservation)
|
||||
|
||||
### Network Security
|
||||
- [ ] **NetworkPolicies – K8s-Layer Segmentation**
|
||||
- Default-Deny Ingress für `matrix` namespace
|
||||
- Allow rules:
|
||||
- Ingress → MAS:443
|
||||
- Ingress → ElementWeb:443
|
||||
- MAS ↔ Synapse:8008
|
||||
- Synapse ↔ Postgres:5432
|
||||
- Authentik → Postgres:5432
|
||||
- Authentik → Loki:3100 (monitoring)
|
||||
- Egress: Matrix-specific (federation, etc.)
|
||||
- Est. Effort: 1 day
|
||||
- Priority: **MEDIUM** (compliance, least-privilege)
|
||||
- [x] **NetworkPolicies – K8s-Layer Segmentation** (2026-07-28, Closes #10)
|
||||
- Default-Deny Ingress (egress left untouched) für `matrix` UND `authentik` namespaces,
|
||||
per-Komponente Allow-Regeln in `apps/authentik/networkpolicy.yaml` und
|
||||
`apps/production/networkpolicy.yaml`. Rollout: authentik zuerst als Pilot, dann matrix.
|
||||
- Empirisch verifiziert, dass K3s' eingebauter NetworkPolicy-Controller tatsächlich
|
||||
durchsetzt (Testnamespace, Timeout- statt Refused-Verhalten unter Deny-Policy).
|
||||
- **Zwei Live-Incidents beim Rollout, beide binnen Minuten behoben**:
|
||||
1. `authentik-server`: Regel erlaubte Service-Port 80/443, aber NetworkPolicy filtert
|
||||
auf dem tatsächlichen Container-Port (9000/9443 nach kube-proxy-DNAT) — 502 auf
|
||||
`auth.axion1337.chat`, sofort korrigiert.
|
||||
2. `matrix-authentication-service`: Regel erlaubte Synapse nur auf Port 8081, aber
|
||||
Synapse ruft `/oauth2/introspect` tatsächlich auf **Port 8080** — jede
|
||||
authentifizierte Anfrage (inkl. `/sync`) scheiterte mit 503, alle Clients zeigten
|
||||
"Verbindung unterbrochen". Live gepatcht, dann committed.
|
||||
- Lehre für zukünftige NetworkPolicies in diesem Repo: wo immer ein Service benannte
|
||||
Ports (`targetPort: <name>`) nutzt, diese direkt in der Policy referenzieren statt
|
||||
Portnummern zu raten — schließt genau diese Fehlerklasse aus.
|
||||
- Nebenbefund (unabhängig von NetworkPolicies): `matrixRTC`-Authorisation-Service hatte
|
||||
ein 20Mi-Memory-Limit (Chart-Default), OOM-gekillt nach ~74 Tagen Uptime während der
|
||||
Verifikations-Calls — auf 64Mi/128Mi angehoben.
|
||||
- `coturn` (hostNetwork) bewusst ausgenommen — NetworkPolicy greift dort nicht.
|
||||
- `authentik-postgresql`'s Bitnami-Chart-Policy (Port 5432, quelloffen) bewusst nicht
|
||||
angefasst/dupliziert, da Helm-verwaltet.
|
||||
|
||||
- [ ] **Pod Security Admission (Restricted)**
|
||||
- Apply to `matrix` & `authentik` namespaces
|
||||
@@ -425,24 +450,8 @@ verankert. Was in dieser Session erledigt wurde:
|
||||
## 🔒 Security Hardening (Host & Cluster Level)
|
||||
|
||||
### Host OS Layer (Ubuntu/Debian)
|
||||
- [ ] **Hetzner Cloud Firewall**
|
||||
- Default-Deny inbound
|
||||
- Allow: 80/443 (HTTP/HTTPS)
|
||||
- Allow: 22 (SSH) from your IP only (or via WireGuard/Tailscale)
|
||||
- Status: ✅ Can be done in Hetzner UI
|
||||
- Est. Effort: 30 min
|
||||
- Priority: **CRITICAL** (immediate, zero config cost)
|
||||
|
||||
- [ ] **SSH Hardening**
|
||||
- Disable password auth (key-only)
|
||||
- Disable root login
|
||||
- PermitRootLogin: no
|
||||
- PasswordAuthentication: no
|
||||
- MaxAuthTries: 3
|
||||
- Optional: Change SSH port (cosmetic, reduces log noise)
|
||||
- Optional: SSH hinter WireGuard/Tailscale (eliminates fail2ban für SSH)
|
||||
- Est. Effort: 2 hours
|
||||
- Priority: **HIGH** (immediate)
|
||||
- [x] **Hetzner Cloud Firewall** – Default-Deny inbound, siehe "Phase 7" oben. **Done.**
|
||||
- [x] **SSH Hardening** – Key-only, Root-Login disabled, Port 2248, siehe "Phase 7" oben. **Done.**
|
||||
|
||||
- [ ] **unattended-upgrades**
|
||||
- Enable automatic security updates
|
||||
|
||||
@@ -57,9 +57,16 @@
|
||||
LiveKits eigener Empfehlung für Mensch-zu-Mensch-Calls. Bewusst **kein** server-seitiges
|
||||
ML-Noise-Cancellation (siehe `docs/TASKS.md` Backlog).
|
||||
- **Incident (2026-07-28)**: Erster Versuch mit erzwungenem `video_codec: vp9` hat Calls
|
||||
komplett kaputt gemacht (kein Bild/Ton). Sofort zurückgerollt, dann ohne erzwungenen Codec
|
||||
(Standard VP8) mit denselben Auflösungswerten neu deployed — funktioniert, live bestätigt.
|
||||
VP9 vorerst zurückgestellt (Backlog).
|
||||
komplett kaputt gemacht (kein Bild/Ton). Sofort zurückgerollt. Vermutete Ursache: LiveKit
|
||||
nutzt für vp9/av1 SVC statt klassischem Simulcast, `buildPublishOptions()` im Fork setzt
|
||||
aber immer Simulcast-Layer — Code-Fix nötig, bevor vp9 erneut versucht wird (Backlog).
|
||||
- **720p-Zwischen-Layer ergänzt** (`simulcast_layers`) — ohne eigene Definition fiel die
|
||||
Übertragung bei kleinsten Netzwerkschwankungen direkt von 1440p auf blockiges 360p, jetzt
|
||||
sanftere Abstufung über 720p.
|
||||
- **H.264 statt VP8** (2026-07-28) — nutzt wie VP8 klassisches Simulcast (kein SVC-Risiko wie
|
||||
bei VP9), zusätzlich auf vielen Geräten (v.a. iOS/Safari) hardwarebeschleunigt. Live
|
||||
verifiziert: 7 von 8 Video-Tracks liefen über H.264, 1 fiel sauber auf den VP8-Backup-Codec
|
||||
zurück (kein Ausfall). Deployed als `v0.2.3-elementcall-h264`.
|
||||
- Deployt als `rohana.axion1337.de/sorb/threadnet-web:v0.2.1-elementcall-noquotavp9` — nur
|
||||
der `/app/widgets/element-call/`-Ordner im bestehenden `v0.1.0`-Image ausgetauscht, da
|
||||
`ThreadNet-Web` einen vorbestehenden Build-Bug hat (siehe unten).
|
||||
|
||||
Regular → Executable
+29
-1
@@ -75,4 +75,32 @@ flux get helmreleases -n matrix --watch
|
||||
# Zeigt, wie die Pods hochfahren:
|
||||
kubectl get pods -n matrix -w
|
||||
```
|
||||
Sobald alle Pods auf `Running` stehen und die Zertifikate über Let's Encrypt validiert wurden (`kubectl get certificate -n matrix`), ist dein Matrix-Stack unter `https://axion1337.chat` erreichbar.
|
||||
Sobald alle Pods auf `Running` stehen und die Zertifikate über Let's Encrypt validiert wurden (`kubectl get certificate -n matrix`), ist dein Matrix-Stack unter `https://axion1337.chat` erreichbar.
|
||||
|
||||
---
|
||||
|
||||
## 🔁 Recovery: lokalen age-Key wiederherstellen (Server läuft bereits)
|
||||
|
||||
Anders als Schritt 2 oben (neuen Key **erzeugen**) — falls der Server bereits läuft und nur der
|
||||
lokale Rechner den age-Key verloren hat (z.B. nach einer Neuinstallation), lässt sich der
|
||||
**bestehende** Private Key direkt aus dem Cluster zurückholen, ohne einen neuen zu generieren
|
||||
(das würde `.sops.yaml` und alle bereits verschlüsselten Secrets ungültig machen):
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.age
|
||||
kubectl get secret sops-age -n flux-system -o jsonpath='{.data.age\.agekey}' | base64 -d > ~/.age/keys.txt
|
||||
chmod 600 ~/.age/keys.txt
|
||||
|
||||
# Public Key zur Kontrolle gegen .sops.yaml abgleichen:
|
||||
grep 'public key:' ~/.age/keys.txt
|
||||
grep 'age:' .sops.yaml
|
||||
```
|
||||
|
||||
Voraussetzung: laufender Kubeconfig-Zugriff auf den Cluster (siehe Schritt 1 oben — auch das
|
||||
ist reines Zurückkopieren, kein Neu-Erzeugen).
|
||||
|
||||
**Bekannte Schwachstelle**: Dieser Key existiert aktuell nur an zwei Orten — im
|
||||
`sops-age`-Secret selbst (auf demselben Server) und lokal bei wem auch immer ihn zuletzt
|
||||
zurückgeholt hat. Es gibt kein separates, offsite Backup. Fällt der Server komplett aus
|
||||
(nicht nur der lokale Rechner), sind alle SOPS-verschlüsselten Secrets im Repo unlesbar.
|
||||
Siehe Issue-Backlog für die Entscheidung, ob/wie das abgesichert wird.
|
||||
Reference in New Issue
Block a user