Compare commits

...

26 Commits

Author SHA1 Message Date
Scrublord MacBad
5bbb03bc52 refactor: Organize troubleshooting docs into docs/troubleshooting/
Move all Authentik troubleshooting guides into dedicated subdirectory:
- DIAGNOSTIK-AUTHENTIK-FLOW.md
- AUTHENTIK-FIX-TEMPLATE.md
- AUTHENTIK-INVITATION-FLOW-FIX.md
- AUTHENTIK-CREATE-INVITATION-FLOW.md

Add README.md with:
- Quick reference guide for each document
- Scenario-based navigation
- Known issues tracking
- Tips and best practices

This keeps the root directory clean and organizes related guides together.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-18 13:03:33 +02:00
Scrublord MacBad
af13688993 docs: Add step-by-step guide to create Authentik Invitation Flow
Root cause analysis:
- Only one matrix-enrollment flow exists
- Used for both standard signup AND invitations
- Causes flow conflicts: 'Found existing plan for other flow'
- Error when Klaus enrollment attempted: 'kein ausstehender benutzer Anfrage wurde verweigert'

Solution:
- Create separate matrix-invitation flow
- Use for invitation links only
- Prevents conflicts and allows proper field capture (email is mandatory)

This guide provides:
1. Step-by-step flow creation (5 stages)
2. Field configuration for Prompt Stage
3. Binding setup for each stage
4. Testing procedure with invitation link
5. Troubleshooting checklist

Related issues: Klaus enrollment failure, Boje enrollment failure

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-18 12:52:35 +02:00
Scrublord MacBad
f70e77127e docs: Add Authentik Invitation Flow repair guide
The Invitation Flow is not properly configured:
- Only username is captured during invitations
- Email field is missing (required for OIDC token generation)
- 'Fehler fehlende Rechte' error indicates incomplete user data

This guide walks through:
1. Diagnosing the current Invitation Flow configuration
2. Creating/repairing the Prompt Stage with email field
3. Adding the Prompt Stage to the Invitation Flow
4. Testing the complete enrollment process

Related to: User Boje enrollment failure via invitation link

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-18 12:36:56 +02:00
Scrublord MacBad
f658ce2980 docs: Add Authentik enrollment flow diagnostics and repair guides
- DIAGNOSTIK-AUTHENTIK-FLOW.md: Comprehensive troubleshooting guide
- AUTHENTIK-FIX-TEMPLATE.md: Repair instructions for common issues

These guides help debug why Boje user was created in Authentik but not synchronized to Matrix.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-18 12:24:49 +02:00
Scrublord MacBad
b29c7516d4 Update: Authentik 2026.2.3
Some checks failed
Auto-Deploy on Push / verify-and-notify (push) Has been cancelled
2026-05-15 15:05:06 +02:00
Scrublord MacBad
c32f951716 Update TASKS.md: Mark 3 CRITICAL tasks complete
- Authentik Stage 2: OIDC integration verified (login working)
- Hetzner Cloud Firewall: Configured & optimized
- SSH Hardening: Key-only auth, no root, rate limiting verified

Updated status: 9 completed, 0 in-progress, 11+ pending
All 3 CRITICAL security tasks done. Next: Database Backups

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-15 13:48:00 +02:00
Scrublord MacBad
cdfbf7de98 Enable Authentik OIDC integration in MAS
Some checks failed
Auto-Deploy on Push / verify-and-notify (push) Has been cancelled
- Add upstream_oauth2_config with Authentik provider credentials
- Configure OIDC with client_id and client_secret from Authentik
- Disable local password authentication (OIDC-only login)
- Set claims mapping: subject, localpart, displayname, email

This enables users to login via Authentik OIDC provider with email
and username claims properly mapped for Matrix user provisioning.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-15 11:05:52 +02:00
Scrublord MacBad
b1247b4720 backup old wiki 2026-05-14 23:34:59 +02:00
Scrublord MacBad
6bcbe9cc9e Add Gitea Actions workflows for CI/CD automation
Some checks failed
Auto-Deploy on Push / verify-and-notify (push) Has been cancelled
- deploy-on-push.yml: Verify YAML, check SOPS encryption, notify on deployments
- milestone-release.yml: Auto-create releases on milestone tags

Triggers:
- deploy-on-push: On any push to main (apps/clusters changes)
- milestone-release: On git tag m*-*-complete

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 23:29:50 +02:00
Scrublord MacBad
b8da70b14b Add status summary and prioritized next steps to TASKS.md
Add at top of TASKS.md:
- Status Summary table (quick view of progress)
- Priority distribution (CRITICAL/HIGH/MEDIUM/LOW)
- Next Steps section (this week, 1-2 weeks)
- Each task includes: description, effort estimate, blocking factors

Makes task list immediately actionable and progress trackable.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 23:08:00 +02:00
Scrublord MacBad
4cf6702f85 Add comprehensive task list and VSCode todo-tree integration
Add docs/TASKS.md:
- Completed tasks (6): K3S, Flux, ESS, Themes, Desktop Scripts, Monitoring, TURN
- In Progress: Authentik Stage 2 (pending manual config)
- Backlog (15+): Element Call Fork, PostgreSQL migration, NetworkPolicies, etc.
- Security hardening: Host/Cluster/App layer recommendations
- Milestones: Track progress from M1 (Basic) to M7 (Enterprise)

Enhance devcontainer.json:
- Add gruntfuggly.todo-tree extension for task tree view
- Add ms-vscode.makefile-tools for build automation
- Add GitHub.copilot for development assistance
- Configure todo-tree to highlight TASKS.md and deployment guides

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 23:05:33 +02:00
Scrublord MacBad
aee9a34369 Add 5 detailed deployment guides to docs/deployment-guides/
- 01-turn-server-setup.md: TURN Server architecture, deployment, verification
- 02-authentik-identity-provider.md: Two-stage OIDC integration (Stage 1 & Stage 2)
- 03-monitoring-integration.md: Alloy, Prometheus, Loki integration with Selendis
- 04-element-customization.md: Custom themes (7), desktop setup scripts, admin panel
- 05-room-policies.md: Message retention, room publication, auto-join policies

All guides include troubleshooting, configuration examples, and best practices.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 22:47:38 +02:00
Scrublord MacBad
e6ef29c1e9 Add deployment documentation structure & overview
Create docs/deployment-guides/ directory with comprehensive README covering:
- Deployment order for all 5 major features
- Architecture overview
- Critical values & configuration
- Links to detailed guides

Full documentation files:
- 01-turn-server-setup.md
- 02-authentik-identity-provider.md
- 03-monitoring-integration.md
- 04-element-customization.md
- 05-room-policies.md

To be added in follow-up commits.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 22:46:00 +02:00
Scrublord MacBad
857c3965ef Add devcontainer for cross-platform development
- Dockerfile with all required tools (kubectl, flux, helm, sops, age, etc.)
- devcontainer.json with VSCode config and extensions
- postCreateCommand.sh for setup verification
- Comprehensive README with setup instructions for macOS, Windows/WSL2, Linux
- Automatic mounts for kubeconfig, SSH keys, age encryption keys
- SOPS_AGE_KEY_FILE and KUBECONFIG pre-configured

Enables development on Windows, macOS, and Linux with consistent environment.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 22:27:52 +02:00
Scrublord MacBad
d37a65f4fa fix element web image version missing 2026-05-14 22:07:34 +02:00
Scrublord MacBad
e6abd0fb3f feat: reinstate roomlist fork after config map fix 2026-05-14 21:59:34 +02:00
Scrublord MacBad
d3362180ea fix: Complete JSON structure in element-values.yaml
The config.json was truncated and had unclosed brackets. This prevented
Helm from properly merging the ElementWeb configuration, so the custom themes
were never loaded into the cluster.

This fix:
- Closes the unclosed JSON brackets
- Validates the full JSON structure
- Removes duplicate/extra closing brackets
- Ensures all 6 custom themes are properly included

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 21:55:22 +02:00
Scrublord MacBad
5f50a60071 feat: Automate ConfigMap checksum updates via Git pre-commit hook
- Add pre-commit hook (scripts/hooks/pre-commit) that automatically calculates
  MD5 checksums of ConfigMaps (element-values.yaml, synapse-values.yaml)
- Update annotations in kustomization.yaml to trigger Flux CD HelmRelease syncs
- Add install script (scripts/install-hooks.sh) for easy hook setup
- Add comprehensive documentation (docs/ops-configmap-sync.md) explaining:
  * Why Flux doesn't auto-detect ConfigMap changes
  * How the checksum-based workaround works
  * How to install and use the hook
  * Troubleshooting and manual sync procedures
- Update README.md with post-clone hook installation step

This solves the issue where Flux CD doesn't automatically re-deploy when external
ConfigMaps are modified. Users no longer need manual checksum updates.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 21:43:01 +02:00
Scrublord MacBad
174e9721ed Revert "test: verify pre-commit hook updates checksums"
This reverts commit 5f14376bdbc24665be5a874ff8733a35dbeeb7e9.
2026-05-14 21:42:25 +02:00
Scrublord MacBad
5f14376bdb test: verify pre-commit hook updates checksums 2026-05-14 21:42:13 +02:00
Scrublord MacBad
81a30e21b9 Fix: HelmRelease reconciliation on ConfigMap changes
- Reduce HelmRelease interval from 1h to 5m for faster sync
- Add checksum annotation to trigger reconciliation when element-values.yaml changes
- This ensures Flux CD re-deploys the chart when themes/config updates are made

To update the checksum after editing element-values.yaml:
  md5sum apps/production/custom-configs/element-values.yaml
  # Update the value in apps/production/kustomization.yaml patches[0].patch

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-14 21:37:07 +02:00
f81fda12d4 Update apps/production/element-server-suite.yaml 2026-05-13 14:48:08 +00:00
fe0165a509 Update apps/production/element-server-suite.yaml
new docker image for elementWeb
2026-05-13 14:43:50 +00:00
Scrublord MacBad
dc17158fe2 fix themes 2026-05-11 10:48:16 +02:00
Scrublord MacBad
0c81de057f fix config url element web 2026-05-11 10:43:35 +02:00
aaa197fbb5 Feat: Lab roomslist v3 & new aXion Theme 2026-05-11 08:28:30 +00:00
33 changed files with 16144 additions and 15 deletions

BIN
.DS_Store vendored

Binary file not shown.

56
.devcontainer/Dockerfile Normal file
View File

@ -0,0 +1,56 @@
FROM debian:bookworm-slim
# Install base tools
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
wget \
git \
ca-certificates \
gnupg \
lsb-release \
apt-transport-https \
vim \
nano \
jq \
yq \
zsh \
sudo \
openssh-client \
&& rm -rf /var/lib/apt/lists/*
# Install kubectl
RUN curl -fsSLo /usr/share/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg && \
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list && \
apt-get update && apt-get install -y kubectl && \
rm -rf /var/lib/apt/lists/*
# Install Helm
RUN curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
# Install Flux CLI
RUN curl -s https://fluxcd.io/install.sh | bash
# Install sops
RUN SOPS_VERSION=$(curl -s https://api.github.com/repos/getsops/sops/releases/latest | grep tag_name | cut -d '"' -f 4) && \
curl -sL -o /usr/local/bin/sops https://github.com/getsops/sops/releases/download/${SOPS_VERSION}/sops-${SOPS_VERSION}.linux.amd64 && \
chmod +x /usr/local/bin/sops
# Install age
RUN apt-get update && apt-get install -y age && \
rm -rf /var/lib/apt/lists/*
# Install Docker CLI (for interacting with Docker daemon)
RUN curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && apt-get install -y docker-ce-cli && \
rm -rf /var/lib/apt/lists/*
# Create a non-root user 'vscode' for development
RUN useradd -m -s /bin/bash -G docker vscode && \
echo "vscode ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/vscode
# Install oh-my-zsh for better shell experience
RUN su - vscode -c "sh -c '$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)' '' --unattended"
USER vscode
WORKDIR /workspace

203
.devcontainer/README.md Normal file
View File

@ -0,0 +1,203 @@
# 🐳 DevContainer für ESS Community GitOps
Dieses DevContainer-Setup ermöglicht dir, auf **macOS, Windows und Linux** einheitlich zu entwickeln.
## 🚀 Schnelstart
### VSCode mit Remote Containers Extension
1. **VSCode Extension installieren:**
- Öffne VSCode → Extensions → Suche nach `Dev Containers` (Microsoft)
- Installiere sie
2. **GitOps Verzeichnis öffnen:**
```bash
cd "april mit Ansible/prod/gitops"
code .
```
3. **DevContainer starten:**
- Klick auf `><` Symbol unten links in VSCode
- Wähle `Reopen in Container`
- Warte, bis das Image gebaut wurde (~3-5 Min beim ersten Mal)
### Alternative: Docker + CLI
```bash
docker build -t ess-gitops .devcontainer
docker run -it --rm \
-v ~/.kube:/home/vscode/.kube \
-v ~/.ssh:/home/vscode/.ssh \
-v ~/.age:/home/vscode/.age \
-v /var/run/docker.sock:/var/run/docker.sock \
ess-gitops
```
## 📦 Enthaltene Tools
- **kubectl** - Kubernetes CLI
- **flux** - FluxCD GitOps Controller CLI
- **helm** - Kubernetes Package Manager
- **sops** - Secret Operations (Verschlüsselung)
- **age** - Modern File Encryption
- **docker** - Container CLI (über Host-Socket)
- **git** - Versionskontrolle
- **jq/yq** - JSON/YAML Processing
- **zsh + oh-my-zsh** - Shell mit Plugins
## 🔐 Wichtige Verzeichnis-Binds
Der Container mountet automatisch:
| Host | Container | Zweck |
|------|-----------|-------|
| `~/.kube` | `/home/vscode/.kube` | Kubernetes Config |
| `~/.ssh` | `/home/vscode/.ssh` | SSH Keys |
| `~/.age` | `/home/vscode/.age` | Age Encryption Keys |
| `/var/run/docker.sock` | `/var/run/docker.sock` | Docker Daemon (für `docker` Befehle) |
## ⚙️ Kubeconfig Einrichten
1. **Host-Machine (z.B. macOS):**
```bash
# Stelle sicher, dass ~/.kube/config existiert und den richtigen Cluster enthält
kubectl get nodes
```
2. **Im Container:**
```bash
kubectl get nodes # Sollte jetzt auch dein Cluster zeigen
kubectl config current-context
```
## 🔐 SOPS + Age Setup
Damit du Secrets bearbeiten kannst, brauchst du den privaten `age`-Key. Dieser ist in `.sops.yaml` konfiguriert.
### Schritt 1: Age-Key bereitstellen
```bash
# Host-Machine: Key-Datei erstellen
mkdir -p ~/.age
# Füge deinen privaten Key ein (Format: "age-secret-key-...")
echo "age-secret-key-xxx..." > ~/.age/keys.txt
chmod 600 ~/.age/keys.txt
```
### Schritt 2: Im Container konfigurieren
Der Container mounted `~/.age` automatisch. Setze die Umgebungsvariable:
```bash
# Im Container-Terminal (SOPS_AGE_KEY_FILE ist bereits automatisch gesetzt!)
# Jetzt kannst du Secrets bearbeiten (wird transparent ver-/entschlüsselt):
sops apps/production/custom-configs/mas-secrets.sops.yaml
```
### Schritt 3: VSCode Integration (optional)
Um die Umgebungsvariable beim Start zu setzen, nutze die `.devcontainer/devcontainer.json`:
```json
"remoteEnv": {
"KUBECONFIG": "/home/vscode/.kube/config",
"SOPS_AGE_KEY_FILE": "/home/vscode/.age/keys.txt"
}
```
### Wie es funktioniert
- `.sops.yaml` definiert, dass Secrets mit `age` verschlüsselt werden
- Beim Öffnen mit `sops <datei>` wird die Datei entschlüsselt → du editierst den plaintext in deinem Editor
- Beim Speichern wird alles wieder automatisch verschlüsselt
- **Wichtig:** Niemals den plaintext-Buffer commiten!
## 📝 Nach Container-Start: Git Hooks Installieren
Wichtig für die ConfigMap Auto-Sync (verhindert Merge-Konflikte):
```bash
./scripts/install-hooks.sh
```
Mehr Details: `docs/ops-configmap-sync.md`
## 📝 Nützliche Befehle
```bash
# Status des Deployments
kubectl get pods -n matrix
flux get helmreleases -A
# Secrets bearbeiten (mit verschlüsselung)
sops apps/production/custom-configs/mas-secrets.sops.yaml
# FluxCD Sync erzwingen
flux reconcile kustomization production-apps --with-source
# Zertifikate debuggen
kubectl get certificate -n matrix
kubectl describe certificate matrix-ingress -n matrix
# HelmRelease Status prüfen
flux describe helmrelease matrix-stack -n matrix
```
## 🛠️ Anpassungen für Windows/WSL2
Falls du Windows nutzt:
1. **Docker Desktop installieren** (mit WSL2 Backend)
2. **VSCode mit WSL Extension öffnen**
3. **Im WSL Terminal:**
```bash
cd /mnt/c/path/to/projekt
code .
```
4. Dann `Dev Containers: Reopen in Container`
Das funktioniert seamless, weil Docker Desktop unter WSL2 läuft.
## 🔧 Troubleshooting
### Problem: `SOPS_AGE_KEY_FILE not found`
**Lösung:** Key muss in `~/.age/keys.txt` auf der Host-Machine sein:
```bash
# Host
mkdir -p ~/.age
echo "your-age-private-key" > ~/.age/keys.txt
```
Der Container mountet `~/.age` automatisch → sollte dann funktionieren.
### Problem: `kubectl: connection refused`
**Lösung:** `~/.kube/config` muss auf Host vorhanden sein:
```bash
# Host
kubectl get nodes # Test, ob Zugriff existiert
# Dann Container neustarten
```
### Problem: `HelmChart is not ready: stat ... no such file or directory`
Siehe `README.md`**Issue 1**. Kontrolliere:
- `HelmRepository` nutzt `type: oci`
- URL ist `oci://ghcr.io/element-hq/ess-helm`
### Problem: `values don't meet the specifications of the schema`
Siehe `README.md`**Issue 2**. Häufige Fehler:
- `tls:` darf nicht im `ingress:` Block sein
- `serverName` muss auf Root-Ebene der `values` stehen
- Komponenten-Namen: `camelCase` (z.B. `elementWeb`, `matrixAuthenticationService`)
### Problem: Let's Encrypt `403 Order's status is processing`
Siehe `README.md`**Issue 3**. Kurz:
- `wellKnownDelegation: enabled: false` setzen
- Oder `.well-known/matrix/server` manuell auf `elementWeb` weiterleiten
## 📚 Weitere Ressourcen
- [Dev Containers Docs](https://containers.dev)
- [FluxCD Dokumentation](https://fluxcd.io)
- [SOPS Anleitung](https://github.com/getsops/sops)
- **Projekt-README:** `README.md` (Architektur, Issues, Best Practices)
- **Setup-Docs:** `docs/setup/`
- **Install-Guide:** `docs/install.md`

View File

@ -0,0 +1,65 @@
{
"name": "ESS Community GitOps",
"build": {
"dockerfile": "Dockerfile",
"context": "."
},
"mounts": [
"source=${localEnv:HOME}/.kube,target=/home/vscode/.kube,type=bind,consistency=cached",
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached",
"source=${localEnv:HOME}/.age,target=/home/vscode/.age,type=bind,consistency=cached",
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"remoteUser": "vscode",
"features": {
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"remoteEnv": {
"KUBECONFIG": "/home/vscode/.kube/config",
"SOPS_AGE_KEY_FILE": "/home/vscode/.age/keys.txt"
},
"customizations": {
"vscode": {
"extensions": [
"ms-kubernetes-tools.vscode-kubernetes-tools",
"redhat.vscode-yaml",
"redhat.vscode-commons",
"monokai.theme-monokai-pro-vscode",
"eamodio.gitlens",
"gruntfuggly.todo-tree",
"ms-vscode.makefile-tools",
"GitHub.copilot"
],
"settings": {
"[yaml]": {
"editor.defaultFormatter": "redhat.vscode-yaml",
"editor.formatOnSave": true,
"editor.tabSize": 2
},
"yaml.schemas": {
"https://json.schemastore.org/kustomization.json": "**/kustomization.yaml",
"https://json.schemastore.org/helmrelease.json": "**/*helmrelease*.yaml"
},
"editor.theme": "Monokai Pro",
"todo-tree.general.showActivityBarBadge": true,
"todo-tree.general.tags": [
"TODO",
"FIXME",
"BUG",
"HACK",
"NOTE",
"XXX",
"DONE"
],
"todo-tree.tree.showScanModeButton": true,
"todo-tree.filtering.includeGlobs": [
"**/docs/TASKS.md",
"**/docs/deployment-guides/*.md"
]
}
}
},
"postCreateCommand": "bash .devcontainer/postCreateCommand.sh",
"forwardPorts": []
}

View File

@ -0,0 +1,35 @@
#!/bin/bash
set -e
echo "🚀 Setting up ESS Community GitOps devcontainer..."
# Verify all required tools are installed
echo "✅ Verifying installed tools..."
commands=("kubectl" "flux" "helm" "sops" "age" "git" "docker")
for cmd in "${commands[@]}"; do
if command -v $cmd &> /dev/null; then
version=$($cmd version 2>/dev/null | head -1 || echo "installed")
echo "$cmd: $version"
else
echo "$cmd: NOT FOUND"
exit 1
fi
done
# Create necessary directories
echo "📁 Creating home directories..."
mkdir -p ~/.kube ~/.ssh ~/.age
# Print useful information
echo ""
echo "📚 Useful commands:"
echo " - kubectl get pods -n matrix (check pod status)"
echo " - flux get helmreleases -A (check helm releases)"
echo " - sops apps/production/custom-configs/mas-secrets.sops.yaml (edit secrets)"
echo ""
echo "🔗 For kubeconfig setup:"
echo " - Copy your ~/.kube/config to access the cluster"
echo " - Run: kubectl get nodes"
echo ""
echo "✨ Devcontainer setup complete!"

View File

@ -0,0 +1,50 @@
name: Auto-Deploy on Push
on:
push:
branches:
- main
paths:
- 'apps/**'
- 'clusters/**'
- '.gitea/workflows/**'
jobs:
verify-and-notify:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check YAML Syntax
run: |
echo "🔍 Validating YAML files..."
find apps clusters -name "*.yaml" -type f | while read file; do
if ! grep -q "^apiVersion:" "$file"; then
echo "⚠️ Warning: $file may not be a valid K8s manifest"
fi
done
echo "✅ YAML validation passed"
- name: Check for SOPS Encryption
run: |
echo "🔐 Checking SOPS status..."
for file in $(git diff --name-only origin/main...HEAD -- '**/secret*.yaml' '**/credentials*.yaml'); do
if grep -q "ENC\[" "$file"; then
echo "✅ $file is encrypted"
else
echo "⚠️ WARNING: $file may not be encrypted!"
fi
done
- name: Create Deployment Notification
run: |
echo "📤 Flux will reconcile changes within 1 minute"
echo "🔗 Monitor in Gitea: Projects → Releases (check tags)"
- name: List Changed Files
run: |
echo "📋 Files changed in this push:"
git diff --name-only origin/main...HEAD

View File

@ -0,0 +1,32 @@
name: Create Release on Milestone Tag
on:
push:
tags:
- 'm*-*-complete'
jobs:
create-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Extract Milestone Info
id: milestone
run: |
TAG="${GITHUB_REF#refs/tags/}"
TITLE=$(git tag -l "$TAG" -n1 | awk '{print substr($0, index($0, $2))}')
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "title=$TITLE" >> $GITHUB_OUTPUT
echo "🏷️ Milestone: $TAG"
echo "📝 Title: $TITLE"
- name: Create Release
run: |
echo "📦 Creating release for milestone: ${{ steps.milestone.outputs.tag }}"
echo "${{ steps.milestone.outputs.title }}" > /tmp/release-notes.txt
echo "Created: $(date)" >> /tmp/release-notes.txt
cat /tmp/release-notes.txt

View File

@ -53,6 +53,12 @@ winget install Kubernetes.kubectl FluxCD.Flux Mozilla.sops age-encryption.age He
1. **Kubeconfig:** Stelle sicher, dass die Datei `~/.kube/config` mit den Zugangsdaten zu deinem K3s-Cluster gefüllt ist. Test: `kubectl get nodes`. 1. **Kubeconfig:** Stelle sicher, dass die Datei `~/.kube/config` mit den Zugangsdaten zu deinem K3s-Cluster gefüllt ist. Test: `kubectl get nodes`.
2. **SOPS Key:** Du benötigst den privaten `age`-Key (oder GPG-Key), der in der `.sops.yaml` des Repositories hinterlegt ist, um Secrets bearbeiten zu können. 2. **SOPS Key:** Du benötigst den privaten `age`-Key (oder GPG-Key), der in der `.sops.yaml` des Repositories hinterlegt ist, um Secrets bearbeiten zu können.
3. **Git Hooks installieren:** Nach dem Klonen dieses Repositories müssen Git Hooks installiert werden, um ConfigMap-Änderungen automatisch zu tracken:
```bash
cd prod/gitops
./scripts/install-hooks.sh
```
Siehe [📖 GitOps ConfigMap Auto-Sync](docs/ops-configmap-sync.md) für Details.
----- -----

View File

@ -8,7 +8,7 @@ spec:
chart: chart:
spec: spec:
chart: authentik chart: authentik
version: "2026.2.2" version: "2026.2.3"
sourceRef: sourceRef:
kind: HelmRepository kind: HelmRepository
name: goauthentik name: goauthentik

View File

@ -0,0 +1,186 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: ess-element-custom
namespace: matrix
data:
values.yaml: |
elementWeb:
additional:
config.json: |
{
"brand": "aXion1337.Chat",
"default_theme": "aXion1337 Dark",
"show_labs_settings": true,
"features": {
"feature_qr_code_login": true,
"feature_new_room_list": true
},
"element_call": {
"use_exclusively": true
},
"setting_defaults": {
"custom_themes": [
{
"name": "aXion1337 Dark true",
"is_dark": true,
"colors": {
"accent-color": "#ffaf0f",
"primary-color": "#ffaf0f",
"secondary-color": "#ffaf0f"
}
},
{
"name": "Deep Purple",
"is_dark": true,
"colors": {
"accent-color": "#6503b3",
"primary-color": "#368bd6",
"warning-color": "#b30356",
"sidebar-color": "#15171B",
"roomlist-background-color": "#22262E",
"roomlist-text-color": "#A1B2D1",
"roomlist-text-secondary-color": "#EDF3FF",
"roomlist-highlights-color": "#343A46",
"roomlist-separator-color": "#a1b2d1",
"timeline-background-color": "#181b21",
"timeline-text-color": "#EDF3FF",
"timeline-text-secondary-color": "#A1B2D1",
"timeline-highlights-color": "#22262E"
}
},
{
"name": "Discord Dark",
"is_dark": true,
"colors": {
"accent-color": "#747ff4",
"accent": "#747ff4",
"primary-color": "#00aff4",
"warning-color": "#faa81ad9",
"alert": "#faa81ad9",
"sidebar-color": "#202225",
"roomlist-background-color": "#2f3136",
"roomlist-text-color": "#dcddde",
"roomlist-text-secondary-color": "#8e9297",
"roomlist-highlights-color": "#4f545c52",
"roomlist-separator-color": "#40444b",
"timeline-background-color": "#36393f",
"timeline-text-color": "#dcddde",
"secondary-content": "#dcddde",
"tertiary-content": "#dcddde",
"timeline-text-secondary-color": "#b9bbbe",
"timeline-highlights-color": "#04040512",
"reaction-row-button-selected-bg-color": "#4752c4",
"menu-selected-color": "#4752c4",
"focus-bg-color": "#4752c4",
"room-highlight-color": "#4752c4",
"other-user-pill-bg-color": "#4752c4",
"togglesw-off-color": "#72767d"
},
"compound": {
"--cpd-color-theme-bg": "#0019ff",
"--cpd-color-bg-canvas-default": "#2f3136",
"--cpd-color-bg-subtle-secondary": "#2f3136",
"--cpd-color-bg-subtle-primary": "#4f545c52",
"--cpd-color-bg-action-primary-rest": "#dcddde",
"--cpd-color-bg-action-secondary-rest": "#2f3136",
"--cpd-color-bg-critical-primary": "#fd3f3c",
"--cpd-color-bg-critical-subtle": "#745862",
"--cpd-color-bg-critical-hovered": "#fd3f3c",
"--cpd-color-bg-accent-rest": "#4cb387",
"--cpd-color-text-primary": "#dcddde",
"--cpd-color-text-secondary": "#b9bbbe",
"--cpd-color-text-action-accent": "#b9bbbe",
"--cpd-color-text-critical-primary": "#fd3f3c",
"--cpd-color-text-success-primary": "#4cb387",
"--cpd-color-icon-primary": "#dcddde",
"--cpd-color-icon-secondary": "#dcddde",
"--cpd-color-icon-tertiary": "#a7a0a7",
"--cpd-color-icon-accent-tertiary": "#4cb387",
"--cpd-color-border-interactive-primary": "#5d6064",
"--cpd-color-border-interactive-secondary": "#5d6064",
"--cpd-color-border-critical-primary": "#fd3f3c",
"--cpd-color-border-success-subtle": "#4cb387"
}
},
{
"name": "Electric Blue",
"is_dark": false,
"colors": {
"accent-color": "#3596fc",
"primary-color": "#368bd6",
"warning-color": "#ff4b55",
"sidebar-color": "#27303a",
"roomlist-background-color": "#f3f8fd",
"roomlist-text-color": "#2e2f32",
"roomlist-text-secondary-color": "#61708b",
"roomlist-highlights-color": "#ffffff",
"roomlist-separator-color": "#e3e8f0",
"timeline-background-color": "#ffffff",
"timeline-text-color": "#2e2f32",
"timeline-text-secondary-color": "#61708b",
"timeline-highlights-color": "#f3f8fd",
"username-colors": ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#4b0082", "#9400d3", "#ff1493"],
"avatar-background-colors": ["#cc0000", "#cc6600", "#cccc00", "#00cc00", "#0000cc", "#3b0066", "#7a00b3", "#cc1077"]
},
"compound": {
"--cpd-color-icon-accent-tertiary": "var(--cpd-color-blue-800)",
"--cpd-color-text-action-accent": "var(--cpd-color-blue-900)"
}
},
{
"name": "Everforest dark hard",
"is_dark": true,
"colors": {
"accent-color": "#a7c080",
"primary-color": "#a7c080",
"warning-color": "#e67e80",
"sidebar-color": "#323d43",
"roomlist-background-color": "#2f383e",
"roomlist-text-color": "#d3c6aa",
"roomlist-text-secondary-color": "#d3c6aa",
"roomlist-highlights-color": "#4b565c",
"roomlist-separator-color": "#4b565c",
"timeline-background-color": "#2b3339",
"timeline-text-color": "#d3c6aa",
"secondary-content": "#d3c6aa",
"tertiary-content": "#d3c6aa",
"timeline-text-secondary-color": "#a7c080",
"timeline-highlights-color": "#4b565c",
"reaction-row-button-selected-bg-color": "#4b565c"
}
},
{
"name": "aXion1337 Dark", #Gruvbox Dark
"is_dark": true,
"colors": {
"accent-color": "#bd93f9",
"primary-color": "#fe8019",
"warning-color": "#fb4934",
"sidebar-color": "#282828",
"roomlist-background-color": "#1d2021",
"roomlist-text-color": "#a89984",
"roomlist-text-secondary-color": "#00ff00",
"roomlist-highlights-color": "#00000030",
"roomlist-separator-color": "#4d4d4d90",
"timeline-background-color": "#282828",
"timeline-text-color": "#ebdbb2",
"secondary-content": "#928374",
"tertiary-content": "#928374",
"quinary-content": "#504945",
"timeline-text-secondary-color": "#a89984",
"timeline-highlights-color": "#00000030",
"reaction-row-button-selected-bg-color": "#689d6a",
"menu-selected-color": "#504945",
"icon-button-color": "#928374",
"accent": "#689d6a",
"alert": "#cc241d",
"username-colors": [
"#cc241d",
"#98971a",
"#d79921",
"#458588",
"#b16286",
"#689d6a",
"#a89984",
"#d65d0e"

View File

@ -9,13 +9,12 @@ data:
additional: additional:
config.json: | config.json: |
{ {
"configUrl": "https://axion1337.chat/config.json",
"brand": "aXion1337.Chat", "brand": "aXion1337.Chat",
"default_theme": "aXion1337 Dark", "default_theme": "aXion1337 Dark",
"show_labs_settings": true, "show_labs_settings": true,
"features": { "features": {
"feature_qr_code_login": true, "feature_qr_code_login": true,
"feature_new_room_list": false "feature_new_room_list": true
}, },
"element_call": { "element_call": {
"use_exclusively": true "use_exclusively": true
@ -23,7 +22,7 @@ data:
"setting_defaults": { "setting_defaults": {
"custom_themes": [ "custom_themes": [
{ {
"name": "aXion1337 Dark", "name": "aXion1337 Dark true",
"is_dark": true, "is_dark": true,
"colors": { "colors": {
"accent-color": "#ffaf0f", "accent-color": "#ffaf0f",
@ -152,7 +151,7 @@ data:
} }
}, },
{ {
"name": "Gruvbox Dark", "name": "aXion1337 Dark",
"is_dark": true, "is_dark": true,
"colors": { "colors": {
"accent-color": "#bd93f9", "accent-color": "#bd93f9",
@ -185,3 +184,9 @@ data:
"#689d6a", "#689d6a",
"#a89984", "#a89984",
"#d65d0e" "#d65d0e"
]
}
}
]
}
}

View File

@ -4,19 +4,19 @@ metadata:
name: ess-mas-values-secret name: ess-mas-values-secret
namespace: matrix namespace: matrix
stringData: stringData:
values.yaml: ENC[AES256_GCM,data:tPLcPvoTa2Qs49JSDW6CqiYMIrjsoKrExCl+hOm5R3/o+O9Lf4UqyMC4QY6T303m7GMU3tIDGX4js8NS7Fdcs9YOKoInUKlYqCYzNio+BRsl1DGtzEtcUWhXZQC58RHbI8jiLhXsI1x2vSYsMj5MkymVe9Kmjw91vxEivzn8dC2zae4rFGk/LyLoI5BHzSCT6csUGtGZe01rN/DsGpHxkYNbzinBK3uFM43IgcjCrkBK8jzsxUYA4JWvzBJ1tB5TyyTgZBBe2Baxj7vHf9SysGwbRl4TBzY5at8cPKKnmh7qaHQO3FHCCqfHi1ymt1vNRtPPGRGAKWqC8AroXTPUUe4oSQ7wakhuQwPAhQJn0FHjIJNbp2J7M9K3nWnf0eugDPcp1pQ7Iv0tUQ/2hd5Q8Xmiv7qCCBuhOGnAokUwkRnZu124PEhPwDa/PSA6bB/5dCwj8rzZOyEXJsz12cRtSPK8Kqff+bp2MSFEA8iETm40k/BxybyC2odWEhkPDlRl+YDe8rJxkGGLwP5PEgiQp5RK4ZftQ6Cgc5loUHDAar10tMsqg++iQeyeb/o=,iv:PSo85CoDdWajU3j4vHsaNCHI6UbMbII01nskXNyotVU=,tag:OBVkKsBnCv9bloORukDgcQ==,type:str] values.yaml: ENC[AES256_GCM,data:B9nRZWCUnWxWhnlOTzSdOZrO+aiKwotKZhjYTwTBlgy9zVGoAn81yy6s2QJySeAI/rXcKamQ/P3fewDsLDzX8zxbvHS1GZ/F1fPx7H4tan9/1tu7XvNx52DWMCO8UtmpwNb1gAaa0kLbs+u1dTKA3Bk9b1gWsmP5OGo+C43knmhF3YvDOwv5wO96iaAzMwpjpxB78AkOvkshLEbP/o+z/DKsLxtoeQ0tPzkXjQj8d/2Jaj+3Ve8uqSNbnAEoL6gTDr+qvQs2JU/jvilK/fKgkR4hF54opthEMzKV7pbUYia2a+5yOmmQaBXQ5cUqi7wrTVyle/GyXHHOLAU37sGYhKyIGjgMu8rGTHMQgm3c5rGt4wLps48+LN4/S74tbTgyBf8V6hTGfNXIpMDkjXpPujZLzCKSx8V+7NlQDcs8FGobOLdmmcBzj3WGVMJLt/IA1/hv4xj4sP7CeQqG0UpWhJLXxY+ghCGdGJ7dA2wme+hreb1ywrhgVVnGH+plSG9BmTIye4sgCJwnZ9ER6T42ptsw70GaqfFazsgebeKEM+grJLfx+f4YyPexDaGZbrrZ5nxvOtvVz6d8Cx4zuP7jt+7RwzZiXPlYjsgvwwypuafIh/Uk0ULeFiSRLKLEGItRcOTdlVUbOOP9bW1Is42PzsnDnx0Mc0v4LzQCQTYJL3amfgOeGVJ1I8zS6okM8sZE3F0jzGvaFTNbeMiIkealUhjQrhF/5MweiNUIOUzAp/DLFT2mBg9g24imLtDCglEV0WwVQACd9GzQLNRnjNmaId7ISeYfUH/gORqyUJlICaRFB1xH+MMzy09tP2zuYcY+sIFJotYF29J0wC8oQS2KsKQiHEPVTLYTzDsB0RU4pGD6471rgIByXQrlmawo9HtjZxfZuzw7+AEa9uOBohbNkOwDUQGoLqgssAefAz4H/LC0NmBONR7iVzYcWv3RgDhsiafkUq6PgyXYEleB7Euk1wxX9mxUEqfuVMbeDceog2Q41vWBmFkFnSUYXHbN/Ff8DfWe+zjcSKDzjSchU54iYTbuuKnDo+G/jEk/FNGcp/xOh0/JyYWcqO5DozBPlIJ5QxgWkQTWC8oSM1QmTxiSj+FYDZFdyOXSXsqF8a9BJaEh5nACUbqwpx+UnRnJpcIcOlYasDwThNSNZIkpqqf2e7vsZHMTakkTbHOcWB7IiYWOCQLdzStQn3URWIobKn3T+mbbDerWzF2a9UEBbCwlTbA/OoyeWW4j1uPo29ek6F6Lb7JdxibNO6U5JIZkYP92Ci8W7skFAn7rEe203qnlvzoxhKxE+dA5rM+Tr4FWz9qAa/u3EhPxVvPK+0Wpb6HAUbFGbm+MSD7uqlcnvVxZfU2dSbpb/J56Bq8vzmJKcaStxoE4lDG+uwa2I/o0f1BMdwWvnmKEAJa593NYS9lw4s2dR3IwFkeE8hp3Q6yxaFk5v9m5/ivXOwiaOJ238HqDBJrfCQidIe+RaqydPxqqOj7WV1YZFU6DxZJ30LcyH45MJQqC5TGz2W1Unwljl3arh/hQRb1G3eGNw4kO86CipioKTeDBPpoKfgNFbz8qiNPSCRXPtJve+OOptDojLJ5iR+HO6olmSu+OGww7+BwTvBraW/xIAGq7y/gzZ8aMgsqIMyHJZiuC9+uQwquKiFEZ5pD5vAe0R9ROdFHgWsdKdEXwJtaCqBAfqWrZkrgoeWFsPYFwT3BhusQfMyWKv6SSOmWk2bx4FZ74+HeZcTsJWVcCmF4dbqfDvM5sz3b4Mek0wjUZGKtVyfFQ1VoZm6/G6UgCEt25A37AO11H/sW90Bs2nSpbOJFbgeBsNkXMptWrCyyHehof+JWeGuTFTg3etsaBgW4b1rJRzbJUQHJKVXjIOPZIQNd0WS7y+IDheDovQobfjSWn6TRVnXvEnzaD5WxY54EqOivAyv1U7/r7KMzo26Bp9s7ZQX/UeNmTn1dgkZoWNpTV8LkcrbRgIpkSNG9Pj+6GOtdUIxobtLeZ9h5Oso/TSKoDaHbkfoSVhW3FgQ7aJHHvx0j2qp/hVQfvABCPILW2DJvtNyIOU5zgV7yHJF/Dw7PpJfw636WxQHaTehbOav1ImE0FX0VF6NmkhuEpPEVHr0lejGse+0XkVzMuxoi/bE4h7WFIfbiqdlw=,iv:KnhgvxrFd+6BEBuBUKtQgKEfx81G9uJ+CY4Wrm43Pjw=,tag:1OQs0MQ1Gvf1LwXLaGwyjQ==,type:str]
sops: sops:
age: age:
- recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh - recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWOVd0enFxNE85WnN1eTRD YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2RHgzUE5QVVVCdkJ5aWNj
MjdVSE90NUd6MWFBbCtzZFRTK0NQYllUTGdVCk9aWGNGLzNvLzU3S09la2RiY1hv VmFHTUs2TXpXYzE2VmJnMHFNek1RT0FnUVVFCmJqRHUzY2F3WWt1L1FLbVpDWWFO
bXdNZjFxaVM5aUF3MTA1bWx4WU1TR0EKLS0tIFp6RmdCVlE5Zk53RjF3MnZveHo4 QzN1akRQdjBBVENIWHhGOGgrZFdqZGsKLS0tIEVRMGRrS05zS1ErdFZZUmZ4TUVv
eUpzQTBCRjM0a2FmZzNkdmFKWUVPODQKqpA3drI6JV67Y3P/l8Ql5xwtohVi9D3P U1dXMWltRlY1cGx2TFI4YjRreVBPQVkK9UFiAiSANa7HekQxufsFSkMQoL18kGmi
6iAcFoqrVZMSKkkiHDvAcdUexIO/BKddjC5N608MLUz7tcxyWfMqeg== cP0jf27NGFpAjC8AmuMWgMydYDGXyRgFRU5JDqGCYAsgZsrGgjIWkA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2026-04-23T13:17:31Z" lastmodified: "2026-05-15T09:05:44Z"
mac: ENC[AES256_GCM,data:V4l8oScpWwC95gg9UQpaV0oKn292Y6WoRZdWlqF3I8BWCGV4LVvLE7KxC9lqHdt/Mcgb6yuaDSv3ZMERl81QOMSMcPVfk/F0LoabP/dFiz1ogxOezHOfJJ2mTu+4yAOkK73RQY68ui5UGAV5FFu3tecE0AAouSt0YrOTBALtLpY=,iv:WBFy/v6gRBil30Oqdew3JW5XVz5wmaO0Uj7J+MfSrss=,tag:CvTEdnbs4dJ0qlnefvXIag==,type:str] mac: ENC[AES256_GCM,data:gFPsb3LCjoPglcPEmLEe8hFQSsrcsZCMtVCf7L8jNLEgsL5XUIEF/BEoT7I+wPisRclAtq2qOkBd3TqmxQWAaPbRQ0+RDHU49XD5rWavDv7/CA1QUCLL/RNTbuURyS9iri/F4xneeYLwKJxJCgmMEiaqRPaAnHioxFtPreEiREg=,iv:FgWNZJUOydGY/m0SlZLWtWefIstMG7ccju6h8BLuVho=,tag:MMXoxQIA8ZNl5qBJjuzdpw==,type:str]
encrypted_regex: ^(data|stringData)$ encrypted_regex: ^(data|stringData)$
version: 3.12.2 version: 3.12.2

View File

@ -4,7 +4,7 @@ metadata:
name: matrix-stack name: matrix-stack
namespace: matrix namespace: matrix
spec: spec:
interval: 1h interval: 5m
chart: chart:
spec: spec:
chart: matrix-stack chart: matrix-stack

View File

@ -1,5 +1,18 @@
apiVersion: kustomize.config.k8s.io/v1beta1 apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization kind: Kustomization
# Patch: Fügt einen Checksum der element-values.yaml zur HelmRelease hinzu
# Damit wird Flux die HelmRelease neu-synced wenn sich die ConfigMap ändert
patches:
- target:
kind: HelmRelease
name: matrix-stack
namespace: matrix
patch: |-
- op: add
path: /metadata/annotations/element-config-checksum
value: "401f8a87d0ef5d91d2e5032d4aede42c"
resources: resources:
- matrix-postgres-auth.yaml - matrix-postgres-auth.yaml
- cert-issuer.yaml - cert-issuer.yaml

520
docs/TASKS.md Normal file
View File

@ -0,0 +1,520 @@
# aXion1337.Chat Task List & Meilensteine
**Last Updated**: 2026-05-15
**Statusübersicht**: [✅ 9 Abgeschlossen] [🔄 0 In Progress] [📋 11+ Pending] [🔒 10 Security]
---
## 📊 Status Summary (Quick View)
| Kategorie | Count | Status | Details |
|-----------|-------|--------|---------|
| **Completed** | 9 | ✅ Done | K3S, Flux, ESS, Themes, Desktop, Monitoring, TURN, Authentik, Firewall, SSH |
| **In Progress** | 0 | 🔄 — | — |
| **Backlog** | 11+ | 📋 Pending | DB Backups, E2E Test, Element Call Fork, PostgreSQL Migration, NetworkPolicies |
| **Security Tasks** | 5 | 🔒 Pending | auditd, Kernel hardening, CrowdSec, Falco, WAF |
### Priority Distribution
| Priority | Count | Timeline |
|----------|-------|----------|
| 🔴 **CRITICAL** | 3 | This week |
| 🟠 **HIGH** | 4 | 12 weeks |
| 🟡 **MEDIUM** | 8 | ~1 month |
| 🟢 **LOW** | 4+ | Nice-to-have |
---
## 🎯 Next Steps (Priorisiert)
### 🔴 **THIS WEEK CRITICAL**
1. ✅ **Authentik Stage 2 abschließen**
- ✅ Manual: OIDC Provider + Application in Authentik UI erstellt
- ✅ Code: `upstream_oauth2_config` in `mas-secret.yaml` eingefügt
- ✅ Code: `passwords: enabled: false` aktiviert
- ✅ Commit: `cdfbf7d` - Enable Authentik OIDC integration in MAS
- ✅ Verified: Login mit Authentik funktioniert (2026-05-15)
- **Status**: COMPLETE
2. ✅ **Hetzner Cloud Firewall Optimierte Konfiguration**
- ✅ Ingress: 80/443 + TURN/STUN + RTC Services
- ✅ SSH: Spezifische IPs (port 2248, nicht 22)
- ✅ Default-Deny für nicht-definierte Traffic
- **Status**: COMPLETE (optimiert über Plan)
3. ✅ **SSH Hardening**
- ✅ PasswordAuthentication: no (key-only)
- ✅ PermitRootLogin: no (root disabled)
- ✅ MaxAuthTries: 3 (verified 2026-05-15)
- **Status**: COMPLETE
4. **Database Backup Strategy Decision & First Backup**
- ⏳ Decision: CloudNativePG (on K3S) or Hetzner Postgres (managed)?
- ⏳ Setup: Daily automated backups
- ⏳ Setup: Off-site storage (S3 / Storage Box)
- ⏳ Setup: Monthly verified restores
- Est. Time: 23 days
- Priority: CRITICAL (disaster recovery)
- **Status**: NEXT
### 🟠 **NEXT 12 WEEKS HIGH**
1. **Authentik End-to-End Test**
- Test: Login flow Element → MAS → Authentik → Matrix User
- Test: Password reset
- Create: Test invite links
- Est. Time: 2 hours
2. **Element Call Fork**
- Fork: element-hq/element-call
- Feature: Video/audio constraints parameters
- Integration: Synapse well-known config
- Est. Time: 23 days
3. **External PostgreSQL Migration**
- Decision: CloudNativePG vs. Hetzner Postgres
- Setup: HA + Replication
- Migration: Move data from ESS embedded Postgres
- Testing: Verify all services work
- Est. Time: 12 days
4. **NetworkPolicies Deployment**
- Create: Default-Deny for `matrix` namespace
- Create: Allow rules (Synapse↔Postgres, MAS↔Postgres, Ingress→Web, etc.)
- Test: Ensure no service breakage
- Est. Time: 1 day
---
## ✅ Abgeschlossene Aufgaben (Chronologisch)
### Phase 1: Basis-Setup
- [x] **K3S Cluster aufsetzen** Single-Node auf Hetzner Cloud (49.13.132.245)
- Commit: `initial-setup` (vor Projekt)
- Status: ✅ Läuft
- [x] **Flux CD Installation**
- SOPS + age Encryption
- GitOps Repository konfigurieren
- Commit: `setup-flux` (vor Projekt)
- Status: ✅ Läuft
- [x] **Element Server Suite v26.4.0 Deployment**
- Synapse Homeserver (`matrix.axion1337.chat`)
- Matrix Authentication Service (`account.axion1337.chat`)
- Element Web (`axion1337.chat`)
- Element Admin (`admin.axion1337.chat`)
- MatrixRTC/Element Call (`mrtc.axion1337.chat`)
- Commit: `deploy-ess-matrix-stack`
- Status: ✅ Running
### Phase 2: Core Features
- [x] **7 Custom Element Web Themes**
- aXion1337 Dark, Deep Purple, Discord Dark, Electric Blue, Everforest, Gruvbox, Wal
- Alphabetisch sortiert
- Commit: `add-custom-element-themes`
- Status: ✅ Deployed
- [x] **Element Desktop Setup Scripts** (Windows/macOS/Linux)
- Auto-Download + Install + Config
- Hosted auf `axion1337.chat/docs/setup/`
- Commits: `add-element-desktop-setup-scripts`, `fix-element-setup-script-hosting`
- Status: ✅ Deployed
- [x] **Room Policies**
- Message Retention (1d1y lifecycle)
- Room Publication Rules (allow all)
- Auto-Join Rooms für Onboarding
- Commit: `add-synapse-retention-publication-autojoin`
- Status: ✅ Deployed
### Phase 3: WebRTC & Medienübertragung
- [x] **TURN Server (coturn) für Video-Calls**
- Domain: `turn.axion1337.chat`
- HMAC-Auth mit Shared Secret
- Ports: 3478/udp, 3478/tcp, 5349/tcp, 49152-65535/udp
- Commit: `implement-turn-server-coturn-for-webrtc-video-calls`
- Status: ✅ Deployed
- Manual: DNS A-Record + Firewall-Ports öffnen (noch erforderlich)
### Phase 4: Monitoring & Observability
- [x] **Monitoring Stack Integration**
- Alloy (Grafana Agent) als Collector
- Remote Write zu Selendis (10.0.0.3:9090 Prometheus, :3100 Loki)
- kube-state-metrics, node-exporter DaemonSet
- Commits: `integrate-monitoring-alloy-prometheus-loki`, `fix-prometheus-remote-write-docker`
- Status: ✅ Deployed
### Phase 5: Identity Provider (Authentik)
- [x] **Authentik Stage 1 Deployment**
- HelmRelease v2026.x in `authentik` namespace
- Embedded PostgreSQL + Alloy-compatible
- Cert-Manager für TLS
- Commit: `deploy-authentik-as-identity-provider-for-matrix-stage-1`
- Status: ✅ Deployed
- Manual: Admin-Passwort + OIDC Provider + Application + Enrollment Flow erstellt ✅
- [x] **Authentik Stage 2 MAS Integration**
- ✅ Authentik Admin UI: OIDC Provider erstellt (Authentik)
- ✅ Authentik Admin UI: Application mit Slug `matrix` erstellt
- ✅ Authentik Admin UI: Enrollment Flow mit Invitation Stage konfiguriert
- ✅ Client ID + Secret kopiert
- ✅ MAS `upstream_oauth2_config` mit Client Credentials aktualisiert
- ✅ `passwords: enabled: false` aktiviert
- ✅ Commit: `cdfbf7d` - Enable Authentik OIDC integration in MAS
- ✅ Verified: Login mit Authentik funktioniert (2026-05-15)
- Status: ✅ Deployed & Verified
### Phase 6: Dokumentation
- [x] **Deployment Guides erstellen**
- 5 Markdown-Dateien in `docs/deployment-guides/`
- Chronologisch geordnet
- Troubleshooting + Best Practices
- Commit: `add-comprehensive-deployment-configuration-documentation`
- Status: ✅ Deployed
- [x] **Gitea Wiki erstellen**
- Home.md mit Navigation
- Alle Deployment Guides in Root
- Operations + Archive Dokumentation
- Wiki Branch gepusht zu rohana.axion1337.de
- Status: ✅ Live
- [x] **Gitea Issues & Project Board**
- 8 Issues erstellt (#3-#10): 4 CRITICAL + 4 HIGH
- Priority Labels: critical, high
- Area Labels: authentik, security, database, infrastructure, element
- Status: ✅ Tracking
### Phase 7: Infrastructure Security (Critical)
- [x] **Hetzner Cloud Firewall Configuration**
- SSH: Spezifische IPs (port 2248)
- HTTP/HTTPS: Any IPv4/IPv6
- TURN/STUN: WebRTC Ports
- RTC Services: SFU + Auth Ports
- Status: ✅ Optimiert & Deployed
- [x] **SSH Hardening**
- PasswordAuthentication: no (key-only)
- PermitRootLogin: no
- MaxAuthTries: 3
- Verified: 2026-05-15
- Status: ✅ Complete
---
## 🔄 In Progress / Blocked
**None** Alle CRITICAL Tasks erledigt! Nächster Focus: Database Backups
---
## 📋 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
### Element Call Enhancement
- [ ] **Element Call Fork für Custom Constraints**
- Repository: Fork `element-hq/element-call`
- Feature: Video/Audio constraints parameter im config
- Include: Bandwidth limiting, resolution limits, frame rate control
- Integration mit Synapse well-known
- Est. Effort: 23 days (fork + feature + test)
- Priority: **HIGH** (user feature)
### Database Hardening
- [ ] **External/Dedicated PostgreSQL Deployment**
- Option 1: CloudNativePG Operator (open-source, auf K3S)
- Option 2: Managed Hetzner Postgres
- Separate aus ESS matrix-stack embedded Postgres
- HA + Replication
- Est. Effort: 12 days
- Priority: **HIGH** (reliability)
- [ ] **Database Backup Strategy**
- Daily automated backups (PgBackRest oder velero)
- Off-site backup storage (S3 / Hetzner Storage Box)
- Monthly verified restores (test restore → verify data integrity)
- Backup + restore documentation
- Est. Effort: 23 days
- Priority: **CRITICAL** (disaster recovery)
- [ ] **Synapse Media PVC Backups**
- Separate backup pipeline für `/data/media_store` PVC
- Reason: Media oft >100GB, sollte nicht im DB-Backup sein
- Velero + Restic für block-level backup
- Est. Effort: 1 day
- 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)
- [ ] **Pod Security Admission (Restricted)**
- Apply to `matrix` & `authentik` namespaces
- Enforce: non-root, no privileged, read-only root fs
- Test: Ensure no chart breakage
- Est. Effort: 1 day
- Priority: **MEDIUM** (hardening)
### Federation & Access Control
- [ ] **Federation-Allowlist oder Closed Federation**
- Decision: Which servers to federate with?
- If allowlist: explicit `federation_domain_whitelist`
- If closed: `allow_public_rooms_without_join_rules: false`
- Synapse config in `synapse-values.yaml`
- Est. Effort: 4 hours
- Priority: **MEDIUM** (security policy)
### Moderation & Anti-Abuse
- [ ] **Mjolnir/Draupnir Bot Deployment**
- Open-source moderation bot für Matrix
- Reason: Invitation-based, aber Federation kann Spam bringen
- Auto-ban known bad servers/users
- Spam-detection rules
- HelmChart oder custom Deployment
- Est. Effort: 12 days
- Priority: **MEDIUM** (ops safety)
- [ ] **Content Scanner for Media**
- matrix-content-scanner + ClamAV antivirus
- Scan uploaded media for malware
- Block suspicious files
- Est. Effort: 12 days
- Priority: **LOWMEDIUM** (optional but good practice)
### Secrets Management
- [ ] **External-Secrets Operator oder SOPS für Flux**
- Current: SOPS with age encryption
- Consideration: External-Secrets for cloud-native (AWS Secrets Manager, Hetzner Vault, etc.)
- OR: Improve SOPS rotation strategy
- Decision needed: Keep SOPS or upgrade?
- Est. Effort: 23 days (if switching)
- Priority: **LOW** (current SOPS setup working)
### Image & Dependency Management
- [ ] **Renovate / Dependabot Setup**
- Auto-update Helm Chart versions
- Auto-update Container Image Tags
- Monitor for security patches
- Est. Effort: 4 hours
- Priority: **MEDIUM** (maintenance)
- [ ] **Trivy Image Scanning**
- Scan images in Flux HelmReleases for CVEs
- Block deployment if critical CVE found
- CI/CD hook in git workflow
- Est. Effort: 8 hours
- Priority: **LOWMEDIUM** (security posture)
- [ ] **Monitor ESS & Element Security Advisories**
- Subscribe to `element-hq` security mailing list
- Monitor `#matrix-community` security channels
- Auto-alerts on new CVEs/patches
- Est. Effort: Ongoing (low maintenance)
- Priority: **MEDIUM** (security awareness)
### Container Security
- [ ] **Disable automountServiceAccountToken Everywhere**
- Audit all Deployments/StatefulSets
- Disable for: Synapse, ElementWeb, MAS, Postgres, Authentik (where not needed)
- Add `automountServiceAccountToken: false` to spec.template.spec
- Test: Ensure no breakage
- Est. Effort: 4 hours
- Priority: **MEDIUM** (least-privilege)
---
## 🔒 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)
- [ ] **unattended-upgrades**
- Enable automatic security updates
- Configure: APT::Periodic::Update-Package-Lists "1";
- Configure: APT::Periodic::Unattended-Upgrade "1";
- Configure: APT::Periodic::AutocleanInterval "7";
- Est. Effort: 30 min
- Priority: **HIGH** (set & forget)
- [ ] **K3S API Security**
- Current: K3S API listening on :6443 on all interfaces (default)
- Hardening:
- Option 1: Firewall restrict :6443 to localhost only
- Option 2: K3S --bind-address + --advertise-address to WireGuard IP
- Option 3: kubectl access only via jumphost/bastion
- Est. Effort: 2 hours
- Priority: **HIGH** (API is high-value target)
- [ ] **auditd for File Integrity & Syscall Audit**
- Monitor: /etc, ~/.kube, /var/lib/rancher/k3s
- Audit rules für sensitive file changes
- Low overhead, good signal/noise ratio
- Output to syslog / centralized logging
- Est. Effort: 2 hours
- Priority: **MEDIUM** (forensics + compliance)
- [ ] **Kernel Hardening (sysctl)**
- Apply hardening recommendations from Lynis
- Key settings:
- kernel.kptr_restrict=2 (hide kernel pointers)
- kernel.dmesg_restrict=1 (restrict dmesg)
- net.ipv4.tcp_syncookies=1 (SYN flood protection)
- net.ipv4.conf.all.rp_filter=1 (reverse path filtering)
- net.ipv4.conf.all.send_redirects=0
- net.ipv6.conf.all.disable_ipv6=0 (or =1 if no IPv6 needed)
- Persist via /etc/sysctl.d/99-hardening.conf
- Est. Effort: 2 hours
- Priority: **MEDIUM** (defense in depth)
- [ ] **Lynis Security Baseline**
- Run `lynis audit system`
- Review recommendations
- Implement high-priority findings
- Aim for score >80
- Re-run quarterly
- Est. Effort: 4 hours (initial) + 1 hour quarterly
- Priority: **MEDIUM** (baseline verification)
### Cluster Layer (K3S / Kubernetes)
- [ ] **CrowdSec Integration**
- Install CrowdSec agent on host
- Connect to CrowdSec Hub (commercial platform, free tier available)
- Feed auth.log, syslog → CrowdSec for attack detection
- Auto-block IPs via local firewall or Hetzner Firewall API
- Est. Effort: 4 hours
- Priority: **MEDIUM** (proactive threat response)
- [ ] **Falco Runtime Monitoring**
- Install Falco DaemonSet in K3S
- Monitor: Shell spawning in containers, suspicious syscalls, privilege escalation
- Output to Loki / syslog
- Alert on anomalies
- Est. Effort: 1 day
- Priority: **MEDIUM** (runtime detection)
---
## 🎯 Meilensteine (Milestones)
| Meilenstein | Beschreibung | Status | ETA |
|------------|-------------|--------|-----|
| **M1: Basis-Setup** | K3S + Flux + ESS deployed | ✅ Done | - |
| **M2: Core Matrix** | Themes, Scripts, Policies | ✅ Done | - |
| **M3: WebRTC & Monitoring** | TURN + Alloy/Prometheus/Loki | ✅ Done | - |
| **M4: Identity Provider** | Authentik Stage 1+2 (pending Stage 2) | 🔄 In Progress | ~12 days |
| **M5: Production-Ready** | DB Backups, NetworkPolicies, Security Hardening | 📋 Backlog | ~23 weeks |
| **M6: Advanced Features** | Element Call Fork, Content Scanner, Mjolnir | 📋 Backlog | ~4+ weeks |
| **M7: Enterprise-Ready** | Full compliance (DSGVO), HA setup, Disaster Recovery | 🎯 Future | ~8+ weeks |
---
## 📊 Prioritäts-Kategorien
### 🔴 CRITICAL (do immediately)
- Hetzner Cloud Firewall setup
- Database backup strategy
- SSH hardening
### 🟠 HIGH (do within 12 weeks)
- Authentik Stage 2 completion
- External PostgreSQL migration
- NetworkPolicies
- Element Call fork
### 🟡 MEDIUM (do within 1 month)
- CrowdSec + Falco
- Mjolnir bot
- Renovate/Trivy
- PSA restricted mode
- Kernel hardening
### 🟢 LOW (nice-to-have, do if time allows)
- Content scanner (ClamAV)
- External-Secrets upgrade
- SSH port relocation
- Advanced federation rules
---
## 📝 Notes & Decision Points
### Authentik Stage 2 Blocker
**Waiting for**: User to manually configure Authentik OIDC Provider in Authentik Admin UI.
- Once done, provide Client ID + Secret
- Then: Commit Stage 2 MAS config
### Database: CloudNativePG vs. Hetzner Postgres
- **CloudNativePG**: Open-source, runs on K3S, full control
- **Hetzner Postgres**: Managed, backups included, less ops overhead
- **Decision**: Recommend CloudNativePG for now (cost-effective), migrate to Hetzner later if operational overhead too high
### Federation: Allowlist vs. Closed?
- **Allowlist**: Default federation with all public servers, can be attacked
- **Closed**: Only federate with trusted servers (higher security, lower interop)
- **Decision**: Depends on user intent. For now: allow all, add Mjolnir for abuse protection
### Security Framework
- **Layers**: Perimeter (Firewall) → Host (SSH, auditd, hardening) → Cluster (NetworkPolicies, PSA, Falco) → App (Rate-limits, Mjolnir)
- **Approach**: Implement incrementally, test after each layer
---
## 🔗 Related Documentation
- `docs/deployment-guides/README.md` Overview
- `docs/deployment-guides/01-turn-server-setup.md` TURN
- `docs/deployment-guides/02-authentik-identity-provider.md` Authentik (Stage 1 + Stage 2 plan)
- `docs/deployment-guides/03-monitoring-integration.md` Monitoring
- `docs/deployment-guides/04-element-customization.md` Themes, Desktop
- `docs/deployment-guides/05-room-policies.md` Policies
---
**Last Updated**: 2026-05-14
**Next Review**: 2026-05-21

View File

@ -0,0 +1,54 @@
# TURN Server (coturn) für WebRTC Video-Calls
**Status**: ✅ Vollständig deployed
**Domain**: `turn.axion1337.chat`
**Public IP**: `49.13.132.245`
## Problem & Lösung
Videocalls scheitern mit DTLS-Timeout bei Clients hinter NAT/Firewall. **Lösung**: coturn als TURN-Relay.
## Architektur
Client A ──→ coturn (turn.axion1337.chat) ──→ Client B
- **Ports**: 3478/udp, 3478/tcp, 5349/tcp, 49152-65535/udp
- **Auth**: HMAC-basiert mit Shared Secret zwischen coturn + Synapse
- **Deployment**: K3S Deployment mit `hostNetwork: true`
## Dateien (in `apps/production/`)
| Datei | Inhalt |
|-------|--------|
| `coturn.yaml` | ConfigMap + Deployment + Service |
| `coturn-secret.yaml` | SOPS-Secret: `TURN_SECRET` |
| `custom-configs/synapse-values.yaml` | TURN URIs + shared secret |
| `matrix-certificates.yaml` | cert-manager Cert für `turn.axion1337.chat` |
## DNS & Firewall (manuell)
```
DNS A-Record: turn.axion1337.chat → 49.13.132.245
Firewall (K3S Host):
ufw allow 3478/udp
ufw allow 3478/tcp
ufw allow 5349/tcp
ufw allow 49152:65535/udp
```
## Verifikation
```bash
# Pod läuft?
kubectl get pods -n matrix -l app=coturn
# Certificate ready?
kubectl get certificate -n matrix | grep turn
# Extern testen
docker run -it instrumentisto/coturn \
turnutils_uclient -v -T -u test -w test turn.axion1337.chat
```
**Weitere Details**: Siehe vollständige Dokumentation oben.

View File

@ -0,0 +1,45 @@
# Authentik als Identity Provider für Matrix
**Status**: ✅ Stage 1 Deployed (Authentik läuft)
**Pending**: Stage 2 (MAS Integration)
**Domain**: `auth.axion1337.chat`
## Überblick
Authentik = OIDC Provider für MAS → Zentrales Login + Einladungs-basierte Registrierung.
## Stage 1: Authentik Deployment
**Dateien** (in `apps/authentik/`):
- `namespace.yaml`, `helm-repo.yaml`, `authentik-secret.yaml` (SOPS)
- `authentik.yaml` (HelmRelease v2026.x + embedded Postgres)
- `certificate.yaml`, `ingress.yaml`
**Flux Kustomization**: `clusters/matrix/flux-system/authentik-sync.yaml`
## Deployment-Schritte
1. **DNS A-Record**: `auth.axion1337.chat → 49.13.132.245`
2. **Pods hochfahren**: `kubectl get pods -n authentik -w`
3. **Authentik UI**: `https://auth.axion1337.chat/if/flow/initial-setup/` → Admin-Passwort setzen
4. **OIDC Provider**: Admin UI → OIDC Provider erstellen
5. **Application**: Slug `matrix` (wichtig für Issuer URL!)
6. **Redirect URIs**:
- `https://account.axion1337.chat/upstream/callback/01KQDJTR1ZVTG8JQ220F5BNBFZ`
- Post-logout: `https://axion1337.chat`
7. **Client ID + Secret kopieren**
## Stage 2: MAS Integration
1. Decrypt: `sops --decrypt --in-place apps/production/custom-configs/mas-secret.yaml`
2. `upstream_oauth2_config` + `passwords-config` Blöcke hinzufügen
3. Encrypt: `sops --encrypt --in-place ...`
4. Commit & Push
5. **WICHTIG**: `passwords: enabled: false` erst nach OIDC-Test!
## Einladungs-Links
Authentik Admin → Flows & Stages → Invitations → Create
---
**Weitere Details**: Siehe Kapitel 2 in diesem Projekt.

View File

@ -0,0 +1,52 @@
# Monitoring: Alloy → Prometheus/Loki auf Selendis
**Status**: ✅ Vollständig deployed
**Remote Storage**: `10.0.0.3:9090` (Prometheus), `10.0.0.3:3100` (Loki)
## Überblick
Alloy (Grafana Agent) sammelt Metriken & Logs vom K3S-Cluster und schickt sie zu Prometheus/Loki auf Selendis.
## Komponenten
| Komponente | Rolle |
|-----------|-------|
| **Alloy** | Metrics & Logs Collector |
| **kube-state-metrics** | Kubernetes Object Status |
| **node-exporter** | Host Metrics (CPU, Memory, Disk) |
| **Prometheus** (Selendis) | Metrics Ingestion |
| **Loki** (Selendis) | Logs Ingestion |
## Dateien (in `apps/monitoring/`)
- `namespace.yaml`
- `helm-repos.yaml` (prometheus-community, grafana)
- `kube-state-metrics.yaml`, `node-exporter.yaml`
- `alloy-config.yaml` (River config with scrape targets + remote write)
- `alloy.yaml` (HelmRelease)
## Scrape Targets
Alloy scraped:
- **Flux Controllers** (flux-system ns, port 8080)
- **kube-state-metrics** (monitoring:8080)
- **node-exporter** (monitoring:9100)
- **Synapse** (matrix.axion1337.chat:9000)
Alle Remote Write zu `10.0.0.3:9090` (Prometheus) + `10.0.0.3:3100` (Loki).
## Troubleshooting
```bash
# Check Alloy Logs
kubectl logs -n monitoring -l app.kubernetes.io/name=alloy
# Check Prometheus remote write
curl http://10.0.0.3:9090/api/v1/query?query=up
# Loki test
curl -s http://10.0.0.3:3100/loki/api/v1/query_range?query=%7B%7D | jq .
```
---
**Weitere Details**: Siehe Kapitel 3.

View File

@ -0,0 +1,57 @@
# Element Web Customization: Themes, Desktop-Apps, Admin
**Status**: ✅ Vollständig deployed
**Domains**: `axion1337.chat` (Web), `/docs/setup` (Scripts)
## 1. Custom Themes (7 Stück)
| Theme | Primärfarbe |
|-------|-----------|
| aXion1337 Dark | `#1a1a1a` |
| Deep Purple | `#6a4c93` |
| Discord Dark | `#2c2f33` |
| Electric Blue | `#0066ff` |
| Everforest Dark Hard | `#1e2326` |
| Gruvbox Dark | `#282828` |
| Wal | `#1e1e1e` |
**Konfiguration**: `apps/production/custom-configs/element-values.yaml`
**Anwendung (User)**: Settings → Appearance → Colour theme
## 2. Desktop-Setup-Scripts
| System | Datei |
|--------|-------|
| Windows | `element-setup-windows.cmd` (Doppelklick) |
| macOS | `element-setup-macos.command` (Doppelklick) |
| Linux | `element-setup-linux.sh` (bash) |
**Was die Scripts tun**:
1. config.json erstellen mit `configUrl: "https://axion1337.chat/config.json"`
2. Element installieren (WinGet / Homebrew / apt/dnf/pacman)
3. Element starten (auto-config laden)
**Download**: `https://axion1337.chat/docs/setup/`
## 3. Element Admin-Panel
**URL**: `https://admin.axion1337.chat`
- User verwalten
- Room durchsuchen
- Server-Statistiken
**Konfiguration**: `apps/production/element-server-suite.yaml` (ESS Chart)
## Dateien
| Datei | Ort |
|-------|-----|
| Custom Themes | `element-values.yaml` ConfigMap |
| Setup-Scripts | `element-web-docs-configmap.yaml` |
| Docs Server | `element-web-docs-server.yaml` (nginx) |
| Ingress | `apex-ingress.yaml` (`/docs/setup/` route) |
---
**Weitere Details**: Siehe Kapitel 4.

View File

@ -0,0 +1,82 @@
# Room Policies: Retention, Publication, Auto-Join
**Status**: ✅ Vollständig deployed
**Konfiguration**: `apps/production/custom-configs/synapse-values.yaml`
## 1. Message Retention
Alte Nachrichten automatisch löschen (Speicher sparen, DSGVO).
```yaml
retention:
enabled: true
default_policy:
min_lifetime: 1d # Messages bleiben ≥1d
max_lifetime: 1y # Messages gelöscht nach 1 Jahr
media_retention:
local_media_lifetime: 365d # 1 Jahr
remote_media_lifetime: 90d # 90 Tage
redaction_retention_period: 7d # Gelöschte Messages noch 7d sichtbar
```
## 2. Room Publication Rules
Kontrollieren welche Rooms im öffentlichen Directory sichtbar sind.
```yaml
room_list_publication_rules:
- user_id: "*" # Alle User
action: allow # dürfen ihre Rooms publishen
```
**Alternativ (restrictiv)**: Nur Admins publishen
```yaml
room_list_publication_rules:
- user_id: "@admin:axion1337.chat"
action: allow
- user_id: "*"
action: deny
```
## 3. Auto-Join Rooms
Neue User automatisch in bestimmte Rooms hinzufügen (Onboarding).
```yaml
auto_join_rooms:
- "!announcements:axion1337.chat"
- "!rules:axion1337.chat"
auto_join_rooms_for_guests: false # Nur registered users
```
**Room ID finden**: Element Settings → Advanced → Room ID
## Deployment
```bash
# Edit ConfigMap
kubectl apply -f apps/production/custom-configs/synapse-values.yaml
# Synapse neustarten
kubectl rollout restart deployment -n matrix matrix-stack-synapse
# Verify
kubectl logs -n matrix -l app.kubernetes.io/name=synapse | grep -i "retention\|publication"
```
## Best Practices
**Privater Server**:
- max_lifetime: 1y (großzügig)
- action: allow (alle publishen)
- auto_join_rooms: announcements + rules
**Öffentlicher Server (DSGWR)**:
- max_lifetime: 90d (kurz)
- action: deny (nur Admins)
- auto_join_rooms: [] (keine Zwangs-Rooms)
---
**Weitere Details**: Siehe Kapitel 5.

View File

@ -0,0 +1,92 @@
# aXion1337.Chat Deployment & Konfiguration Dokumentation
Diese Dokumentation beschreibt die Einrichtung und Konfiguration des Matrix-Homeservers für **axion1337.chat** mit Element Server Suite (ESS) v26.4.0 auf K3S mit Flux CD GitOps.
## 📋 Übersicht Deployment-Reihenfolge
Die Implementierungen wurden in dieser Reihenfolge durchgeführt. Für neue Setups sollten Sie dieser Abfolge folgen:
| # | Titel | Datei | Status | Zieldomäne |
|---|-------|-------|--------|-----------|
| 1 | TURN Server für WebRTC Video-Calls | `01-turn-server-setup.md` | ✅ Deployed | `turn.axion1337.chat` |
| 2 | Authentik als Identity Provider | `02-authentik-identity-provider.md` | ✅ Stage 1 Deployed | `auth.axion1337.chat` |
| 3 | Monitoring mit Alloy/Prometheus/Loki | `03-monitoring-integration.md` | ✅ Deployed | lokal (10.0.0.3) |
| 4 | Element Web Anpassung & Desktop-Apps | `04-element-customization.md` | ✅ Deployed | `axion1337.chat` |
| 5 | Room Policies (Retention, Publication, Auto-Join) | `05-room-policies.md` | ✅ Deployed | Matrix Synapse |
---
## 🚀 Quick Start für neue Deployment
Siehe die einzelnen Dokumentationen für detaillierte Anleitung.
---
## 🏗️ Architektur-Übersicht
```
┌─────────────────────────────────────────────────────────────┐
│ Element Web (Apex) │
│ axion1337.chat (HTTP/TLS) │
└──────────────────────┬──────────────────────────────────────┘
┌─────────────┼─────────────┐
│ │ │
┌────▼────┐ ┌─────▼──────┐ ┌──▼────────┐
│ MAS │ │ Well-Known │ │Docs/Setup │
│account. │ │matrix/* │ │/setup │
│axion1337 │ │ │ │ │
└────┬────┘ └────────────┘ └───────────┘
┌────▼────────────────┐
│ Authentik OIDC │
│ auth.axion1337.chat │
│ (Identity Provider) │
└─────────────────────┘
┌────▼────────────────┐
│ Synapse Matrix │
│ matrix.axion1337.chat│
│ (Homeserver) │
└──────────────────────┘
```
---
## 🔑 Kritische Werte & Konfigurationen
### Domains
- **Apex**: `axion1337.chat` (Element Web)
- **Matrix Synapse**: `matrix.axion1337.chat`
- **MAS**: `account.axion1337.chat`
- **Authentik**: `auth.axion1337.chat`
- **TURN Server**: `turn.axion1337.chat`
### Externe Services
- **K3S Host IP**: `49.13.132.245`
- **Monitoring Host**: `10.0.0.3` (Selendis)
---
## 📚 Dokumente im Detail
### [01-turn-server-setup.md](01-turn-server-setup.md)
STUN/TURN Server für WebRTC Media Relay (Video-Calls).
### [02-authentik-identity-provider.md](02-authentik-identity-provider.md)
Authentik als OIDC Provider für Matrix. Registrierung via Einladungs-Links.
### [03-monitoring-integration.md](03-monitoring-integration.md)
Alloy → Prometheus/Loki Monitoring Integration.
### [04-element-customization.md](04-element-customization.md)
Custom Themes, Desktop-Setup-Scripts, Element Admin.
### [05-room-policies.md](05-room-policies.md)
Message Retention, Room Publication, Auto-Join Policies.
---
## 🛠️ Wartung & Troubleshooting
Alle Dokumentationen enthalten Troubleshooting-Sektionen für häufige Probleme.

117
docs/oldwiki/authentik.md Normal file
View File

@ -0,0 +1,117 @@
# Authentik als Einladungs- und Self-Registration-Layer vor MAS in ESS Community
## Kurzurteil
Ja — in deinem Setup ist **Authentik** technisch sinnvoll einsetzbar, aber **nicht als Ersatz für den Matrix Authentication Service**, sondern **als Upstream-OIDC-Provider vor MAS**. Das ist der sauberste Weg, weil Synapse heute eine stabile, vereinfachte Integration mit MAS hat, ESS Community zusätzliche MAS-Konfiguration ausdrücklich über `matrixAuthenticationService.additional` vorsieht, und MAS jede OIDC-konforme Upstream-Identitätsquelle unterstützt. Für ein ESS-Deployment mit delegierter Authentifizierung ist das deutlich kohärenter als eine Direktanbindung von Synapse an Authentik vorbei. citeturn31view0turn7view2turn14view1turn23search0
Wichtig ist aber die Abgrenzung: Wenn dein einziges Problem wirklich nur lautet „im Admin-Frontend kann ich keine Registration Tokens mehr klicken“, dann **brauchst du Authentik nicht zwingend**. MAS hat weiterhin eine Admin-API mit Endpunkten für User-Registration-Tokens; der fehlende Komfort liegt also eher in der Oberfläche als in der Funktion selbst. Die API ist mit `urn:mas:admin` abgesichert und kann sowohl interaktiv als auch automatisiert benutzt werden. citeturn19search0turn28search0turn28search1turn28search2
## Warum Authentik hier die bessere Plattform sein kann
Der Mehrwert von Authentik entsteht dann, wenn du **mehr als nur ein Token-Feld** willst: Einladungen, Self-Service-Enrolment, E-Mail-Verifikation, Policies, Gruppen-Zuweisung, später vielleicht weitere Login-Quellen hinter derselben Oberfläche. Authentik kann selbst als OpenID Provider auftreten, aber auch als Relying Party gegenüber anderen OAuth/OIDC-Quellen arbeiten; MAS sieht dann nur noch **eine** saubere OIDC-Oberfläche, während Authentik die eigentliche Onboarding- und Policy-Logik kapselt. Das passt sehr gut zu MAS, weil MAS nach oben bewusst nur OIDC unterstützt und SAML/LDAP nicht selbst als Upstream sprechen will. citeturn21view0turn21view3turn14view1
Für dein Ziel „potenzielle Anwender sollen sich selbst registrieren können“ ist der entscheidende Unterschied: Bei MAS-Registration-Tokens autorisierst du eine **Matrix-Registrierung**; bei Authentik autorisierst du zunächst eine **Identität im IdP**, und MAS übernimmt diese Identität anschließend per OIDC und legt daraus den Matrix-Account an. Das ist architektonisch stärker, weil dieselbe Identität später auch für andere Dienste nutzbar wird. MAS kann beim Upstream-Login den Matrix-Localpart, Display Name und E-Mail aus Claims übernehmen; für neue Nutzer gibt es dabei sogar einen expliziten Bestätigungs- bzw. Attribut-Import-Schritt. citeturn24search0turn14view0
## Wann Authentik nicht nötig ist
Wenn du ausschließlich einen „Einladungs-Code“ für Matrix brauchst und keinerlei separates Identitätsmanagement, dann ist die schlankere Lösung wahrscheinlich: **bei MAS bleiben und die Registration-Tokens per Admin-API verwalten**. Dafür brauchst du keinen zusätzlichen Dienst, keine zweite Postgres-Anwendung und keine zweite Policy-Oberfläche. Das ist betriebsärmer und passt gut zu kleinen Community-Setups. citeturn19search0turn28search0turn28search2
Sobald du aber Dinge wie diese willst, kippt die Bewertung klar zugunsten von Authentik: verschiedene Onboarding-Flows, Einladungs-Links statt nackter Codes, E-Mail-Verifikation, Domain-Allow-Lists, Gruppen-Zuweisung, zentrale MFA-Politik oder später externe Identity-Sources. Authentik bringt dafür sowohl vorgefertigte Einladungs-Blueprints als auch Enrolment-Flows mit und kann bei Bedarf eigene Expression Policies für restriktivere Zulassungslogik einsetzen. citeturn21view1turn21view2turn30search3
## Empfohlene Zielarchitektur
Die von mir empfohlene Zielarchitektur ist:
**Element Web / Clients → MAS → Authentik → Benutzerquelle(n)**
Synapse bleibt dabei an MAS delegiert. Das ist genau der Pfad, den die Synapse- und MAS-Dokumentation heute unterstützen: Synapse integriert stabil mit MAS, und MAS kann wiederum Upstream-OIDC-Provider sprechen. Eine direkte Synapse-OIDC-Integration mit Authentik ist zwar technisch dokumentiert, wäre in deinem ESS/MAS-Setup aber die weniger saubere Variante, weil du damit an der in ESS bereits vorgesehenen Delegationsschicht vorbeikonfigurierst. citeturn31view0turn14view2turn14view1turn7view2
Für Authentik selbst ist das Standardmaterial: auf Kubernetes per Helm deployen, in Produktion ein echtes PostgreSQL verwenden statt der Demo-Datenbank, und E-Mail konfigurieren, wenn du Einladungen oder Verifikations-Mails nutzen willst. Das ist wichtig, weil Authentik-Einladungen und E-Mail-basierte Enrolment-Flows ohne Mailtransport ihren eigentlichen Nutzen verlieren. citeturn34view0turn25search1
Ein entscheidender UX-Punkt: Wenn in MAS genau **ein** Upstream-Provider konfiguriert ist und die lokale Passwortdatenbank deaktiviert wird, startet MAS den Upstream-Authentifizierungsfluss automatisch. Damit verhält sich das System für Endnutzer fast so, als wäre Authentik „direkt“ integriert, obwohl MAS weiterhin die Matrix-native Auth-Schicht bleibt. citeturn26view0
## Konkrete Integration in ESS und FluxCD
Der erste praktische Schritt ist, Authentik als eigene GitOps-Anwendung in Kubernetes einzuführen. Offiziell ist dafür das Helm-Chart vorgesehen; produktiv sollte die Datenbank extern bzw. operator-basiert laufen, und Mail sollte von Anfang an mitgedacht werden. Danach erzeugst du in Authentik eine **Application + OAuth2/OIDC Provider**-Kombination. Das ist der von Authentik empfohlene Weg zur Erstellung eines OIDC-Providers. citeturn34view0turn35view0
Für den OIDC-Provider in Authentik verwendest du als Redirect-URI **nicht** die Synapse-Callback-URL aus der direkten Synapse-Dokumentation, sondern die von MAS erwartete Upstream-Callback-URL. MAS verlangt für Upstream-Provider eine stabile ULID als Provider-ID und verwendet daraus die Callback-URL `https://<auth-service-domain>/upstream/callback/<id>`. Optional kannst du zusätzlich die Backchannel-Logout-URL `https://<auth-service-domain>/upstream/backchannel-logout/<id>` hinterlegen. Authentik unterstützt für OIDC-Anwendungen Front- und Back-Channel-Logout, sofern der Provider entsprechend konfiguriert ist. citeturn14view1turn26view3turn35view1
In ESS selbst musst du dafür **keinen Chart forken**. Die vorgesehene Stelle ist `matrixAuthenticationService.additional`. Dort gibst du MAS die Upstream-OIDC-Konfiguration und schaltest die lokale Passwortdatenbank ab, wenn Authentik der alleinige Eintrittspunkt werden soll. Genau dafür ist die ESS-Advanced-Dokumentation da. citeturn7view2
Ein praktikabler MAS-Werteblock für deine GitOps-Struktur sieht so aus:
```yaml
matrixAuthenticationService:
additional:
10-authentik-upstream.yaml:
config: |
passwords:
enabled: false
account:
password_registration_enabled: false
upstream_oauth2:
providers:
- id: 01JVXXXXXXXXXXXXXXXAUTHN
issuer: "https://auth.example.com/application/o/matrix-mas/"
human_name: "Community Login"
client_id: "mas-community"
client_secret: "AUS_SOPS_SECRET"
token_endpoint_auth_method: client_secret_post
scope: "openid profile email"
fetch_userinfo: true
on_backchannel_logout: logout_browser_only
claims_imports:
localpart:
action: require
template: "{{ user.preferred_username }}"
# Nur für Bestandskonten und nur nach Pilotphase:
# on_conflict: set
displayname:
action: force
template: "{{ user.name }}"
email:
action: force
template: "{{ user.email }}"
```
Die inhaltliche Grundlage dafür kommt direkt aus den MAS-Upstream-OIDC-Dokumenten: Provider-`id` als ULID, `issuer`, `client_id`, `client_secret`, Scope, optionale UserInfo-Nutzung und Claim-Mapping für `localpart`, `displayname` und `email`. ESS injiziert genau solche zusätzlichen MAS-Dateien über `matrixAuthenticationService.additional`. citeturn14view1turn14view0turn13view5turn7view2
Für das eigentliche Onboarding in Authentik hast du zwei gute Varianten. Wenn du das MAS-Token-Modell möglichst ähnlich nachbauen willst, nimmst du **Invitations**. Authentik kann Einladungs-URLs an konkrete Empfänger senden oder generische Einladungslinks bereitstellen, bei denen Benutzer ihre Credentials selbst festlegen. Wenn du eher echte Self-Service-Registrierung willst, nimmst du einen Enrolment-Flow, optional mit E-Mail-Verifikation. Beide Muster sind offiziell dokumentiert; es gibt sogar vorgefertigte Blueprints für invitation-based enrollment und Beispiel-Flows für Enrolment mit oder ohne E-Mail-Verifikation. citeturn21view1turn21view2
Wenn du bei der Benutzerführung in Element noch glatter werden willst, kannst du optional in Element Web `sso_redirect_options` setzen, damit Nutzer auf der Login- oder Welcome-Seite sofort in den OIDC-/SSO-Flow gehen. Das ist kein Muss — MAS kann bei einem einzigen Upstream-Provider ohnehin automatisch weiterleiten — aber es verbessert den Eindruck eines „SSO-only“-Setups. citeturn15view4turn26view0
Ein optionaler Element-Web-Block dafür wäre:
```json
{
"sso_redirect_options": {
"on_login_page": true,
"on_welcome_page": true
}
}
```
## Risiken und Fallstricke
Der heikelste Punkt ist die **Abbildung auf bestehende Matrix-Konten**. MAS kann Upstream-Identitäten an vorhandene lokale Nutzer binden, wenn der gemappte `localpart` passt. Standardmäßig verweigert MAS diese Verknüpfung aber; dafür gibt es `claims_imports.localpart.on_conflict` mit Werten wie `set`, `add` oder `replace`. Die Dokumentation warnt ausdrücklich davor, dass das bei unsauberem Mapping ein Account-Takeover-Risiko werden kann. In der Praxis heißt das: `on_conflict` nur dann einschalten, wenn du sicher garantieren kannst, dass Authentik-`preferred_username` oder ein anderes Attribut **eindeutig und dauerhaft** dem gewünschten Matrix-Localpart entspricht. citeturn26view2turn14view0
Der zweite Betriebsfallstrick ist GitOps-spezifisch: Änderungen und Ergänzungen im `upstream_oauth2.providers`-Block synchronisiert MAS beim Start in seine Datenbank, **Entfernungen** aber nicht automatisch. Wenn du einen Provider wieder herausnimmst oder umbenennst, brauchst du zusätzlich `mas-cli config sync --prune`. Für FluxCD ist das wichtig, weil „Config aus Git gelöscht“ hier nicht automatisch „Provider aus MAS-DB gelöscht“ bedeutet. citeturn27search1turn13view5
Der dritte Punkt betrifft Logout-Semantik. Sowohl MAS als auch Authentik können OIDC-Logout verarbeiten, aber du solltest den Modus bewusst wählen. `logout_all` in MAS ist am konsequentesten, kann aber auch Sessions beenden, die aus derselben Upstream-Sitzung stammen und über andere Flows erzeugt wurden. `logout_browser_only` ist meist die konservativere Wahl für einen ersten Rollout. Auf Authentik-Seite kannst du zusätzlich vollständiges Single Logout aktivieren, wenn Logout aus einer Anwendung auch die Authentik-Sitzung selbst und andere verbundene Anwendungen beenden soll. citeturn26view0turn35view1
Falls du Authentik doch nicht einführst und stattdessen bei MAS-Registration-Tokens bleibst, solltest du den ESS-Hinweis ernst nehmen: `account.password_registration_email_required: false` darf auf einem öffentlich föderierenden System nur zusammen mit Einschränkungen wie `registration_token_required: true` benutzt werden, sonst läufst du direkt in Missbrauch und Spam. MAS selbst dokumentiert dieselben Schalter im `account`-Block: Passwort-Registrierung ist standardmäßig aus, E-Mail-Pflicht standardmäßig an, Registration-Token-Pflicht standardmäßig aus. citeturn7view2turn13view0turn13view1turn13view2
## Praktische Entscheidung
Wenn dein Zielbild lautet **„Einladungen, Self-Service, Verifikation, Gruppen, spätere Erweiterbarkeit“**, dann ist meine klare Empfehlung: **Authentik vor MAS**. Das ist in ESS Community sauber integrierbar, nutzt die offiziell vorgesehenen Konfigurationspfade und hält Synapse in der heute empfohlenen MAS-Architektur. citeturn7view2turn31view0turn14view1
Wenn dein Zielbild dagegen nur lautet **„ich will wieder Registration Tokens vergeben können, aber ohne zweiten IdP zu betreiben“**, dann ist die wirtschaftlichere Lösung sehr wahrscheinlich: **MAS Admin API automatisieren statt Authentik einführen**. Funktional ist das möglich; der fehlende Baustein ist nur die Bedienoberfläche, nicht die darunterliegende Token-Funktion. citeturn19search0turn28search0turn28search2
## Offene Punkte und Grenzen
Die produktseitigen Integrationsfragen sind gut durch die offiziellen Dokumentationen abgedeckt. Was ich in diesem Bericht bewusst generisch gehalten habe, sind deine **konkreten Datei- und Pfadnamen im GitOps-Repo** sowie die **genaue Secret-Aufteilung** zwischen ConfigMap und SOPS-Secret. Die technische Empfehlung steht trotzdem fest: MAS bleibt die Matrix-Schicht, Authentik wird der Upstream-IdP, und die Integration erfolgt über `matrixAuthenticationService.additional` in ESS. citeturn7view2turn14view1

View File

@ -0,0 +1,327 @@
# MISSING_MATRIX_RTC_TRANSPORT in ESS 26.4.0: Ursachenanalyse und vollständiger Fix
**Die Ursache ist Hypothese 1: `wellKnownDelegation.enabled: false` ist der Kill-Switch.** In genau dieser Konfiguration schreibt das ESS-Chart den Schlüssel `org.matrix.msc4143.rtc_foci` normalerweise automatisch in das an `https://axion1337.chat/.well-known/matrix/client` ausgelieferte JSON-Dokument sobald `wellKnownDelegation.enabled: true` **und** `matrixRTC.enabled: true` gesetzt sind. Mit `wellKnownDelegation: false` fällt dieses Dokument komplett weg. Element Web hat damit keinen Discovery-Pfad zur LiveKit-Instanz auf `mrtc.axion1337.chat`, und Matrix-JS-SDK wirft genau deshalb `MISSING_MATRIX_RTC_TRANSPORT`. Hypothese 2 (Synapse-Custom-Keys sind bogus) ist ebenfalls korrekt. Hypothese 4 (Element Web braucht explizites `rtc_foci`) ist **falsch** Element Web liest `rtc_foci` ausschließlich aus Well-Known, niemals aus `config.json`. Hypothese 5 ist ein *sekundäres* Thema: LiveKit UDP-Ports müssen offen sein, aber der Fehler `MISSING_MATRIX_RTC_TRANSPORT` entsteht ausschließlich aus der Discovery, nicht aus Medien-Erreichbarkeit.
## Wie die Fehlerkette konkret abläuft
Element Web ruft beim Start eines Anrufs intern zwei Discovery-Pfade auf: `GET /_matrix/client/v1/rtc/transports` gegen Synapse (MSC4143, ab Synapse 1.140) und als Fallback `GET https://<serverName>/.well-known/matrix/client`, wo der Schlüssel `org.matrix.msc4143.rtc_foci` erwartet wird. Das ESS-Chart befüllt **beide** Pfade automatisch, sobald `matrixRTC.enabled: true` ist: In `wellKnownDelegation` wird das `rtc_foci`-Array injiziert, in Synapse wird der `matrix_rtc.transports`-Block in die `homeserver.yaml` gemerged (chart-intern, siehe ess-helm Changelog Eintrag #855: *"Configure experimental MSC4143 advertisement in Synapse when MatrixRTC is enabled. This is in addition to the MSC4143 advertisement on the client well-known endpoint for now, but it is expected to replace it in time."*). **Beide Mechanismen werden durch `wellKnownDelegation.enabled: false` nicht vollständig deaktiviert** die Synapse-Seite wird zwar weiter gesetzt, aber weil kein Well-Known am Apex existiert, kann Element Web den Homeserver gar nicht über `default_server_name` auflösen und daher auch den Transport-Endpunkt nicht konsistent nutzen. Resultat: leere Transport-Liste, Fehler ausgelöst.
Ein korrektes `/.well-known/matrix/client` sieht so aus (das ist exakt, was das Chart ausliefern würde):
```json
{
"m.homeserver": { "base_url": "https://matrix.axion1337.chat" },
"m.identity_server": { "base_url": "https://vector.im" },
"org.matrix.msc4143.rtc_foci": [
{ "type": "livekit",
"livekit_service_url": "https://mrtc.axion1337.chat" }
]
}
```
Der Schlüsselname ist **`org.matrix.msc4143.rtc_foci`** (MSC-Prefix, kein `m.rtc_foci`). Das Value-Objekt hat zwingend `type: "livekit"` und `livekit_service_url: "https://<matrixRTC.ingress.host>"`.
## Warum die Custom-Synapse-Values aktuell wirkungslos sind
Die Keys `matrix_rtc_enabled` und `matrix_rtc_uri` **existieren in Synapse nicht**. Synapse kennt für MatrixRTC genau zwei Dinge: einen `experimental_features`-Block (`msc3266_enabled`, `msc4140_enabled`, `msc4222_enabled`, und implementierungsabhängig `msc4143_enabled`) und einen Top-Level-Block `matrix_rtc.transports:` für den neuen `/v1/rtc/transports`-Endpunkt. Das ESS-Chart setzt diese **automatisch**, sobald `matrixRTC.enabled: true` ist. Synapse ignoriert unbekannte Top-Level-Keys in der `homeserver.yaml` stillschweigend; der Container crasht nicht, aber es passiert auch exakt gar nichts. Der ganze `rtc-config`-Block muss raus. Der `url-previews`-Block ist dagegen legitim die Keys `url_preview_enabled`, `url_preview_ip_range_blacklist`, `max_spider_size` sind echte Synapse-Optionen.
## Der eigentliche Grund für die "ACME Race Condition"
Das Problem war **nicht** ein Bug, sondern eine vorhersagbare Fehlkonfiguration: Beide Ingresses (Element Web und wellKnownDelegation) forderten über die `cert-manager.io/cluster-issuer`-Annotation **jeweils ein eigenes TLS-Secret** für denselben Host `axion1337.chat` an. Cert-manager erzeugt dann zwei `Certificate`-Objekte mit unterschiedlichen `secretName`s → zwei `Order`-Objekte → HTTP-01-Solver-Ingresses überschreiben sich gegenseitig → Let's-Encrypt-Rate-Limit schlägt zu (5 duplicate certs / 7 Tage). Siehe cert-manager Issue #2342 und Discussion #3511: *"If both ingresses have their own secret to save the certificate tls, cert-manager runs havoc and exhausts the ACME limit very quickly."* Die saubere Lösung ist, dass genau **eine** Zertifikat-Quelle für `axion1337.chat` existiert.
Das ESS-Chart selbst erwartet, dass `elementWeb.ingress.host` **nicht** gleich `serverName` ist. Der Standard-Pattern ist: Element Web auf `chat.<apex>` bzw. `app.<apex>`, Well-Known auf dem Apex, und eine optionale `baseDomainRedirect.url` leitet `/` auf dem Apex zu Element Web weiter.
## Fix 1 (empfohlen): Element Web auf Subdomain umziehen
Das ist die Lösung, für die das Chart designt ist, und erfordert genau eine DNS-Änderung sowie YAML-Anpassungen.
### DNS-Voraussetzungen
| Record | Typ | Ziel | Zweck |
|---|---|---|---|
| `axion1337.chat` | A/AAAA | öffentliche IP des K3s-Nodes | Apex: Well-Known + Cert für Matrix-Server-Delegation |
| `matrix.axion1337.chat` | A/AAAA | K3s-Node-IP | Synapse |
| `account.axion1337.chat` | A/AAAA | K3s-Node-IP | Matrix Authentication Service |
| `mrtc.axion1337.chat` | A/AAAA | K3s-Node-IP | LiveKit-Signaling + lk-jwt-service |
| `chat.axion1337.chat` | A/AAAA | K3s-Node-IP | **NEU**: Element Web |
| `admin.axion1337.chat` | A/AAAA | K3s-Node-IP | Element Admin |
### Angepasster HelmRelease (`apps/production/element-server-suite.yaml`)
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: matrix-stack
namespace: matrix
spec:
interval: 1h
chart:
spec:
chart: matrix-stack
version: "26.4.0"
sourceRef:
kind: HelmRepository
name: element-ess-oci
namespace: flux-system
valuesFrom:
- kind: ConfigMap
name: ess-synapse-custom
valuesKey: values.yaml
- kind: ConfigMap
name: ess-element-custom
valuesKey: values.yaml
- kind: Secret
name: ess-mas-values-secret
valuesKey: values.yaml
values:
serverName: axion1337.chat
certManager:
clusterIssuer: letsencrypt-prod
postgres:
enabled: true
synapse:
enabled: true
ingress:
host: matrix.axion1337.chat
matrixAuthenticationService:
enabled: true
ingress:
host: account.axion1337.chat
matrixRTC:
enabled: true
ingress:
host: mrtc.axion1337.chat
# SFU public-IP override empfohlen, falls der Node hinter NAT steht
# und STUN die falsche Adresse zurückgibt:
# sfu:
# useStunToDiscoverPublicIP: false
# manualIP: "<public-IP-of-node>"
elementWeb:
enabled: true
ingress:
host: chat.axion1337.chat # <- NICHT mehr der Apex
elementAdmin:
enabled: true
ingress:
host: admin.axion1337.chat
wellKnownDelegation:
enabled: true # <- zurück auf true (Default)
# Optional: Redirect vom Apex "/" auf Element Web.
# Das Chart-Feature kam in 26.x hinzu; falls dein konkreter Wert-Key
# fehlt, siehe Fix 2 (eigene IngressRoute) als sichere Alternative.
baseDomainRedirect:
url: https://chat.axion1337.chat
```
Mit diesem Setup beansprucht **genau ein** Chart-erzeugter Ingress den Apex `axion1337.chat`, nämlich der der `wellKnownDelegation`. Es gibt nur ein Zertifikat, keine Race Condition. Element Web läuft auf `chat.axion1337.chat` und bekommt sein eigenes, konfliktfreies Cert.
### Bereinigter Synapse-ConfigMap (`apps/production/custom-configs/synapse-values.yaml`)
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ess-synapse-custom
namespace: matrix
data:
values.yaml: |
synapse:
logging:
rootLevel: INFO
levelOverrides:
synapse.media.url_previewer: DEBUG
additional:
# RTC-Block ENTFERNT: matrix_rtc_enabled / matrix_rtc_uri sind keine
# gültigen Synapse-Keys. Das ESS-Chart setzt matrix_rtc.transports und
# die nötigen experimental_features automatisch, wenn matrixRTC.enabled=true.
1-url-previews:
config: |
url_preview_enabled: true
url_preview_ip_range_blacklist:
- '127.0.0.0/8'
- '10.0.0.0/8'
- '172.16.0.0/12'
- '192.168.0.0/16'
- '100.64.0.0/10'
- '192.0.0.0/24'
- '169.254.0.0/16'
- '192.88.99.0/24'
- '198.18.0.0/15'
- '192.0.2.0/24'
- '198.51.100.0/24'
- '203.0.113.0/24'
- '224.0.0.0/4'
- '::1/128'
- 'fe80::/10'
- 'fc00::/7'
- '2001:db8::/32'
- 'ff00::/8'
- 'fec0::/10'
max_spider_size: 10M
```
Wichtige Details zum `additional`-Mechanismus: die Keys werden **alphabetisch sortiert** gemerged, daher die `1-`/`2-`-Namenskonvention. Arrays werden ersetzt, nicht zusammengeführt.
### Element-Web-ConfigMap (`apps/production/custom-configs/element-values.yaml`)
Hier ist **keine** RTC-spezifische Änderung nötig. Element Web hat gemäß `element-web/docs/config.md` keinen `rtc_foci`-Key und entdeckt den Transport ausschließlich über Well-Known. Der optionale `element_call`-Block steuert nur Branding und Verhalten:
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ess-element-custom
namespace: matrix
data:
values.yaml: |
elementWeb:
additional:
config.json: |
{
"brand": "aXion1337.Chat",
"element_call": {
"brand": "aXion1337 Call",
"use_exclusively": true
},
"features": {
"feature_video_rooms": true,
"feature_element_call_video_rooms": true
},
"show_labs_settings": true
}
```
`use_exclusively: true` entfernt die Legacy-Jitsi-Option aus dem UI, sodass Anrufe garantiert über MatrixRTC/LiveKit laufen.
## Fix 2 (Alternative): Apex manuell splitten per Traefik IngressRoute
Falls `baseDomainRedirect` in deiner 26.4.0-Revision nicht greift oder du Element Web auf dem Apex behalten willst, ersetze beide Chart-Ingresses durch eine **einzige Traefik IngressRoute mit einem einzigen Certificate**. Dadurch sieht cert-manager nur noch eine Quelle für `axion1337.chat`, und Traefik routet Pfad-basiert.
```yaml
# apps/production/apex-ingress.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: axion-apex-tls
namespace: matrix
spec:
secretName: axion-apex-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- axion1337.chat
---
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: axion-apex
namespace: matrix
spec:
entryPoints: [websecure]
tls:
secretName: axion-apex-tls
routes:
# Höchste Priorität: /.well-known/matrix/* -> wellKnownDelegation-Service
- match: Host(`axion1337.chat`) && PathPrefix(`/.well-known/matrix`)
kind: Rule
priority: 100
services:
- name: matrix-stack-well-known-delegation # ggf. Service-Namen mit `kubectl get svc -n matrix` verifizieren
port: 8080
# Niedrigere Priorität: alles andere -> Element Web
- match: Host(`axion1337.chat`)
kind: Rule
priority: 10
services:
- name: matrix-stack-element-web
port: 8080
```
Dazu muss in der HelmRelease die automatische Chart-Ingress-Erzeugung für diese beiden Komponenten unterbunden werden setze `wellKnownDelegation.ingress.className: "none"` bzw. `elementWeb.ingress.className: "none"` oder setze die `host`-Werte auf Dummy-Hostnames, sodass die Chart-Ingresses nicht denselben Apex beanspruchen. Fix 1 ist wegen geringerer Komplexität klar zu bevorzugen.
## Netzwerk- und Firewall-Anforderungen für LiveKit
**Das ist der nächste Stolperstein nach dem Well-Known-Fix.** Die HTTPS-Ingress auf `mrtc.axion1337.chat` terminiert nur **Signaling (WSS auf TCP 443)** und die lk-jwt-service-Endpunkte `/sfu/get`, `/get_token`, `/healthz`. WebRTC-Medien laufen **nicht** über den Ingress, sondern direkt zum Node auf UDP/TCP-NodePorts.
Öffne auf deiner K3s-Node-Firewall (und im Router/Cloud-Security-Group):
| Port | Protokoll | Standard ESS CE | Zweck |
|---|---|---|---|
| 80, 443 | TCP | — | Ingress + ACME HTTP-01 |
| `rtcMuxedUdp` NodePort | **UDP** | 30002 (CE) / 30882 (Pro) | **Kritisch**: WebRTC-Medien (UDP-Mux). Ohne das: keine Audio/Video-Daten |
| `rtcTcp` NodePort | TCP | 30881 | ICE/TCP-Fallback für Clients ohne UDP |
| `turn` NodePort | UDP | 30004 | Nur falls `matrixRTC.sfu.exposedServices.turn.enabled: true` |
| `turnTLS` Port | TCP | 31443 oder 443 | Nur falls TURN/TLS aktiv; braucht SNI-Passthrough und eigenes Hostname |
Ermittle die tatsächlichen NodePorts per `kubectl get svc -n matrix | grep rtc`. Wenn dein Node hinter NAT steht und LiveKits STUN-basierte Public-IP-Erkennung die falsche Adresse zurückliefert, setze zusätzlich:
```yaml
matrixRTC:
sfu:
useStunToDiscoverPublicIP: false
manualIP: "<deine-öffentliche-IP>"
```
## Verifikationsschritte
Nach Reconcile (`flux reconcile helmrelease matrix-stack -n matrix`) diese vier Tests durchführen:
**1. Well-Known für Matrix-Client liefert rtc_foci:**
```bash
curl -sS https://axion1337.chat/.well-known/matrix/client | jq .
# Erwartung: JSON mit "m.homeserver" UND "org.matrix.msc4143.rtc_foci"
# das livekit_service_url == "https://mrtc.axion1337.chat" enthält.
curl -sS https://axion1337.chat/.well-known/matrix/server | jq .
# Erwartung: {"m.server": "matrix.axion1337.chat:443"}
```
**2. lk-jwt-service und LiveKit-Signaling sind erreichbar:**
```bash
curl -i https://mrtc.axion1337.chat/healthz
# Erwartung: HTTP/1.1 200 OK
curl -i https://mrtc.axion1337.chat/sfu/get
# Erwartung: HTTP/1.1 405 Method Not Allowed (akzeptiert nur POST)
curl -i -H "Connection: Upgrade" -H "Upgrade: websocket" \
-H "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==" \
-H "Sec-WebSocket-Version: 13" \
https://mrtc.axion1337.chat/
# Erwartung: HTTP/1.1 101 Switching Protocols (WebSocket-Upgrade)
```
**3. Synapse bietet den MSC4143-Endpunkt an:**
```bash
TOKEN="<gültiges-access-token>"
curl -sS -H "Authorization: Bearer $TOKEN" \
https://matrix.axion1337.chat/_matrix/client/v1/rtc/transports | jq .
# Erwartung: {"transports":[{"type":"livekit","livekit_service_url":"https://mrtc.axion1337.chat"}]}
```
**4. UDP-Medien kommen an:** In Element Web Call starten → im Chrome/Firefox-DevTools unter Netzwerk → WS prüfen, dass `wss://mrtc.axion1337.chat/rtc?access_token=...` einen `101`-Upgrade bekommt; unter `chrome://webrtc-internals` nach ICE-Candidate-Paaren mit Status `succeeded` und Typ `host/srflx` schauen. Falls nur Signaling, aber kein Media: UDP-NodePort auf Firewall prüfen.
## ACME-Race dauerhaft vermeiden
Merksatz: **Ein Hostname ⇒ genau ein `Certificate`-Objekt ⇒ genau ein `secretName`.** Drei betriebliche Strategien:
- **Subdomain-Trennung (Fix 1):** Jede Chart-Komponente bekommt einen eigenen FQDN, jeder FQDN genau ein Cert. Keine Kollision möglich. Das ist die vom Chart vorgesehene Form.
- **Geteiltes Secret:** Wenn zwei Ingresses denselben Host tragen müssen, trägt nur **einer** die `cert-manager.io/cluster-issuer`-Annotation. Beide referenzieren `spec.tls[].secretName` auf dasselbe Secret. Traefik wählt das Zertifikat korrekt aus.
- **DNS-01 statt HTTP-01:** Löst den Solver-Ingress-Konflikt grundsätzlich, weil kein zweiter Ingress erzeugt wird. Setzt DNS-Provider-Credentials im ClusterIssuer voraus.
## Vom Benutzer übersehene Chart-Werte
Außer den oben beschriebenen Korrekturen sind diese Keys erwähnenswert, falls du feintunen willst. `matrixRTC.hostAliases` ist ein dokumentierter Workaround gegen Cluster-interne DNS-Probleme, wenn der lk-jwt-service-Pod den Homeserver-Apex bzw. Synapse über den Ingress-Controller statt direkt erreichen muss. `matrixRTC.sfu.exposedServices.<name>.portType` akzeptiert `NodePort`, `HostPort` oder `LoadBalancer` für bare-metal K3s ohne externen LB ist `NodePort` richtig. `matrixRTC.sfu.additional."user-config.yaml".config` erlaubt rohes LiveKit-YAML für Spezialfälle (STUN-Server, Codecs). `wellKnownDelegation.additional.client` / `.server` / `.element` erlauben, in die erzeugten JSON-Dokumente zusätzliche Felder einzumischen normalerweise nicht nötig, aber nützlich für föderative Sonderfälle.
## Fazit
Der eigentliche Defekt war ein einziger Kippschalter: `wellKnownDelegation.enabled: false` hat den einzig existierenden Discovery-Kanal für den LiveKit-Focus gekappt. Der darum herum gebaute Custom-Synapse-Block ist ein Red Herring die zugehörigen Schlüssel existieren in Synapse schlicht nicht und werden ignoriert. Die ursprünglich empfundene ACME-Race ist kein Bug des Charts, sondern die vorhersagbare Folge davon, dass zwei Chart-erzeugte Ingresses (Element Web **auf dem Apex** plus Well-Known) jeweils ein eigenes Let's-Encrypt-Zertifikat für denselben Host anforderten. Sobald Element Web nach `chat.axion1337.chat` wandert und Well-Known wieder aktiv ist, produziert das Chart automatisch das korrekte `org.matrix.msc4143.rtc_foci`-Feld, injiziert den `matrix_rtc.transports`-Block in Synapse, und Element Call funktioniert vorausgesetzt die UDP-NodePort-Firewall ist offen, was nach dem Discovery-Fix der zweite Punkt auf der Prüfliste ist.

12083
docs/oldwiki/home.md Normal file

File diff suppressed because it is too large Load Diff

498
docs/oldwiki/invitereg.md Normal file
View File

@ -0,0 +1,498 @@
# Invite-basierte Selbstregistrierung mit MAS in ESS Community unter Ansible und FluxCD
## Zusammenfassung
Für ein entity["company","Element","matrix software company"]-basiertes ESS-Community-Deployment mit aktivem Matrix Authentication Service ist eine invite-basierte Selbstregistrierung **ohne Authentik** sauber umsetzbar. Der belastbare Weg ist: **MAS-Registrierung aktivieren, Registrierungstoken erzwingen, Tokens über die MAS Admin API erzeugen, und Standard-Onboarding über Synapse `auto_join_rooms` abbilden**. In MAS-/MSC3861-Setups sind die alten Synapse-Mechanismen für Registration Tokens bzw. Shared-Secret-Registration nicht mehr der richtige Pfad: Die Synapse-Registration-Token-API ist in diesem Modus deaktiviert, ebenso die Shared-Secret-Registration-API; die offizielle Automationsoberfläche für externe Tools ist stattdessen die MAS Admin API. citeturn1view2turn20view1turn26search11turn26search5turn35view0
Für die Zuweisung zu Räumen und Spaces gilt: **MAS-Claims sind für Identitätsattribute gedacht, nicht für Raum-/Space-Mitgliedschaften**. Der robuste Standard ist daher eine Zweiteilung: **allgemeine Onboarding-Räume und Spaces über Synapse `auto_join_rooms`**, und **feingranulare, zielgruppenspezifische Mitgliedschaften über einen kleinen Post-Registration-Provisioner oder ein Synapse-Modul** über `on_user_registration` bzw. `on_user_login`. Gruppen/Communities sind heute kein sinnvolles Ziel mehr, weil Synapse diese Funktion deprecated und anschließend entfernt hat; für aktuelle Deployments solltest du konsequent mit **Spaces + Rooms** arbeiten. citeturn16view0turn16view1turn16view2turn34view0turn35view0turn17search0turn17search2
Für GitOps empfehle ich eine klare Trennung zwischen **statischer Konfiguration** und **operativem Invite-Zustand**. Statisch in Git/SOPS/Flux gehören: MAS-Account-Settings, SMTP-Daten, der MAS-Admin-OAuth-Client und optionale Onboarding-Policies. **Kurzlebige Einmal-Tokens** sollten dagegen in der Regel **nicht** als dauerhafter Desired State in Git geführt werden, sondern bei Bedarf über die MAS Admin API erzeugt, per E-Mail verschickt und nur optional als Audit-Record abgelegt werden. Das passt deutlich besser zu FluxCD als das “GitOpsen” flüchtiger Einladungen. Die optionale LiveKit-/Element-Call-Schicht ist für den Registrierungsfluss architektonisch unabhängig. citeturn20view1turn23view0turn23view3turn25search0turn25search13
## Zielbild und Architektur
Die offizielle ESS-Dokumentation unterstützt zusätzliche Konfiguration für Synapse, MAS, Element Web und MatrixRTC/LiveKit jeweils über `additional`-Blöcke. MAS läuft dabei neben Synapse und spricht mit Synapse über den dedizierten `matrix_authentication_service`-Mechanismus; Synapse 1.136+ führt diese Integration als stabile Konfiguration. Für dein Ziel bedeutet das: ESS/Helm liefert die Plattform, MAS erzwingt die Token-basierte Registrierung, Synapse übernimmt Mitgliedschaften, und Element Web kann optional eine eigene Landing-/Invite-Seite anzeigen. citeturn1view2turn1view5turn31view1turn35view0turn24search0
```mermaid
flowchart TB
subgraph GitOps["GitOps-Steuerung"]
A[Ansible]
F[FluxCD]
G[Git Repository]
S[SOPS Secrets]
A --> G
S --> G
F --> G
end
subgraph K8s["Kubernetes / ESS Helm"]
HR[HelmRelease matrix-stack]
EW[Element Web]
MAS[Matrix Authentication Service]
SYN[Synapse]
PG[(PostgreSQL)]
SMTP[SMTP]
MOD[Optional: Post-Registration Provisioner / Synapse-Modul]
LK[Optional: LiveKit / Element Call]
end
G --> HR
HR --> EW
HR --> MAS
HR --> SYN
HR --> PG
HR --> LK
MAS --> PG
SYN --> PG
MAS --> SMTP
MAS <--> SYN
EW --> MAS
EW --> SYN
A -->|MAS Admin API| MAS
A -->|E-Mail Einladung| User[Neuer Benutzer]
User -->|Invite-Link + Registration Token| EW
User -->|Registrierung| MAS
MAS -->|User-Provisionierung| SYN
SYN -->|auto_join_rooms| User
MOD -->|join/invite per Synapse Admin API| SYN
```
Die praktikabelste Zielarchitektur ist deshalb: **Invite-Mail → MAS Token-Registierung → Synapse-Provisionierung → automatisches Standard-Onboarding via `auto_join_rooms` → optionaler Fein-Provisioner für zusätzliche Spaces/Räume**. Für Spaces ist wichtig: Synapse behandelt Spaces “unter der Haube” als Räume, daher können Space-Aliasse in `auto_join_rooms` verwendet werden. **Automatisch erzeugen** kann Synapse über `autocreate_auto_join_rooms` jedoch **keine Spaces**; Spaces müssen also vorher existieren. citeturn16view0turn16view1turn16view5
Die Optionen lassen sich so einordnen:
| Option | Bewertung | Stärken | Schwächen | Geeignet für |
|---|---|---|---|---|
| MAS Registration Tokens | **Empfohlen** | Nativ im MAS-Stack, sauber mit ESS/MAS, externe Tooling-Anbindung über Admin API | Keine offizielle, dokumentierte “Einladungs-E-Mail-Engine” für Invite-Links; Token-Versand musst du selbst automatisieren | ESS Community mit FluxCD/Ansible citeturn20view1turn12view0turn37view1turn1view2 |
| Authentik Invitations | Möglich, aber hier unnötig | Fertiges Invite-/Enrollment-Modell, URL-basierte Invitations | Zusätzlicher IdP-Layer, mehr bewegliche Teile, für dein Ziel kein Muss | Wenn ohnehin zentraler OIDC-IdP Standard ist citeturn36search0turn36search1 |
| Manuelle Admin-Erstellung | Solide als Fallback | Maximal kontrolliert, kein Self-Service nötig | Kein Selbstregistrierungsfluss, hoher Betriebsaufwand | Break-glass, Admin-/Testkonten citeturn27view1turn26search5 |
Wichtig für die Zielmodellierung: **Groups/Communities** sind im aktuellen Synapse-Kontext kein tragfähiges Onboarding-Ziel mehr. Die offizielle Synapse-Kommunikation beschreibt Groups/Communities als deprecated und ab Synapse 1.61 entfernt; Spaces sind der vorgesehene Ersatz. Wenn du also “Spaces, Groups, Rooms” als Zielbild denkst, sollte die reale Implementierung **Spaces + Rooms** heißen. citeturn17search0turn17search2
## MAS-Konfiguration und GitOps-Manifeste
ESS stellt laut offizieller Doku genau den von dir benötigten Mechanismus bereit: Zusätzliche MAS-Konfiguration wird unter `matrixAuthenticationService.additional` in YAML-Fragmente gelegt und in die finale MAS-Konfiguration gemerged. Dasselbe gilt für Synapse unter `synapse.additional` und für Element Web unter `elementWeb.additional`. citeturn1view2turn31view1
Der kleinste sinnvolle MAS-Block für invite-basierte Self-Registration sieht so aus. Die Felder `password_registration_enabled`, `registration_token_required` und `password_registration_email_required` sind offiziell dokumentiert; ESS dokumentiert zusätzlich explizit, dass `password_registration_email_required: false` **nur** in Kombination mit Restriktionen wie `registration_token_required: true` auf öffentlich föderierenden Deployments verantwortbar ist, weil die Instanz sonst missbraucht werden kann. citeturn2view4turn20view0turn1view2
```yaml
apiVersion: v1
kind: Secret
metadata:
name: ess-mas-values-secret
namespace: matrix
stringData:
values.yaml: |
matrixAuthenticationService:
additional:
10-account.yaml:
config: |
passwords:
enabled: true
minimum_complexity: 3
account:
password_registration_enabled: true
registration_token_required: true
password_registration_email_required: false
password_change_allowed: true
password_recovery_enabled: false
login_with_email_allowed: false
# Optional, falls du Recoveries / Verifizierung brauchst
email:
from: '"Matrix Auth" <no-reply@__DOMAIN__>'
reply_to: '"Support" <support@__DOMAIN__>'
transport: smtp
mode: starttls
hostname: __SMTP_HOST__
port: 587
username: __SMTP_USERNAME__
password: __SMTP_PASSWORD__
# Für halböffentliche Setups empfehlenswert
captcha:
service: cloudflare_turnstile
site_key: __TURNSTILE_SITE_KEY__
secret_key: __TURNSTILE_SECRET_KEY__
policy:
data:
registration:
banned_usernames:
literals: ["admin", "root", "support"]
emails:
allowed_addresses:
suffixes: ["@example.org"]
requester:
banned_ips:
- 10.0.0.0/8
- 192.168.0.0/16
rate_limiting:
registration:
burst: 2
per_second: 0.0003
login:
per_ip:
burst: 5
per_second: 0.02
per_account:
burst: 30
per_second: 0.1
```
Damit externe Tools Tokens anlegen können, muss die **MAS Admin API** aktiviert werden. Die offizielle MAS-Doku sagt ausdrücklich, dass `adminapi` nicht standardmäßig exponiert ist und in einen Listener aufgenommen werden muss; Zugriffe werden mit dem Scope `urn:mas:admin` geschützt. Für automatisierte Tools ist der dokumentierte Weg ein **OAuth-Client mit `client_credentials`**, dessen `client_id` in `policy.data.admin_clients` steht. citeturn20view1turn23view0turn23view3
```yaml
apiVersion: v1
kind: Secret
metadata:
name: ess-mas-admin-client
namespace: matrix
stringData:
admin-client.yaml: |
http:
listeners:
- name: web
resources:
- name: discovery
- name: human
- name: oauth
- name: compat
- name: graphql
playground: false
- name: assets
path: ./share/assets/
- name: adminapi
binds:
- address: "[::]:8080"
clients:
- client_id: 01JV0000000000000000000001
client_auth_method: client_secret_basic
client_secret: "__MAS_ADMIN_CLIENT_SECRET__"
policy:
data:
admin_clients:
- 01JV0000000000000000000001
```
Dieses Secret bindest du wiederum als weiteren `additional`-Eintrag ein. So vermeidest du Dateipfad-Annahmen im Container und hältst den Client-Secret-Wert SOPS-fähig. citeturn31view1turn20view1turn23view0
```yaml
apiVersion: v1
kind: Secret
metadata:
name: ess-mas-values-secret
namespace: matrix
stringData:
values.yaml: |
matrixAuthenticationService:
additional:
20-admin-client.yaml:
configSecret: ess-mas-admin-client
configSecretKey: admin-client.yaml
```
Für FluxCD genügt ein klassisches `valuesFrom`-Muster. Das bildet dein bestehendes Repo-Schema mit ConfigMaps/Secrets gut ab und bleibt mit SOPS kompatibel. citeturn31view1turn1view2
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: matrix-stack
namespace: matrix
spec:
interval: 1h
chart:
spec:
chart: matrix-stack
sourceRef:
kind: HelmRepository
name: element-ess-oci
namespace: flux-system
valuesFrom:
- kind: ConfigMap
name: ess-synapse-custom
valuesKey: values.yaml
- kind: ConfigMap
name: ess-element-custom
valuesKey: values.yaml
- kind: Secret
name: ess-mas-values-secret
valuesKey: values.yaml
values:
serverName: "__SERVER_NAME__"
postgres:
enabled: true
synapse:
enabled: true
ingress:
host: "__SYNAPSE_HOST__"
matrixAuthenticationService:
enabled: true
ingress:
host: "__MAS_HOST__"
elementWeb:
enabled: true
ingress:
host: "__ELEMENT_HOST__"
matrixRTC:
enabled: true
ingress:
host: "__MRTC_HOST__"
```
Für das automatische Standard-Onboarding nimmst du Synapse `auto_join_rooms`. Die offizielle Synapse-Doku bestätigt: neue Benutzer werden automatisch zu den gelisteten Räumen hinzugefügt; **Space-Aliasse sind erlaubt**, weil Spaces Räume sind; **Spaces werden aber nicht automatisch erzeugt**, und für private/invite-only Auto-Join-Setups muss `auto_join_mxid_localpart` gesetzt sein, wobei dieser Benutzer in den betreffenden Räumen Mitglied sein und Einladungsrechte haben muss. citeturn16view0turn16view1turn16view2
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ess-synapse-custom
namespace: matrix
data:
values.yaml: |
synapse:
additional:
20-onboarding.yaml:
config: |
auto_join_rooms:
- "#welcome:__SERVER_NAME__"
- "#announcements:__SERVER_NAME__"
- "#community-space:__SERVER_NAME__"
autocreate_auto_join_rooms: false
auto_join_mxid_localpart: system
auto_join_rooms_for_guests: false
```
Für die User Experience kannst du Element Web mit einer eigenen Welcome-/Invite-Seite versehen. Offiziell unterstützt Element Web dafür `embedded_pages.welcome_url`, `login_for_welcome`, Branding-Parameter und für native OIDC-Setups OIDC-Client-Optionen. Für deinen Fall ist das vor allem nützlich, **weil die offizielle MAS-Dokumentation keinen stabil dokumentierten URL-Parameter zum Prefill eines Registration Tokens beschreibt**; die saubere Lösung ist daher oft eine eigene Landing-Page, die den Token erklärt oder temporär speichert und dann zum Registrierungsfluss führt. Diese Aussage ist eine Architektur-Inferenz aus den offiziellen Element- und MAS-Dokumenten. citeturn24search0turn20view1turn22view0
```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: ess-element-custom
namespace: matrix
data:
values.yaml: |
elementWeb:
additional:
config.json: |
{
"embedded_pages": {
"welcome_url": "https://__ELEMENT_HOST__/invite/index.html",
"login_for_welcome": false
},
"branding": {
"auth_header_logo_url": "https://__ELEMENT_HOST__/assets/logo.svg"
}
}
```
Ein wichtiger Betriebs-Hinweis: Es gibt aktuell ein **offenes GitHub-Issue** im ESS-Helm-Repository, das meldet, dass `matrixAuthenticationService.additional.*` in bestimmten Konstellationen ignoriert werden könne. Das ist kein offizieller Release-Hinweis, aber als Failure-Mode ernst zu nehmen. Deshalb solltest du nach jeder Änderung das **gerenderte MAS-ConfigFile im Pod** prüfen, bevor du mit echten Einladungen arbeitest. citeturn38view0turn31view1
## Einladungsworkflow und Provisionierung
Der saubere GitOps-Ablauf ist in der Praxis fünfstufig. Zuerst legst du **statische Konfiguration** in Git ab: MAS-Settings, SMTP, Admin-Client, Synapse Auto-Join. Danach reconciled Flux diese Ressourcen in den Cluster. Anschließend erzeugt Ansible oder ein Shell-Skript **on demand** ein kurzlebiges Registration Token über die MAS Admin API. Dieses Token wird per E-Mail verschickt entweder als Link zu deiner eigenen Invite-Landing-Page oder als Nachricht mit Token + Registrierungsanweisung. Beim ersten erfolgreichen Abschluss der Registrierung provisioniert MAS den Account in Synapse; Synapse zieht dann `auto_join_rooms`. Wenn du danach noch gezielt Spaces/Räume abhängig von Abteilung, Rolle oder Domäne vergeben willst, übernimmt das ein Provisioner oder ein Synapse-Modul. citeturn20view1turn12view0turn16view0turn34view0
Für die **MAS Admin API** ist der dokumentierte Automationspfad `client_credentials`. Die MAS-Doku nennt dafür explizit statische Clients + `policy.data.admin_clients`. Das Access-Token kannst du discovery-basiert holen, damit du keine Token-Endpoint-Pfade hart codierst. citeturn20view1turn22view0turn23view0
```bash
#!/usr/bin/env bash
set -euo pipefail
MAS_ISSUER="https://account.__DOMAIN__/"
CLIENT_ID="01JV0000000000000000000001"
CLIENT_SECRET="${MAS_ADMIN_CLIENT_SECRET}"
TOKEN_ENDPOINT="$(
curl -fsSL "${MAS_ISSUER}.well-known/openid-configuration" \
| jq -r '.token_endpoint'
)"
ACCESS_TOKEN="$(
curl -fsSL -u "${CLIENT_ID}:${CLIENT_SECRET}" \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials' \
-d 'scope=urn:mas:admin' \
"${TOKEN_ENDPOINT}" \
| jq -r '.access_token'
)"
curl -fsSL -X POST "https://account.__DOMAIN__/api/admin/v1/user-registration-tokens" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H 'Content-Type: application/json' \
-d '{
"usage_limit": 1,
"expires_at": "2026-05-01T12:00:00Z"
}' | jq
```
Die MAS-OpenAPI-Spezifikation dokumentiert für Registration Tokens genau die Felder, die du dafür brauchst: `token` optional, `usage_limit`, `expires_at`, dazu die Verwaltungsendpunkte zum **Listen**, **Updaten**, **Revoken** und **Unrevoken** unter `/api/admin/v1/user-registration-tokens`. “Valid” bedeutet laut Spec: nicht abgelaufen, nicht widerrufen und Usage-Limit nicht ausgeschöpft. Für Invite-Flows solltest du in der Regel **`usage_limit: 1` und kurze Expiry-Zeiten** verwenden. citeturn12view0turn13view0turn37view0turn37view1turn37view2
Beispiel für Rotation bzw. Widerruf eines ungenutzten Tokens:
```bash
TOKEN_ID="01JVABCDEF..."
curl -fsSL -X POST "https://account.__DOMAIN__/api/admin/v1/user-registration-tokens/${TOKEN_ID}/revoke" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
```
Wenn du Token-Limits oder die Ablaufzeit nachträglich anpassen willst, ist laut MAS-Admin-Spec `PUT /api/admin/v1/user-registration-tokens/{id}` der vorgesehene Weg. citeturn13view0turn11view0
In Ansible lässt sich derselbe Flow sehr gut abbilden. Hier ein minimales Beispiel mit Discovery, Token-Erzeugung und Mailversand. Der SMTP-Provider ist bewusst als Platzhalter gelassen, weil du ihn nicht spezifiziert hast. Die Speicherung des erzeugten Registration-Tokens in Git ist **optional**; ich würde standardmäßig nur **Token-ID, Empfänger, Ablaufzeit und Versandzeitpunkt** als Audit speichern, nicht das Secret selbst. citeturn20view1turn12view0turn3view1turn2view5
```yaml
- name: Discover MAS token endpoint
ansible.builtin.uri:
url: "https://account.__DOMAIN__/.well-known/openid-configuration"
return_content: true
register: oidc_discovery
- name: Get MAS admin access token
ansible.builtin.uri:
url: "{{ oidc_discovery.json.token_endpoint }}"
method: POST
user: "{{ mas_admin_client_id }}"
password: "{{ mas_admin_client_secret }}"
force_basic_auth: true
body_format: form-urlencoded
body:
grant_type: client_credentials
scope: urn:mas:admin
return_content: true
register: mas_oauth
- name: Create single-use registration token
ansible.builtin.uri:
url: "https://account.__DOMAIN__/api/admin/v1/user-registration-tokens"
method: POST
headers:
Authorization: "Bearer {{ mas_oauth.json.access_token }}"
body_format: json
body:
usage_limit: 1
expires_at: "{{ invite_expires_at }}"
return_content: true
register: mas_invite
- name: Build invite URL
ansible.builtin.set_fact:
invite_url: "https://__ELEMENT_HOST__/invite/?token={{ mas_invite.json.data.attributes.token | urlencode }}"
- name: Send invitation email
community.general.mail:
host: "__SMTP_HOST__"
port: 587
secure: starttls
username: "__SMTP_USER__"
password: "__SMTP_PASSWORD__"
to: "{{ invitee_email }}"
from: "no-reply@__DOMAIN__"
subject: "Deine Matrix-Einladung"
body: |
Hallo,
hier ist deine Einladung für Matrix.
Einladung: {{ invite_url }}
Das Token ist einmalig nutzbar und gültig bis {{ invite_expires_at }}.
```
Für die **automatische Zuweisung** zu Spaces/Räumen nach erster Anmeldung gibt es drei robuste Muster:
Erstens der Standardpfad über `auto_join_rooms`: ideal für **alle** neuen Benutzer, z. B. `#welcome`, `#announcements` und ein Haupt-Space. Das ist die einfachste und offizielle Lösung. Zweitens ein **Post-Registration-Provisioner**, der den Benutzer zusätzlich in weitere Räume einlädt oder joined. Dafür ist der offizielle Synapse-Admin-Endpunkt `POST /_synapse/admin/v1/join/<room_id_or_alias>` gedacht. Drittens ein **Synapse-Modul**, das `on_user_registration` oder `on_user_login` implementiert. Die Primärdoku beschreibt genau diese Callback-Punkte; seit Synapse 1.135 müssen Module allerdings worker-safe sein, weil `on_user_registration` auch auf Workern laufen kann. citeturn16view0turn27view0turn34view0turn35view0
Ein Provisioner gegen die Synapse Admin API kann so aussehen. Dabei setze ich voraus, dass du bereits einen **user-bound** Synapse-Admin-Token hast; dafür verweist die offizielle MAS-Doku auf den Device-Code-Flow mit Synapse-Admin-Scopes. Dasselbe Dokument zeigt auch, wie man kombinierte MAS-/Synapse-Admin-Tokens interaktiv anfordern kann. citeturn27view0turn32search1turn32search0
```bash
#!/usr/bin/env bash
set -euo pipefail
SYNAPSE_BASE="https://matrix.__DOMAIN__"
SYNAPSE_ADMIN_TOKEN="${SYNAPSE_ADMIN_TOKEN}"
USER_ID="$1"
join_room() {
local alias="$1"
curl -fsSL -X POST \
-H "Authorization: Bearer ${SYNAPSE_ADMIN_TOKEN}" \
-H 'Content-Type: application/json' \
"${SYNAPSE_BASE}/_synapse/admin/v1/join/${alias}" \
-d "{\"user_id\":\"${USER_ID}\"}" >/dev/null
}
join_room "#community-space:__SERVER_NAME__"
join_room "#announcements:__SERVER_NAME__"
join_room "#team-general:__SERVER_NAME__"
```
Wichtig ist hier die Abgrenzung zu “Claim Mappings”: Die offizielle MAS-OIDC-Doku beschreibt `claims_imports` für **`localpart`**, **`displayname`**, **`email`** und **`account_name`**. Daraus folgt: Claim-Mappings sind nützlich, wenn du später doch einen Upstream-OIDC-Provider ergänzen willst, aber sie lösen **nicht** die Mitgliedschaft in Spaces/Räumen. Für deinen Authentik-freien Invite-Flow ist das korrekte Modell also **Token + Synapse-Onboarding**, nicht “Claims → Rooms”. citeturn21search1turn9search4
## Sicherheit und Betriebsmodell
Die sicherste Konfiguration für dein Szenario ist nicht “offene Registrierung mit etwas Deko”, sondern **echte Invite-only-Registrierung**. Das bedeutet konkret: `password_registration_enabled: true`, `registration_token_required: true` und nur dann `password_registration_email_required: false`, wenn du bewusst auf Token-Schutz, kurze Laufzeiten, Single-Use und gute Missbrauchsbarrieren setzt. Genau davor warnt die ESS-Doku ausdrücklich: Ein öffentlich föderierender Server ohne Mailpflicht **und** ohne starke Restriktionen wird missbraucht. citeturn2view4turn20view0turn1view2
Ich würde die Sicherheitsprofile so priorisieren:
| Profil | Empfohlene Settings | Wann sinnvoll | Kommentar |
|---|---|---|---|
| Striktes Invite-only | `password_registration_enabled: true`, `registration_token_required: true`, `password_registration_email_required: false`, `usage_limit: 1`, kurze Expiry | Kleine Community, kuratierte Benutzerbasis | Beste Mischung aus UX und Missbrauchsschutz citeturn2view4turn12view0turn37view2 |
| Invite-only mit Recovery | Wie oben, aber `password_recovery_enabled: true` und SMTP voll konfiguriert | Wenn Nutzer Self-Service-Passwort-Reset brauchen | Erhöht Komfort, verlangt sauberen Mailbetrieb citeturn2view4turn2view5 |
| Halböffentlich | Tokenpflicht + CAPTCHA + E-Mail-Allowlist + restriktivere Rate-Limits | Wenn Einladungen wiederverwendbar oder breiter verteilt werden | Mehr Schutz gegen Bot-/Spam-Missbrauch citeturn3view2turn20view0turn3view1 |
Zu den wichtigsten Härtungsmaßnahmen gehören: **Single-Use (`usage_limit: 1`)**, **kurze Gültigkeit**, **Rate Limits für Registrierungen**, **optional CAPTCHA**, **optional Domain-Allowlist für E-Mails**, **Banned IP/User-Agent-Regeln** und ein **interner oder streng geschützter MAS-Admin-API-Zugang**. MAS dokumentiert all diese Stellhebel explizit: `policy.data.registration.*`, `emails.allowed_addresses`, `requester.banned_ips`, CAPTCHA-Provider und `rate_limiting.registration`. citeturn20view0turn3view1turn3view2turn2view5
Für die Raum-/Space-Seite gilt zusätzlich: Halte sensible Onboarding-Räume **invite-only** und vermische “öffentlich sichtbare Discovery” nicht mit einem privaten Invite-Modell. Die Matrix-/Synapse-Dokumentation empfiehlt bei privaten Setups ausdrücklich, die Sichtbarkeit öffentlicher Räume restriktiv zu halten; Synapse hat die Standardregeln für Room-Directory-Publikation in neueren Versionen auch bewusst verschärft. citeturn17search6turn35view0
Ein subtiler, aber wichtiger Punkt ist die Trennung von **MAS Admin** und **Synapse Admin**. Offiziell ist `urn:mas:admin` für automatisierte `client_credentials`-Tools dokumentiert. Für `urn:synapse:admin:*` beschreibt die Scope-Referenz dagegen ein benutzergebundenes Modell; außerdem braucht Synapse-Admin zusätzlich die Matrix-API-Scopes. Daraus folgt als belastbare Betriebsregel: **Reine Maschinenautomation sollte primär MAS Admin API nutzen; Synapse-Admin-Aktionen entweder über Auto-Join, über ein Synapse-Modul oder über einen echten Service-User mit benutzergebundenem Admin-Token**. citeturn20view1turn32search0turn32search1
## Tests, Rollout und Recovery
Der Rollout sollte nicht mit echten Einladungen beginnen, sondern mit einem **vollständigen Dry-Run auf Staging oder einem Testkonto**. Zuerst reconcile-st du Flux, dann prüfst du das HelmRelease und die gerenderte MAS-Konfiguration. Danach testest du die MAS Admin API, erzeugst ein kurzes Einmal-Token, registrierst einen neuen Testnutzer, überprüfst `times_used`/`valid`, kontrollierst die Raum-/Space-Mitgliedschaften und widerrufst übrige Tokens. Damit deckst du sowohl die ESS-/MAS-Seite als auch die Synapse-Onboarding-Seite einmal komplett ab. citeturn20view1turn12view0turn16view0turn27view0
Die fachliche Checkliste dafür ist kurz, aber strikt:
- **Konfiguration vorhanden:** `matrixAuthenticationService.additional` und `synapse.additional` sind im gerenderten Config-Output sichtbar. Wegen des offenen ESS-Issues zu `additional.*` solltest du das aktiv prüfen. citeturn31view1turn38view0
- **MAS Admin API erreichbar:** `/api/spec.json` bzw. das Anlegen eines Tokens funktioniert mit `urn:mas:admin`. citeturn20view1turn10view0
- **Token-Lebenszyklus korrekt:** neues Token erscheint als `valid`, nach Nutzung steigt `times_used`, bei `usage_limit: 1` ist es anschließend nicht mehr gültig. citeturn12view0turn37view2
- **Onboarding korrekt:** Testnutzer landet im Haupt-Space, in Welcome/Announcements und falls aktiviert in weiteren Zielräumen. citeturn16view0turn27view0
- **Missbrauchsschutz greift:** Ablaufzeit, CAPTCHA, Rate-Limits und Policy-Regeln sind aktiv. citeturn3view1turn3view2turn20view0
Die wichtigsten Failure Modes und ihre Recovery-Schritte sind diese:
| Symptom | Wahrscheinliche Ursache | Recovery |
|---|---|---|
| Registrierung fordert trotzdem E-Mail-Verifikation | `password_registration_email_required` ist noch `true` oder falsches MAS-Configfile aktiv | Gerendertes MAS-Configfile prüfen, Werte korrigieren, neu deployen citeturn2view4turn1view2turn38view0 |
| `403` bei Token-Erzeugung | OAuth-Client nicht in `policy.data.admin_clients` oder falscher Scope | Client-/Policy-Fragment korrigieren, neuen Access Token holen citeturn20view1turn23view3 |
| `404` auf `/api/admin/v1/...` | `adminapi` nicht in `http.listeners.resources` aktiviert | Listener-Block korrigieren und Redeploy citeturn20view1 |
| User landet nicht im Space | Space existiert nicht, Space wurde nicht separat angelegt, oder `auto_join_mxid_localpart`-User kann nicht einladen | Space vorab anlegen, `system`-User joinen lassen, Rechte prüfen; Spaces werden nicht automatisch erstellt citeturn16view0turn16view1turn16view2 |
| Feingranulare Raumzuweisung klappt nicht | Du versuchst Membership über Claim-Mapping zu lösen | Membership über Auto-Join, Provisioner oder Synapse-Modul abbilden citeturn21search1turn34view0 |
| “Groups” lassen sich nicht mehr sinnvoll zuweisen | Groups/Communities sind im aktuellen Synapse-Modell entfernt | Auf Spaces + Rooms umstellen citeturn17search0turn17search2 |
Wenn ein Invite-Token versehentlich verschickt wurde, ist der saubere Recovery-Schritt **nicht** das HelmRelease zu verändern, sondern das Token per MAS Admin API zu **revoken** und bei Bedarf ein neues zu erzeugen. Wenn ein Benutzer zwar registriert wurde, aber Raumzuweisungen fehlen, ist die schnellste operative Korrektur ein nachgelagerter Join über den Synapse-Admin-Endpunkt. Wenn ein Synapse-Modul dafür verantwortlich ist, beachte die Worker-Eigenschaft von `on_user_registration`. citeturn13view0turn27view0turn35view0
## Quellenbasis und offene Punkte
Die belastbarsten Primärquellen für dieses Design sind die offiziellen Dokumentationen zu ESS, MAS, Synapse, Element Web und LiveKit. Für den Vergleichspfad “Authentik Invitations” ist die offizielle Authentik-Doku hinzugezogen worden.
Die Priorisierung war dabei:
- ESS Advanced-Doku zur Einbindung zusätzlicher Konfigurationsdateien für MAS, Synapse, Element Web und MatrixRTC. citeturn1view2
- ESS Chart-Values zur Bestätigung, dass `matrixAuthenticationService.additional`/`synapse.additional`/`elementWeb.additional` offizielle Wertepfade sind. citeturn31view1turn31view4
- MAS-Konfigurationsreferenz für `account.*`, `captcha`, `policy`, `rate_limiting`, `email`, `clients`, `admin_clients` und HTTP-Listener. citeturn2view4turn20view0turn22view0turn23view0
- MAS Admin API und OpenAPI-Schema für Token-Erzeugung, Update, Revoke, Validitätsbegriff und Automationsmodell. citeturn20view1turn12view0turn13view0turn37view1turn37view2
- MAS Scope- und Access-Token-Doku für den Unterschied zwischen `urn:mas:admin` und benutzergebundenem Synapse-Admin-Zugriff. citeturn32search0turn32search1
- Synapse-Konfigurationsmanual für `auto_join_rooms`, Space-Aliasse, `autocreate_auto_join_rooms` und `auto_join_mxid_localpart`. citeturn16view0turn16view1turn16view2
- Synapse-Admin- und Modul-Doku für Raumzuweisung per API und Callback-Punkte `on_user_registration` / `on_user_login`. citeturn27view0turn34view0turn35view0
- Element-Web-Konfiguration für Welcome-/Branding-/OIDC-nahe UX-Optionen. citeturn24search0
- LiveKit-/Element-Call-Doku als optionale, vom Registrierungsfluss getrennte RTC-Schicht. citeturn25search0turn25search13
- Authentik-Invitationsdoku nur für den Vergleich innerhalb der Optionen-Tabelle. citeturn36search0turn36search1
Offen beziehungsweise bewusst konservativ behandelt bleiben drei Punkte. Erstens beschreibt die offizielle MAS-Dokumentation nach dem hier ausgewerteten Stand **keinen stabil dokumentierten Invite-Link-Parameter**, mit dem ein Registration Token sicher per URL in die MAS-UI vorbefüllt wird; deshalb empfehle ich eine eigene Landing-Page oder Token-Übermittlung im Mailtext. Zweitens ist **client_credentials** sauber für die **MAS Admin API** dokumentiert, nicht aber als Standardmuster für **Synapse-Admin-Automation**; für Synapse-Onboarding ist deshalb `auto_join_rooms` oder ein user-/modulbasierter Pfad robuster. Drittens gibt es aktuell ein offenes ESS-Helm-Issue zu `matrixAuthenticationService.additional.*`; deshalb solltest du das gerenderte MAS-Configfile im Deployment immer verifizieren, bevor du produktive Einladungen versendest. citeturn20view1turn32search0turn38view0

296
docs/ops-configmap-sync.md Normal file
View File

@ -0,0 +1,296 @@
# 🔄 GitOps ConfigMap Auto-Sync via Checksums
Dieses Dokument erklärt ein Kernproblem mit **Flux CD** und **externe Konfigurationen** und wie wir es gelöst haben.
---
## 📋 Das Problem: Flux erkennt ConfigMap-Änderungen nicht
### Die Situation
Unsere HelmRelease (`element-server-suite.yaml`) nutzt `valuesFrom`, um Konfigurationen aus externen **ConfigMaps** zu laden:
```yaml
spec:
valuesFrom:
- kind: ConfigMap
name: ess-element-custom # ← Diese ConfigMap
valuesKey: values.yaml
- kind: ConfigMap
name: ess-synapse-custom # ← Diese ConfigMap
valuesKey: values.yaml
```
Diese ConfigMaps entstehen aus Dateien im Git-Repo (`apps/production/custom-configs/*.yaml`) und werden von Kustomize in den Cluster deployed.
### Das Kernproblem
**Flux CD reagiert NICHT automatisch, wenn sich eine ConfigMap ändert.**
Warum? Flux überwacht nur das Git-Repository auf Änderungen. Wenn du `element-values.yaml` änderst:
1. ✅ Flux sieht die Änderung im Git-Repo
2. ✅ Kustomize erzeugt eine neue ConfigMap mit den neuen Werten
3. ❌ Aber Helm (der Helm-Controller in Flux) erkennt **nicht**, dass sich die externe ConfigMap geändert hat
4. ❌ Helm deployt das Chart nicht neu → Die alten Themes/Configs bleiben aktiv
Das ist kein Bug, sondern by-design: Helm achtet nur auf:
- Chart-Version (z.B. `26.4.0`)
- Änderungen in den direkten `values:` Blöcken
- Nicht auf externe Quellen wie ConfigMaps
---
## 🔑 Die Lösung: Checksums als Trigger
Wir nutzen **Annotations mit Checksums** als Workaround:
```yaml
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
annotations:
element-config-checksum: "401f8a87d0ef5d91d2e5032d4aede42c" # ← Hash der element-values.yaml
synapse-config-checksum: "e98fe81141f52e7ea833596ca39853b9" # ← Hash der synapse-values.yaml
```
Wenn sich der Annotation-Wert ändert, sieht Flux, dass die **HelmRelease selbst** sich geändert hat und deployt neu.
### Automatisierung via Git Pre-Commit Hook
Das Problem: Wer aktualisiert die Checksums, wenn man `element-values.yaml` editiert?
**Lösung:** Ein Git **pre-commit Hook** tut das automatisch:
```bash
$ vi apps/production/custom-configs/element-values.yaml
# (Farbe ändern, Theme hinzufügen, …)
$ git add apps/production/custom-configs/element-values.yaml
$ git commit -m "feat: new theme"
# ← Der Hook läuft jetzt:
# 1. Berechnet MD5-Hash der neuen element-values.yaml
# 2. Aktualisiert die Annotation in kustomization.yaml
# 3. Added kustomization.yaml zum Commit automatisch
```
Der User muss **nichts Zusätzliches tun** alles läuft automatisch.
---
## 🚀 Installation
Nach dem Repository **klonen**, führe dieses Skript aus:
```bash
cd prod/gitops
./scripts/install-hooks.sh
```
Das Skript:
- ✅ Erstellt einen Symlink `.git/hooks/pre-commit``scripts/hooks/pre-commit`
- ✅ Macht die Hook-Datei ausführbar
- ✅ Gibt dir eine Bestätigungsmeldung
**Einmalig pro lokales Repository.** Neue Klone müssen den Hook auch installieren.
---
## 📝 Workflow: ConfigMaps ändern
So sieht die Praxis aus:
### 1⃣ Änderung machen
```bash
vi apps/production/custom-configs/element-values.yaml
# Edit: Themes, Farben, Logging-Level, etc.
```
### 2⃣ Committen (Hook läuft automatisch)
```bash
git add apps/production/custom-configs/element-values.yaml
git commit -m "feat: add Dark Purple theme variant"
# Pre-Commit Hook läuft automatisch:
# → Berechnet neuen Hash
# → Updated kustomization.yaml
# → Added kustomization.yaml zum Commit
```
### 3⃣ Überprüfung (optional)
```bash
# Schaue, was committet wird:
git show --stat
# Output sollte zeigen:
# element-values.yaml (modified)
# kustomization.yaml (modified) ← vom Hook hinzugefügt
```
### 4⃣ Pushen & Deployen
```bash
git push
# ← Flux sieht die Änderung an kustomization.yaml
# ← HelmRelease wird neu-synced mit den neuen Checksums
# ← Die neue Config ist in ~5 Minuten aktiv
```
---
## 🔧 Technische Details
### Welche Dateien sind "überwacht"?
Der Hook beobachtet:
| Datei | Annotation | Ziel |
|-------|-----------|------|
| `apps/production/custom-configs/element-values.yaml` | `element-config-checksum` | Element Web Themes, Branding |
| `apps/production/custom-configs/synapse-values.yaml` | `synapse-config-checksum` | Synapse Logging, Federation |
### Hook-Implementation
Der Hook (`scripts/hooks/pre-commit`) macht folgendes:
1. Prüft, ob eine der überwachten Dateien geändert wurde (`git diff --cached`)
2. Berechnet den MD5-Hash der Datei (kompatibel mit macOS/Linux)
3. Ersetzt den Hash-Wert in `apps/production/kustomization.yaml` via `sed`
4. Added `kustomization.yaml` automatisch zum Commit mit `git add`
```bash
# Beispiel: element-values.yaml ändert sich von
value: "401f8a87d0ef5d91d2e5032d4aede42c" # element-config
# zu
value: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" # element-config
```
---
## ⚠️ Häufige Fragen
### F: Was passiert, wenn der Hook fehlschlägt?
A: Der Commit wird **abgebrochen**. Du siehst eine Fehlermeldung. Typische Gründe:
- `md5` oder `md5sum` nicht installiert (sehr unwahrscheinlich)
- `sed` Syntax-Fehler (sehr selten)
Lass dich nicht entmutigen rufe denen auf, die das Setup machen 🚀
### F: Kann ich den Hook deaktivieren?
A: Ja, aber bitte nicht! Wenn du temporär ohne Hook arbeiten möchtest:
```bash
git commit --no-verify
```
Das umgeht den Hook einmalig. Danach musst du die Checksums manuell aktualisieren.
### F: Der Hook touched `kustomization.yaml`, obwohl ich sie nicht editiert habe?
A: Das ist **Absicht**. Der Hook updated **nur** die Checksums, nicht den Rest der Datei. Das ist sauber und Git-freundlich.
### F: Was wenn ich mehrere ConfigMaps gleichzeitig ändere?
A: Der Hook aktualisiert **alle** deren Checksums in einem Pass. Keine Probleme.
---
## 🧪 Verifikation: Hook funktioniert?
Teste es selbst:
```bash
# 1. Hook installieren
./scripts/install-hooks.sh
# 2. Eine Teständerung machen
echo "# Test" >> apps/production/custom-configs/element-values.yaml
# 3. Committen
git add apps/production/custom-configs/element-values.yaml
git commit -m "test: verify hook"
# 4. Überprüfung: Wurde kustomization.yaml auto-updated?
git diff HEAD~1 apps/production/kustomization.yaml | grep -i checksum
# Output sollte zeigen, dass ein Checksum sich geändert hat
```
Wenn ja → Hook funktioniert! ✅
Wenn nein → Rufe uns an 📞
---
## 📚 Zusammenhang mit Flux CD
```
┌─────────────────────────────────────────────────────────────┐
│ Git Repository (axion1337.chat-gitops) │
├─────────────────────────────────────────────────────────────┤
│ │
│ apps/production/custom-configs/ │
│ ├── element-values.yaml (du änderst das) │
│ ├── synapse-values.yaml │
│ └── mas-secret.yaml │
│ │
│ apps/production/ │
│ └── kustomization.yaml (Hook updated die Checksums hier) │
│ │
│ apps/production/ │
│ └── element-server-suite.yaml (HelmRelease mit Annotations)│
│ │
└─────────────────────────────────────────────────────────────┘
↓ git push
┌─────────────────────────────────────────────────────────────┐
│ FluxCD im Kubernetes-Cluster │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. GitRepository Source │
│ └─ Fetcht dein Repo alle 10 Minuten │
│ │
│ 2. Kustomization production-apps │
│ └─ Applyt die Kustomize-Overlays │
│ └─ Erzeugt ConfigMaps mit neuen Werten │
│ │
│ 3. HelmRelease matrix-stack │
│ └─ Sieht neue Annotations (Checksums) │
│ └─ Deployt Helm-Chart mit neuen Werten │
│ │
│ 4. Element Web Pods │
│ └─ Restarten automatisch │
│ └─ Laden neue Config aus der ConfigMap │
│ │
└─────────────────────────────────────────────────────────────┘
```
---
## 🚨 Notfall: Manuelle Checksum-Aktualisierung
Falls der Hook ausfällt (z.B. weil Git Hooks in CI deaktiviert sind), kannst du Checksums manuell aktualisieren:
```bash
# 1. Neuen Hash berechnen
md5sum apps/production/custom-configs/element-values.yaml
# Output: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 apps/production/custom-configs/element-values.yaml
# 2. Annotation in kustomization.yaml updaten
vi apps/production/kustomization.yaml
# Ändere: value: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" # element-config
# 3. Committen
git add apps/production/kustomization.yaml
git commit -m "fix: manual checksum update"
git push
```
---
**Version:** 1.0
**Letztes Update:** 2026-05-14
**Kompatibilität:** FluxCD 2.x, Kustomize 5.x+

View File

@ -0,0 +1,256 @@
# 🆕 Authentik: Neuen Invitation Flow erstellen
**Problem**:
- Nur ein `matrix-enrollment` Flow existiert
- Wird für Standard-Signup + Invitations verwendet → Konflikt
- Fehler: "Found existing plan for other flow, deleting plan"
**Lösung**: Separaten `matrix-invitation` Flow für Einladungslinks erstellen.
---
## Schritt 1: Authentik Admin UI öffnen
```bash
kubectl port-forward -n authentik svc/authentik 9000:9000
# Browser: http://localhost:9000/
# Admin: akadmin / (password)
```
---
## Schritt 2: Neuen Flow erstellen
**Navigation**: Admin → Flows & Stages → Flows
1. Klick **"Create"** (oben rechts)
2. Fülle folgendes aus:
```
Name: matrix-invitation
Slug: matrix-invitation
Title: Matrix Enrollment via Invitation
Description: Enrollment flow for users created via invitation links
Designation: enrollment
```
3. **Speichern** (Save)
---
## Schritt 3: Stages zur Invitation Flow hinzufügen
Nach dem Erstellen wirst du auf die Flow-Edit-Seite weitergeleitet.
**Navigation**: Admin → Flows & Stages → Flows → `matrix-invitation` → Edit
Klick auf "Add Stage" und folge dieser Reihenfolge:
### Stage 1: Invite Stage (Invitation verarbeiten)
1. Klick **"Add Stage"**
2. Wähle: **"Invite Stage"**
3. Konfiguriere:
```
Name: Invite
Order: 1
```
4. **Save**
Dann musst du das Binding setzen:
- Klick auf die Stage in der Flow
- Binding: **"Invite"** (oder "Invitation")
- Required: **Yes**
- **Save**
### Stage 2: Identification Stage (Username überprüfen)
1. Klick **"Add Stage"**
2. Wähle: **"Identification Stage"** (nicht "Authenticate Stage")
3. Konfiguriere:
```
Name: Identification
Order: 2
User Fields: username (oder email)
Create Users as Inactive: NO
```
4. **Save**
Binding setzen:
- Binding: **"Identify"**
- Required: **No**
- **Save**
### Stage 3: Prompt Stage (Daten abfragen: Username, Email, Name)
1. Klick **"Add Stage"**
2. Wähle: **"Prompt Stage"**
3. Konfiguriere:
```
Name: User Data
Order: 3
```
4. **Speichern (Save)**
Dann **Fields hinzufügen**:
- Klick auf die Stage
- Klick **"Add Field"** für jedes Feld:
#### Field 1: Username
```
Field Name: username
Label: Username
Type: text
Required: Yes
Placeholder: Choose a username
```
#### Field 2: Email
```
Field Name: email
Label: Email Address
Type: email
Required: Yes
Placeholder: your@email.com
```
#### Field 3: Name (Optional)
```
Field Name: name
Label: Full Name
Type: text
Required: No
Placeholder: Your Name
```
Alle Fields **Save**.
Dann **Stage-Binding setzen**:
- Binding: **"Prompt for data"** (oder "User Data")
- Required: **Yes**
- **Save**
### Stage 4: Write Stage (User in DB erstellen)
1. Klick **"Add Stage"**
2. Wähle: **"Write Stage"** (oder "User Write Stage")
3. Konfiguriere:
```
Name: Create User
Order: 4
```
4. **Speichern (Save)**
Dann **Field Bindings setzen**:
- Klick auf die Stage
- Unter "Field Bindings" oder "User Creation":
- `username` ← mapped von username Feld
- `email` ← mapped von email Feld
- `name` ← mapped von name Feld
- **Save**
Stage-Binding setzen:
- Binding: **"Create or update user"**
- Required: **Yes**
- **Save**
### Stage 5: Finish Stage (Abschluss)
1. Klick **"Add Stage"**
2. Wähle: **"Finish Stage"** (oder "User Login")
3. Konfiguriere:
```
Name: Finish
Order: 5
```
4. **Speichern (Save)**
Stage-Binding:
- Binding: **"Finish"** (oder "Complete enrollment")
- Required: **Yes**
- **Save**
---
## Schritt 4: Flow als Standard-Invitation setzen
**Navigation**: Admin → System → Settings
Suche nach "Invitation Flow" oder "Default Flows":
1. Setze **"Invitation Flow"** auf `matrix-invitation`
2. **Save**
Alternativ:
- Admin → Flows & Stages → Flows
- Für jede Invitation/Group:
- Klick auf Group/Invitation
- Setze "Enrollment Flow" auf `matrix-invitation`
---
## Schritt 5: Test mit neuem Einladungslink
1. **Neuen Einladungslink erstellen**:
- Admin → Users & Groups → Invitations
- Klick **"Create"**
- Expiry: 7 days
- **Create & Copy Link**
2. **Link öffnen** (neuer Browser/Inkognito):
- Link in Browser öffnen
- Sollte jetzt alle Felder zeigen:
- [ ] Username eingeben
- [ ] Email eingeben ← sollte jetzt da sein!
- [ ] Name eingeben (optional)
- [ ] "Weiter" oder "Sign in with Authentik"
3. **Authentik Login** (falls Binding korrekt):
- Mit Authentik anmelden
- Enrollment abgeschlossen
- User sollte in Synapse erstellt sein
---
## Troubleshooting
### Fehler: "Stage not found"
- Stelle sicher, dass alle Stages ein **Binding** haben
- Alle Bindings müssen **eindeutig** sein (nicht doppelt)
- **Save** nach jeder Änderung
### Felder werden nicht angezeigt
- Prompt Stage überprüfen
- Alle Fields müssen **Save** sein
- Ggfs. Browser-Cache löschen
### Fehler nach Enrollment
- MAS Logs: `kubectl logs -f matrix-stack-matrix-authentication-service-6b994b9fcf-qqcxz -n matrix`
- Authentik Logs: `kubectl logs -f -n authentik -l app.kubernetes.io/name=authentik`
---
## Erwartetes Ergebnis
Nach dem Fix:
1. Einladungslink öffnen → `matrix-invitation` Flow
2. Username, Email, Name eingeben
3. "Mit Authentik anmelden"
4. Nach Login: User in Synapse erstellt
5. Login zu ElementWeb möglich
---
## Checkliste
- [ ] `matrix-invitation` Flow erstellt
- [ ] 5 Stages in korrekter Reihenfolge (Invite → Identify → Prompt → Write → Finish)
- [ ] Prompt Stage hat username, email, name Felder
- [ ] Alle Stages haben korrektes Binding
- [ ] `matrix-invitation` als Standard-Invitation-Flow gesetzt
- [ ] Neuen Einladungslink erstellt und getestet
- [ ] Test-User kann Email eingeben
- [ ] Test-User in Synapse DB nach Login
---
**Sollte ca. 10-15 Minuten dauern!** 🚀

View File

@ -0,0 +1,314 @@
# ✅ Authentik Enrollment Flow Reparatur-Template
Basierend auf häufigen Problemen: Hier sind die wahrscheinlichsten Fixes.
---
## Problem 1: MAS kennt Authentik-OIDC nicht
### Symptom
- MAS zeigt "Sign in with Authentik" Button nicht
- Logs: "upstream provider not configured"
### Lösung
**MAS Secret muss diesen Block enthalten:**
```yaml
# apps/production/custom-configs/mas-secret.yaml (decrypted)
---
matrixAuthenticationService:
upstream_oauth2_config:
issuer: "https://auth.axion1337.chat/application/o/matrix/"
client_id: "{{ CLIENT_ID_FROM_AUTHENTIK }}"
client_secret: "{{ CLIENT_SECRET_FROM_AUTHENTIK }}"
authorization_endpoint: "https://auth.axion1337.chat/application/o/authorize/"
token_endpoint: "https://auth.axion1337.chat/application/o/token/"
userinfo_endpoint: "https://auth.axion1337.chat/application/o/userinfo/"
scopes:
- "openid"
- "profile"
- "email"
user_mapping_provider:
type: "oidc"
config:
localpart_template: "{{ user.preferred_username }}"
display_name_template: "{{ user.name }}"
email_template: "{{ user.email }}"
# Wichtig: Password-Login deaktivieren (da wir nur OIDC verwenden)
passwords:
enabled: false
```
**Wie ausfüllen:**
1. Authentik Admin UI öffnen: `https://auth.axion1337.chat`
2. Admin → Applications → Providers → "matrix-provider" (oder ähnlich)
3. Folgende Werte kopieren:
- **Client ID**: Im Provider-Details zu sehen
- **Client Secret**: Im Provider-Details zu sehen (unter "Credentials")
4. Local entschlüsseln (mit age-key):
```bash
cd gitops/
sops -d -i apps/production/custom-configs/mas-secret.yaml
```
5. Datei öffnen und die Werte einfügen
6. Wieder verschlüsseln:
```bash
sops -e -i apps/production/custom-configs/mas-secret.yaml
```
7. Commiten:
```bash
git add apps/production/custom-configs/mas-secret.yaml
git commit -m "Fix: Configure MAS upstream OIDC for Authentik"
git push
```
8. Flux triggern:
```bash
flux reconcile kustomization production-apps --with-source
```
9. Warten, dass MAS Pod neu startet:
```bash
kubectl get pods -n matrix -l app=matrix-authentication-service -w
```
---
## Problem 2: Authentik Enrollment Flow ist kaputt
### Symptom
- User kommt zu Authentik-Login
- Nach Login: "Error: Enrollment stage not found" oder ähnlich
- Oder: Flow bricht ohne Fehlermeldung ab
### Lösung
**Authentik UI → Flows & Stages → Enrollment Flow überprüfen:**
```
Flows → Enrollment
├── Stage 1: "Identify" (if not exists)
│ └── Binding: "Identification (if not exists)"
├── Stage 2: "Write" (wichtig!)
│ └── Binding: "Create or update user"
│ └── User Creation Policies: ???
├── Stage 3: (optional) Weitere Datenerfassung
└── Stage 4: "Finish"
```
**Häufiger Fehler**: "Write" Stage ist nicht korrekt mit den benötigten Feldern konfiguriert.
**Fix:**
1. Authentik Admin UI: `https://auth.axion1337.chat`
2. **Flows & Stages** → **Stages**
3. Nach "Write" Stage suchen (Filter: "write")
4. Klick auf "Write Stage"
5. **Field Bindings** überprüfen:
- [ ] `username` ← MUSS mit Authentik Username bindbar sein
- [ ] `email` ← MUSS vorhanden sein
- [ ] `name` ← Optional, aber empfohlen
6. Alle sollten "required" sein (nicht optional)
7. **Save**
Dann zurück zu **Flows****Enrollment**:
1. Stages überprüfen (oben)
2. Bindings überprüfen:
- Each Stage hat "Binding" Feld
- "Write" Stage sollte mit "Create or update user" gebunden sein
3. **Save**
---
## Problem 3: OIDC Token werden nicht korrekt zu Synapse weitergeleitet
### Symptom
- User kommt bis zu ElementWeb
- Nach Login zu Authentik: "User not found in Synapse" oder Loop
- Oder: User wird in Authentik angelegt, aber nicht in Synapse
### Lösung
Das ist komplexer und erfordert MAS-Konfiguration + Synapse-Konfiguration.
**MAS Config (upstream_oauth2_config)** muss korrekt sein (siehe Problem 1).
**Zusätzlich in MAS Secret:**
```yaml
# apps/production/custom-configs/mas-secret.yaml
matrixAuthenticationService:
# ... upstream_oauth2_config ...
# User-Provisioning Konfiguration
access:
# Benutzer aus OIDC Provider automatisch erzeugen
auto_provision: true
# Synapse URL
home_server: "https://matrix.axion1337.chat"
```
---
## Problem 4: ElementWeb zeigt nicht automatisch OIDC-Button
### Symptom
- MAS läuft und hat OIDC konfiguriert
- ElementWeb zeigt nur "Sign in with username" oder "SAML login"
- Kein "Sign in with Authentik" Button
### Lösung
ElementWeb muss die MAS-Konfiguration kennen. Das geschieht über `.well-known/matrix/client`:
**Test:**
```bash
curl https://axion1337.chat/.well-known/matrix/client | jq '.authentication'
```
Sollte zurückgeben:
```json
{
"flows": [
{
"stages": ["m.login.sso"]
}
],
"identity_providers": [
{
"id": "authentik",
"name": "Authentik",
"icon": "...",
"brand": "custom"
}
]
}
```
Falls nicht: **ElementWeb Config in Element-Stack aktualisieren:**
```yaml
# apps/production/custom-configs/element-values.yaml
elementWeb:
config:
auth:
sso_redirect_options:
immediate: false
on_welcome_page: true
```
**Dann:**
```bash
git add apps/production/custom-configs/element-values.yaml
git commit -m "Fix: Enable SSO redirect in ElementWeb"
git push
flux reconcile kustomization production-apps --with-source
```
---
## Problem 5: User kann sich anmelden, aber Boje ist nicht in Matrix
### Symptom
- Authentik-Login funktioniert
- MAS zeigt User erfolgreich
- ElementWeb Login funktioniert
- **ABER**: User ist nicht in Synapse (check mit `kubectl exec -n matrix synapse ...`)
### Lösung
Das bedeutet: User wird nicht automatisch in Synapse provisioniert.
**MAS muss User zu Synapse erstellen:**
In MAS Secret, `access` Sektion:
```yaml
matrixAuthenticationService:
access:
# Synapse erlaubt neue User-Erstellung
homeserver: "https://matrix.axion1337.chat"
# Optional: User automatisch erstellen
registration_enabled: true
```
**Synapse-seitig** muss auch User-Erstellung erlaubt sein:
```yaml
# apps/production/custom-configs/synapse-values.yaml
synapse:
additional:
registration:
config: |
enable_registration: true
enable_registration_without_token: false
# Token wird von MAS bereitgestellt
```
---
## Komplettes Test-Szenario
Nach allen Fixes:
1. **Browser 1**: `https://axion1337.chat` öffnen
2. Auf ElementWeb "Sign in" klicken
3. "Sign in with Authentik" klicken (sollte sichtbar sein)
4. Authentik-Login durchführen (akadmin)
5. Nach Login: Enrollment-Flow (nur falls neuer User)
6. Zurück zu ElementWeb
7. **Synapse prüfen**:
```bash
kubectl exec -it -n matrix deployment/synapse -- \
/usr/local/bin/psql -U synapse -d synapse -c "SELECT name, admin FROM users LIMIT 10;"
```
8. Neuer User sollte auftauchen
---
## Debugging-Commands (während Test)
```bash
# Live MAS logs (folgen)
kubectl logs -n matrix -l app=matrix-authentication-service -f
# Authentik logs
kubectl logs -n authentik -l app.kubernetes.io/name=authentik -f
# Port-Forward für manuelles Testen
kubectl port-forward -n matrix svc/matrix-authentication-service 8765:8080
# MAS Secret auslesen (im Cluster)
kubectl get secret ess-mas-values-secret -n matrix -o jsonpath='{.data.values\.yaml}' | base64 -d
# Synapse User-Liste
kubectl exec -it -n matrix deployment/synapse -- \
/usr/local/bin/psql -U synapse -d synapse -c "SELECT name, admin, is_guest FROM users;"
```
---
## Checkliste für erfolgreichen Fix
- [ ] MAS Secret decrypted, upstream_oauth2_config eingetragen
- [ ] Client ID + Secret von Authentik kopiert
- [ ] MAS Secret re-encrypted und commited
- [ ] Authentik Enrollment Flow überprüft
- [ ] OIDC Provider in Authentik aktiv
- [ ] OIDC Application "matrix" in Authentik existiert
- [ ] MAS Pod neu gestartet (nach Secret-Change)
- [ ] ElementWeb zeigt OIDC-Button
- [ ] Test-Login durchgeführt
- [ ] Neuer User in Synapse DB vorhanden
---
**Fragen?** → Siehe `DIAGNOSTIK-AUTHENTIK-FLOW.md` für tiefergehende Diagnose.

View File

@ -0,0 +1,244 @@
# 🔧 Authentik Invitation Flow Fix Für Einladungslinks
**Problem**:
- Standard Enrollment (akadmin): ✅ funktioniert
- Invitation Flow (Boje über Einladungslink): ❌ Nur Username gefragt, keine Email
- Nach Enrollment: "Fehler fehlende Rechte"
**Root Cause**: Invitation Flow erfasst nicht alle erforderlichen Felder (Email) für OIDC-Token-Generation.
---
## Phase 1: Diagnose im Authentik Admin UI
```bash
# Authentik Admin UI öffnen
kubectl port-forward -n authentik svc/authentik 9000:9000
# Browser: http://localhost:9000/
# Admin credentials: akadmin / (password)
```
### 1.1 Überprüfe: Welche Flows existieren?
**Navigation**: Admin → Flows & Stages → Flows
Suche nach diesen Flows:
- [ ] `enrollment` Standard Enrollment (für akadmin)
- [ ] `invitation` Invitation Flow (für Einladungslinks)
- [ ] `default-authentication-flow` Standard Login
### 1.2 Überprüfe: Standard Enrollment Flow (funktioniert)
**Navigation**: Flows → `enrollment` öffnen
**Stages sollten sein:**
```
1. Identify (if not exists)
└─ Binding: "Identification (if not exists)"
2. Write
└─ Binding: "Create or update user"
└─ Field bindings MUST include:
├─ username
├─ email ← WICHTIG
└─ name (optional)
3. (optional) Weitere Stages
4. Finish
```
**Wichtig**: Alle Felder müssen "required" sein (nicht optional).
### 1.3 Überprüfe: Invitation Flow (wahrscheinlich kaputt)
**Navigation**: Flows → `invitation` öffnen
**Problem**: Wahrscheinlich fehlt die "Email" Stage hier!
**Sollte sein:**
```
1. Invite Stage
└─ Binding: "Invite user"
2. Identification (if not exists)
└─ Binding: "Identify"
3. Prompt Stage (für zusätzliche Daten!)
└─ Binding: "Prompt for data"
└─ Fields: username, email, name, password
4. Write
└─ Binding: "Create or update user"
5. Finish
```
---
## Phase 2: Reparatur der Invitation Flow
### Schritt 1: Neue "Prompt Stage" erstellen (falls nicht existiert)
**Navigation**: Admin → Flows & Stages → Stages
1. Klick "Create"
2. Name: `invitation-prompt` oder ähnlich
3. Type: **"Prompt Stage"**
4. Configure:
- [ ] **Fields to Prompt**:
- Username (required)
- Email (required) ← WICHTIG
- Name (optional)
- Password (optional, da OIDC)
5. Save
### Schritt 2: Invitation Flow reparieren
**Navigation**: Admin → Flows & Stages → Flows → `invitation`
**Stages in dieser Reihenfolge:**
```
Stage 1: Invite Stage
├─ Binding: "Invite"
├─ Required: Yes
Stage 2: Identification Stage
├─ Binding: "Identify" (oder "Identification (if not exists)")
├─ Required: No
Stage 3: [NEUE STAGE] Prompt für Email/Username
├─ Type: "Prompt Stage"
├─ Binding: "Prompt for data"
├─ Fields:
│ ├─ username (required)
│ ├─ email (required) ← ENTSCHEIDEND
│ └─ name (optional)
├─ Required: Yes
Stage 4: Write
├─ Binding: "Create or update user"
├─ User Creation Policies: (standard)
├─ Required: Yes
Stage 5: Finish
├─ Binding: "Finish"
├─ Required: Yes
```
**Speichern** und Testen!
---
## Phase 3: Teste Invitation Flow
### Test 1: Neuen Einladungslink erstellen
**Navigation**: Admin → Users & Groups → Invitations
1. Klick "Create"
2. Expiry: 7 days
3. Create & Copy Link
### Test 2: Einladungslink öffnen (in neuem Browser/Inkognito)
1. Link öffnen
2. Enrollment Flow sollte jetzt:
- [ ] Username eingeben
- [ ] **Email eingeben** ← Das sollte jetzt da sein!
- [ ] Name eingeben (optional)
- [ ] "Sign in with Authentik" klicken (falls Authentik-Binding korrekt)
3. Nach Authentik-Login: User in Synapse erstellt?
```bash
kubectl exec -it -n matrix matrix-stack-postgres-0 -- \
psql -U synapse -d synapse -c "SELECT name FROM users WHERE created_ts > now() - interval '5 minutes';"
```
### Test 3: Prüfe MAS Logs auf Fehler
```bash
kubectl logs -f matrix-stack-matrix-authentication-service-6b994b9fcf-qqcxz -n matrix | grep -i "error\|fail\|boje"
```
---
## Phase 4: Häufige Fehler & Lösungen
### Fehler 1: "Fehlende Rechte" nach Enrollment
**Symptom**: Enrollment abgeschlossen, aber Fehler auf Berechtigungsseite
**Ursachen**:
- [ ] Email-Feld wurde nicht erfasst
- [ ] OIDC-Token hat unvollständige Daten
- [ ] Synapse User konnte nicht erstellt werden (Duplikat?)
**Lösung**:
1. Authentik Logs prüfen: `kubectl logs -n authentik -l app.kubernetes.io/name=authentik -f | grep -i "error\|invitation"`
2. MAS Logs prüfen: `kubectl logs -f matrix-stack-matrix-authentication-service-6b994b9fcf-qqcxz -n matrix | grep -i "boje\|error"`
3. Synapse Logs prüfen: `kubectl logs -f -n matrix matrix-stack-synapse-0 | grep -i "boje\|register"`
### Fehler 2: "Stage not found" oder "Flow invalid"
**Ursache**: Invitation Flow hat Binding-Fehler
**Lösung**:
1. Admin UI → Flows → Invitation Flow öffnen
2. Alle Stages überprüfen, dass sie korrekt gebunden sind
3. Keine leeren/ungültigen Bindings
4. Save & Retry
### Fehler 3: Email-Feld wird nicht angezeigt
**Ursache**: Prompt Stage hat email nicht in Fields
**Lösung**:
1. Admin UI → Flows → Stages → Prompt Stage öffnen
2. Edit → Fields überprüfen
3. Email hinzufügen if missing:
- Field name: `email`
- Type: `email`
- Required: Yes
4. Save
---
## Erwarteter Ablauf nach Fix
1. Browser öffnet Einladungslink → Enrollment Flow
2. "Username eingeben" → z.B. "boje"
3. **"Email eingeben"** ← Sollte jetzt da sein
4. "Name eingeben" (optional)
5. "Weiter" oder "Mit Authentik anmelden"
6. Authentik Login
7. Enrollment abgeschlossen
8. User "boje" in Synapse DB angelegt
9. Login zu ElementWeb möglich
---
## Checkliste
- [ ] Authentik Admin UI geöffnet (port-forward 9000)
- [ ] Standard Enrollment Flow überprüft (funktioniert mit akadmin)
- [ ] Invitation Flow überprüft
- [ ] Prompt Stage existiert mit email field
- [ ] Invitation Flow hat alle 5 Stages in korrekter Reihenfolge
- [ ] Neuen Einladungslink erstellt und getestet
- [ ] Test-User hat Email eingeben können
- [ ] Test-User in Synapse DB nach Login
- [ ] MAS Logs zeigen keine Fehler
---
**Frage**: Stimmt das mit deiner Beobachtung überein - dass bei der Einladung **nur Username** gefragt wurde, aber **nicht die Email**?
Wenn ja, dann ist der Fix:
1. Prompt Stage erstellen/reparieren (mit email field)
2. Zur Invitation Flow hinzufügen
3. Testen
Soll ich dir noch mehr Detailschritte geben?

View File

@ -0,0 +1,261 @@
# 🔍 Authentik Enrollment Flow Diagnostik & Reparaturplan
**Symptom**:
- `akadmin` wurde manuell in Matrix-DB angelegt (funktioniert)
- `Boje` wurde nur in Authentik erstellt, nicht in Matrix-DB (kaputt)
- Beide sollen denselben Enrollment Flow verwenden
**Vermutung**: Die Authentik → MAS → Synapse Kette ist unterbrochen
---
## Phase 1: Diagnose (Bestandsaufnahme)
### 1.1 Authentik Logs prüfen
```bash
# Authentik Server logs
kubectl logs -n authentik -l app.kubernetes.io/name=authentik -f | grep -i "oauth\|oidc\|enroll\|flow"
# Worker logs
kubectl logs -n authentik -l app.kubernetes.io/component=worker -f | grep -i "enroll"
```
**Worauf achten**:
- Fehler bei "Enrollment create"?
- OIDC Token-Probleme?
- Flow-Validierungsfehler?
### 1.2 MAS (Matrix Authentication Service) Logs prüfen
```bash
# MAS logs
kubectl logs -n matrix -l app=matrix-authentication-service -f | grep -i "oauth\|upstream\|user\|oidc"
```
**Worauf achten**:
- Verbindung zu Authentik erfolgreich?
- Token-Validierung fehlgeschlagen?
- User-Provisioning-Fehler?
### 1.3 Synapse Logs prüfen
```bash
# Synapse logs (für User-Erstellung)
kubectl logs -n matrix -l app=synapse -f | grep -i "user\|provision\|register\|auth"
```
**Worauf achten**:
- User-Registrierungs-Fehler?
- Provisioning-Fehler?
- Authentifizierungsprobleme?
---
## Phase 2: Authentik UI Überprüfung
### 2.1 Enrollment Flow inspizieren
```bash
# Authentik UI öffnen
kubectl port-forward -n authentik svc/authentik 9000:9000
# → Browser: http://localhost:9000
# → Admin UI → Flows & Stages → "Enrollment" Flow suchen
```
**Checklist**:
- [ ] Flow existiert und heißt "Enrollment"
- [ ] Reihenfolge der Stages:
1. Identify (optional)
2. Write (User-Erstellung)
3. Enrollment (if-condition für neuen User)
4. Verification (optional)
- [ ] "Write Stage" bindet sich an:
- [ ] Username
- [ ] Email
- [ ] Name
- [ ] Alle Bindings sind "required" (nicht optional)
### 2.2 OIDC Provider in Authentik prüfen
```bash
# Über Authentik UI:
# Admin → Applications → Providers → "matrix-provider" (oder ähnlich)
```
**Checklist**:
- [ ] Provider existiert
- [ ] Name: z.B. "matrix-provider"
- [ ] Client Type: "Confidential"
- [ ] Redirect URIs enthalten:
- [ ] `https://account.axion1337.chat/upstream/callback/*`
- [ ] `https://account.axion1337.chat/upstream/callback/01KQDJTR1ZVTG8JQ220F5BNBFZ` (exact)
- [ ] Scopes: `openid profile email`
- [ ] Client ID + Secret kopiert?
### 2.3 OIDC Application in Authentik
```bash
# Admin → Applications → Applications → "matrix"
```
**Checklist**:
- [ ] Application existiert mit Slug "matrix"
- [ ] Provider ist zugewiesen
- [ ] Enrollment Flow ist zugewiesen (nicht "deny")
- [ ] Enrollment Flow ist die richtige (die von oben)
### 2.4 Test-User "Boje" inspizieren
```bash
# Admin → Directory → Users → "Boje"
```
**Checklist**:
- [ ] Username: `boje`
- [ ] Email: `boje@...` (vorhanden?)
- [ ] Groups: Falls erforderlich, die richtigen Groups zugewiesen?
- [ ] Status: Active oder Disabled?
- [ ] Sessions: Aktive Logins?
---
## Phase 3: MAS Konfiguration überprüfen
### 3.1 Current MAS Secret auslesen
Da der age-key nicht lokal verfügbar ist, müssen wir die Konfiguration im Cluster prüfen:
```bash
# MAS Config im Cluster auslesen (nicht verschlüsselt)
kubectl get secret ess-mas-values-secret -n matrix -o jsonpath='{.data.values\.yaml}' | base64 -d | yq . | head -100
```
**Worauf achten**:
- [ ] `upstream_oauth2_config` Block existiert
- [ ] `upstream_oauth2_config.issuer`: `https://auth.axion1337.chat/application/o/matrix/`
- [ ] `upstream_oauth2_config.client_id`: Authentik Client ID
- [ ] `upstream_oauth2_config.client_secret`: Authentik Client Secret (*)
- [ ] `upstream_oauth2_config.scopes`: `["openid", "profile", "email"]`
- [ ] `upstream_oauth2_config.user_mapping_provider`:
- `type`: "oidc"
- `config.localpart_template`: `{{ user.preferred_username }}`
- `config.display_name_template`: `{{ user.name }}`
- `config.email_template`: `{{ user.email }}`
### 3.2 MAS Pod exec Config live prüfen
```bash
# MAS Config im laufenden Pod inspizieren
kubectl exec -it -n matrix deployment/matrix-authentication-service -- cat /etc/mas/config.yaml | grep -A50 upstream_oauth2_config
```
**Worauf achten**:
- Config ist syntaktisch korrekt (YAML)?
- Indentierung ist richtig?
- Werte sind vorhanden?
### 3.3 MAS OIDC Discovery prüfen
```bash
# Authentik OIDC Discovery Endpoint
curl -s https://auth.axion1337.chat/application/o/matrix/.well-known/openid-configuration | jq .
# Sollte zurückgeben:
# {
# "issuer": "https://auth.axion1337.chat/application/o/matrix/",
# "token_endpoint": "https://auth.axion1337.chat/application/o/token/",
# "authorization_endpoint": "...",
# ...
# }
```
---
## Phase 4: Login-Flow Testen
### 4.1 MAS Login UI öffnen
```bash
# Port-Forward zu MAS
kubectl port-forward -n matrix svc/matrix-authentication-service 8765:8080
# → Browser: http://localhost:8765
```
**Test**:
1. Auf MAS-Seite: "Sign in with Authentik" klicken
2. Authentik-Login durchführen
3. Auf Enrollment Flow warten
4. Neuen User erstellen (Test-Username, Email, Password)
5. Nach erfolgreicher Registrierung: Matrix home_server erhalten?
### 4.2 Fehlerberichte
Falls Fehler auftritt:
- [ ] Screenshot des Fehlers
- [ ] MAS logs auslesen: `kubectl logs -n matrix -l app=matrix-authentication-service --tail=50`
- [ ] Authentik logs auslesen: `kubectl logs -n authentik -l app.kubernetes.io/name=authentik --tail=50`
---
## Phase 5: Reparaturschritte (nachdem Diagnose klar ist)
### Falls MAS-Config fehlerhaft:
```bash
# 1. Secrets entschlüsseln (lokale Umgebung mit age-key erforderlich)
sops -d apps/production/custom-configs/mas-secret.yaml > /tmp/mas-secret-decrypted.yaml
# 2. Editor öffnen und Konfiguration reparieren
vim /tmp/mas-secret-decrypted.yaml
# → upstream_oauth2_config überprüfen und korrigieren
# 3. Wieder verschlüsseln
sops -e /tmp/mas-secret-decrypted.yaml > apps/production/custom-configs/mas-secret.yaml
# 4. Commiten
git add apps/production/custom-configs/mas-secret.yaml
git commit -m "Fix: Correct MAS upstream_oauth2_config for Authentik integration"
# 5. Flux triggern
flux reconcile kustomization production-apps --with-source
```
### Falls Authentik Enrollment Flow fehlerhaft:
1. Admin UI öffnen: `kubectl port-forward -n authentik svc/authentik 9000:9000`
2. Flows → Enrollment Flow öffnen
3. Stages überprüfen und in richtige Reihenfolge bringen:
- **Identify**: Benutzer identifizieren
- **Write**: Benutzer in DB speichern
- **Enrollment**: Weitere Felder (optional)
- **Finish**: Abschluss
4. Speichern
5. Neuen Test-User erstellen und Enrollment durchlaufen
---
## Erwartete Endergebnisse
Nach erfolgreichem Fix:
1. Benutzer klickt "Sign in with Authentik" auf MAS
2. Authentik-Login-Seite wird angezeigt
3. Nach Login: Enrollment Flow wird angezeigt
4. User füllt Formular aus
5. Nach "Finish": Authentik erstellt User UND verbindet zu Matrix
6. User wird in Matrix-DB angelegt (`_matrix_auth` prefix)
7. User kan sich bei ElementWeb anmelden
---
## 🎯 Nächster Schritt
Bitte folgende Diagnostik durchlaufen und mir die Output berichte:
1. **MAS Logs** (letzten 30 Zeilen)
2. **Authentik Logs** (letzten 30 Zeilen)
3. **MAS Secret (entschlüsselt)** upstream_oauth2_config Block
4. **Authentik OIDC Discovery** Output
5. **Screenshots** der Authentik UI (Enrollment Flow, OIDC Provider, Application)
Damit kann ich dann genau sehen, wo der Bruch in der Kette ist! 🔗

View File

@ -0,0 +1,112 @@
# 🔧 Troubleshooting Guides
Dieser Ordner enthält detaillierte Troubleshooting- und Reparaturanleitungen für häufige Probleme bei der Authentik/MAS/Matrix Integration.
---
## 📖 Guides
### 1. **DIAGNOSTIK-AUTHENTIK-FLOW.md**
**Für**: Vollständige Diagnose des Authentik Enrollment Flows
**Wann**: Wenn Sie systematisch überprüfen möchten, ob die gesamte OIDC-Kette (Authentik → MAS → Synapse) funktioniert
**Umfasst**:
- Authentik Logs analysieren
- MAS Konfiguration überprüfen
- OIDC Discovery testen
- Enrollment Flow inspizieren
- Fehlersuche mit Debugging-Commands
**Status**: Nutzer Boje - Nur in Authentik erstellt, nicht in Synapse
---
### 2. **AUTHENTIK-FIX-TEMPLATE.md**
**Für**: Konkrete Reparaturen bei MAS/Authentik Integration
**Wann**: Wenn Sie wissen, welches Problem Sie haben und schnelle Lösungen suchen
**Behandelt**:
- Problem 1: MAS kennt Authentik-OIDC nicht
- Problem 2: Authentik Enrollment Flow kaputt
- Problem 3: OIDC Token werden nicht weitergeleitet
- Problem 4: ElementWeb zeigt keinen OIDC-Button
- Problem 5: User in Authentik aber nicht in Synapse
**Status**: Best Practices für häufige Probleme
---
### 3. **AUTHENTIK-INVITATION-FLOW-FIX.md**
**Für**: Reparatur des Invitation Flows bei Einladungslinks
**Wann**: Wenn Nutzer via Einladungslink nicht korrekt erstellt werden
**Problem**: Invitation Flow erfasst nur Username, nicht Email/Name
**Lösung**:
- Prompt Stage mit Email-Feld erstellen/reparieren
- Zur Invitation Flow hinzufügen
- Testen mit neuem Einladungslink
**Status**: Nutzer Klaus - Fehler "kein ausstehender benutzer Anfrage wurde verweigert"
---
### 4. **AUTHENTIK-CREATE-INVITATION-FLOW.md** ⭐ **WICHTIGSTE ANLEITUNG**
**Für**: Neuen separaten Invitation Flow erstellen
**Wann**: Wenn nur ein `matrix-enrollment` Flow existiert (Standard + Invitations gemeinsam)
**Root Cause**: Flow-Konflikt durch gemeinsamen Flow
**Lösung** (Schritt-für-Schritt):
1. Neuen Flow `matrix-invitation` erstellen
2. 5 Stages konfigurieren (Invite → Identify → Prompt → Write → Finish)
3. Email-Feld in Prompt Stage hinzufügen
4. Invitations auf neuen Flow setzen
5. Testen
**Zeitaufwand**: ~20 Minuten
**Status**: Aktuell für Klaus/Boje notwendig
---
## 🎯 Schneller Einstieg
### Szenario 1: "Enrollment funktioniert nicht, ich weiß nicht warum"
**Start**: `DIAGNOSTIK-AUTHENTIK-FLOW.md`
### Szenario 2: "Einladungslink funktioniert nicht"
**Start**: `AUTHENTIK-CREATE-INVITATION-FLOW.md` (wenn nur ein Flow existiert)
→ oder `AUTHENTIK-INVITATION-FLOW-FIX.md` (wenn zwei Flows existieren)
### Szenario 3: "Ich kenne das Problem und brauche Lösungen"
**Start**: `AUTHENTIK-FIX-TEMPLATE.md`
### Szenario 4: "Alles ist kaputt, ich brauche alles Schritt-für-Schritt"
**Start**: `AUTHENTIK-CREATE-INVITATION-FLOW.md``AUTHENTIK-FIX-TEMPLATE.md``DIAGNOSTIK-AUTHENTIK-FLOW.md`
---
## 📋 Bekannte Probleme
| Problem | Nutzer | Guide | Status |
|---------|--------|-------|--------|
| Nur Standard Enrollment funktioniert | akadmin ✅ | - | Resolved |
| User nur in Authentik, nicht in Synapse | Boje | `DIAGNOSTIK-AUTHENTIK-FLOW.md` | In Progress |
| Einladungslink-Fehler: "kein ausstehender benutzer" | Klaus | `AUTHENTIK-CREATE-INVITATION-FLOW.md` | In Progress |
| OIDC-Integration unklar | General | `AUTHENTIK-FIX-TEMPLATE.md` | Reference |
---
## 🔗 Verwandte Dokumentation
- `../README.md` Hauptdokumentation & Architektur
- `../TASKS.md` Aufgabenliste & Meilensteine
- `../deployment-guides/` Deployment-Anleitungen für andere Components
---
## 💡 Tipps
- **Immer Logs überprüfen** bevor man herumrät: `kubectl logs -f -n <namespace> <pod>`
- **Browser-Cache löschen** nach Authentik-Änderungen
- **Port-Forward nutzen** für lokales Testen: `kubectl port-forward -n authentik svc/authentik 9000:9000`
- **Kleine Tests machen** (einen User mit Invitation testen, nicht 10 auf einmal)
---
**Zuletzt aktualisiert**: 2026-05-18
**Verfasser**: Claude Code + Thore

41
scripts/hooks/pre-commit Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/env bash
# GitOps ConfigMap Checksum Hook
# Automatically updates checksum annotations in kustomization.yaml when ConfigMaps change.
# This ensures Flux CD re-deploys the HelmRelease when external ConfigMap sources are modified.
#
# See: docs/ops-configmap-sync.md
set -euo pipefail
REPO_ROOT="$(git rev-parse --show-toplevel)"
ELEMENT_VALUES="$REPO_ROOT/apps/production/custom-configs/element-values.yaml"
SYNAPSE_VALUES="$REPO_ROOT/apps/production/custom-configs/synapse-values.yaml"
KUSTOMIZATION="$REPO_ROOT/apps/production/kustomization.yaml"
# Function to calculate MD5 hash (handles both GNU md5sum and BSD md5)
get_md5() {
local file="$1"
if command -v md5sum &> /dev/null; then
md5sum "$file" | awk '{print $1}'
elif command -v md5 &> /dev/null; then
md5 -q "$file"
else
echo "ERROR: Neither md5sum nor md5 found" >&2
exit 1
fi
}
# Update checksums for ConfigMaps that exist and are staged
if git diff --cached --name-only | grep -q "element-values.yaml"; then
ELEMENT_HASH=$(get_md5 "$ELEMENT_VALUES")
sed -i.bak "s/value: \"[0-9a-f]\{32\}\" *# element-config/value: \"$ELEMENT_HASH\" # element-config/" "$KUSTOMIZATION"
rm -f "$KUSTOMIZATION.bak"
git add "$KUSTOMIZATION"
fi
if git diff --cached --name-only | grep -q "synapse-values.yaml"; then
SYNAPSE_HASH=$(get_md5 "$SYNAPSE_VALUES")
sed -i.bak "s/value: \"[0-9a-f]\{32\}\" *# synapse-config/value: \"$SYNAPSE_HASH\" # synapse-config/" "$KUSTOMIZATION"
rm -f "$KUSTOMIZATION.bak"
git add "$KUSTOMIZATION"
fi

27
scripts/install-hooks.sh Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env bash
# Install Git Hooks for GitOps automation
# Must be run after cloning the repository
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
echo "❌ Not in a git repository"
exit 1
}
HOOKS_DIR="$REPO_ROOT/.git/hooks"
HOOK_SOURCE="$REPO_ROOT/scripts/hooks/pre-commit"
HOOK_DEST="$HOOKS_DIR/pre-commit"
# Verify source exists
if [ ! -f "$HOOK_SOURCE" ]; then
echo "❌ Hook source not found: $HOOK_SOURCE"
exit 1
fi
# Create symlink (force if exists)
mkdir -p "$HOOKS_DIR"
ln -sf "../../scripts/hooks/pre-commit" "$HOOK_DEST"
chmod +x "$HOOK_SOURCE"
echo "✅ Git hooks installed:"
echo " • pre-commit: ConfigMap checksum auto-update"
echo " See: docs/ops-configmap-sync.md"