Compare commits
26 Commits
M7-Impleme
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bbb03bc52 | ||
|
|
af13688993 | ||
|
|
f70e77127e | ||
|
|
f658ce2980 | ||
|
|
b29c7516d4 | ||
|
|
c32f951716 | ||
|
|
cdfbf7de98 | ||
|
|
b1247b4720 | ||
|
|
6bcbe9cc9e | ||
|
|
b8da70b14b | ||
|
|
4cf6702f85 | ||
|
|
aee9a34369 | ||
|
|
e6ef29c1e9 | ||
|
|
857c3965ef | ||
|
|
d37a65f4fa | ||
|
|
e6abd0fb3f | ||
|
|
d3362180ea | ||
|
|
5f50a60071 | ||
|
|
174e9721ed | ||
|
|
5f14376bdb | ||
|
|
81a30e21b9 | ||
| f81fda12d4 | |||
| fe0165a509 | |||
|
|
dc17158fe2 | ||
|
|
0c81de057f | ||
| aaa197fbb5 |
56
.devcontainer/Dockerfile
Normal file
56
.devcontainer/Dockerfile
Normal 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
203
.devcontainer/README.md
Normal 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`
|
||||||
65
.devcontainer/devcontainer.json
Normal file
65
.devcontainer/devcontainer.json
Normal 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": []
|
||||||
|
}
|
||||||
35
.devcontainer/postCreateCommand.sh
Executable file
35
.devcontainer/postCreateCommand.sh
Executable 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!"
|
||||||
50
.gitea/workflows/deploy-on-push.yml
Normal file
50
.gitea/workflows/deploy-on-push.yml
Normal 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
|
||||||
|
|
||||||
32
.gitea/workflows/milestone-release.yml
Normal file
32
.gitea/workflows/milestone-release.yml
Normal 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
|
||||||
|
|
||||||
@ -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.
|
||||||
|
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
186
apps/production/custom-configs/element-values copy.yaml
Normal file
186
apps/production/custom-configs/element-values copy.yaml
Normal 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"
|
||||||
@ -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",
|
||||||
@ -184,4 +183,10 @@ data:
|
|||||||
"#b16286",
|
"#b16286",
|
||||||
"#689d6a",
|
"#689d6a",
|
||||||
"#a89984",
|
"#a89984",
|
||||||
"#d65d0e"
|
"#d65d0e"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
520
docs/TASKS.md
Normal 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 | 1–2 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: 2–3 days
|
||||||
|
- Priority: CRITICAL (disaster recovery)
|
||||||
|
- **Status**: NEXT
|
||||||
|
|
||||||
|
### 🟠 **NEXT 1–2 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: 2–3 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: 1–2 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 (1d–1y 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: 2–3 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: 1–2 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: 2–3 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: 1–2 days
|
||||||
|
- Priority: **MEDIUM** (ops safety)
|
||||||
|
|
||||||
|
- [ ] **Content Scanner for Media**
|
||||||
|
- matrix-content-scanner + ClamAV antivirus
|
||||||
|
- Scan uploaded media for malware
|
||||||
|
- Block suspicious files
|
||||||
|
- Est. Effort: 1–2 days
|
||||||
|
- Priority: **LOW–MEDIUM** (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: 2–3 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: **LOW–MEDIUM** (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 | ~1–2 days |
|
||||||
|
| **M5: Production-Ready** | DB Backups, NetworkPolicies, Security Hardening | 📋 Backlog | ~2–3 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 1–2 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
|
||||||
54
docs/deployment-guides/01-turn-server-setup.md
Normal file
54
docs/deployment-guides/01-turn-server-setup.md
Normal 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.
|
||||||
45
docs/deployment-guides/02-authentik-identity-provider.md
Normal file
45
docs/deployment-guides/02-authentik-identity-provider.md
Normal 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.
|
||||||
52
docs/deployment-guides/03-monitoring-integration.md
Normal file
52
docs/deployment-guides/03-monitoring-integration.md
Normal 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.
|
||||||
57
docs/deployment-guides/04-element-customization.md
Normal file
57
docs/deployment-guides/04-element-customization.md
Normal 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.
|
||||||
82
docs/deployment-guides/05-room-policies.md
Normal file
82
docs/deployment-guides/05-room-policies.md
Normal 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.
|
||||||
92
docs/deployment-guides/README.md
Normal file
92
docs/deployment-guides/README.md
Normal 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
117
docs/oldwiki/authentik.md
Normal 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. citeturn31view0turn7view2turn14view1turn23search0
|
||||||
|
|
||||||
|
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. citeturn19search0turn28search0turn28search1turn28search2
|
||||||
|
|
||||||
|
## 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. citeturn21view0turn21view3turn14view1
|
||||||
|
|
||||||
|
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. citeturn24search0turn14view0
|
||||||
|
|
||||||
|
## 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. citeturn19search0turn28search0turn28search2
|
||||||
|
|
||||||
|
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. citeturn21view1turn21view2turn30search3
|
||||||
|
|
||||||
|
## 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. citeturn31view0turn14view2turn14view1turn7view2
|
||||||
|
|
||||||
|
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. citeturn34view0turn25search1
|
||||||
|
|
||||||
|
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. citeturn26view0
|
||||||
|
|
||||||
|
## 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. citeturn34view0turn35view0
|
||||||
|
|
||||||
|
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. citeturn14view1turn26view3turn35view1
|
||||||
|
|
||||||
|
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. citeturn7view2
|
||||||
|
|
||||||
|
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`. citeturn14view1turn14view0turn13view5turn7view2
|
||||||
|
|
||||||
|
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. citeturn21view1turn21view2
|
||||||
|
|
||||||
|
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. citeturn15view4turn26view0
|
||||||
|
|
||||||
|
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. citeturn26view2turn14view0
|
||||||
|
|
||||||
|
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. citeturn27search1turn13view5
|
||||||
|
|
||||||
|
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. citeturn26view0turn35view1
|
||||||
|
|
||||||
|
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. citeturn7view2turn13view0turn13view1turn13view2
|
||||||
|
|
||||||
|
## 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. citeturn7view2turn31view0turn14view1
|
||||||
|
|
||||||
|
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. citeturn19search0turn28search0turn28search2
|
||||||
|
|
||||||
|
## 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. citeturn7view2turn14view1
|
||||||
327
docs/oldwiki/fix report mrtc.md
Normal file
327
docs/oldwiki/fix report mrtc.md
Normal 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
12083
docs/oldwiki/home.md
Normal file
File diff suppressed because it is too large
Load Diff
498
docs/oldwiki/invitereg.md
Normal file
498
docs/oldwiki/invitereg.md
Normal 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. citeturn1view2turn20view1turn26search11turn26search5turn35view0
|
||||||
|
|
||||||
|
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. citeturn16view0turn16view1turn16view2turn34view0turn35view0turn17search0turn17search2
|
||||||
|
|
||||||
|
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. citeturn20view1turn23view0turn23view3turn25search0turn25search13
|
||||||
|
|
||||||
|
## 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. citeturn1view2turn1view5turn31view1turn35view0turn24search0
|
||||||
|
|
||||||
|
```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. citeturn16view0turn16view1turn16view5
|
||||||
|
|
||||||
|
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 citeturn20view1turn12view0turn37view1turn1view2 |
|
||||||
|
| 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 citeturn36search0turn36search1 |
|
||||||
|
| Manuelle Admin-Erstellung | Solide als Fallback | Maximal kontrolliert, kein Self-Service nötig | Kein Selbstregistrierungsfluss, hoher Betriebsaufwand | Break-glass, Admin-/Testkonten citeturn27view1turn26search5 |
|
||||||
|
|
||||||
|
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. citeturn17search0turn17search2
|
||||||
|
|
||||||
|
## 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`. citeturn1view2turn31view1
|
||||||
|
|
||||||
|
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. citeturn2view4turn20view0turn1view2
|
||||||
|
|
||||||
|
```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. citeturn20view1turn23view0turn23view3
|
||||||
|
|
||||||
|
```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. citeturn31view1turn20view1turn23view0
|
||||||
|
|
||||||
|
```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. citeturn31view1turn1view2
|
||||||
|
|
||||||
|
```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. citeturn16view0turn16view1turn16view2
|
||||||
|
|
||||||
|
```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. citeturn24search0turn20view1turn22view0
|
||||||
|
|
||||||
|
```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. citeturn38view0turn31view1
|
||||||
|
|
||||||
|
## 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. citeturn20view1turn12view0turn16view0turn34view0
|
||||||
|
|
||||||
|
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. citeturn20view1turn22view0turn23view0
|
||||||
|
|
||||||
|
```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. citeturn12view0turn13view0turn37view0turn37view1turn37view2
|
||||||
|
|
||||||
|
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. citeturn13view0turn11view0
|
||||||
|
|
||||||
|
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. citeturn20view1turn12view0turn3view1turn2view5
|
||||||
|
|
||||||
|
```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. citeturn16view0turn27view0turn34view0turn35view0
|
||||||
|
|
||||||
|
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. citeturn27view0turn32search1turn32search0
|
||||||
|
|
||||||
|
```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”. citeturn21search1turn9search4
|
||||||
|
|
||||||
|
## 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. citeturn2view4turn20view0turn1view2
|
||||||
|
|
||||||
|
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 citeturn2view4turn12view0turn37view2 |
|
||||||
|
| 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 citeturn2view4turn2view5 |
|
||||||
|
| Halböffentlich | Tokenpflicht + CAPTCHA + E-Mail-Allowlist + restriktivere Rate-Limits | Wenn Einladungen wiederverwendbar oder breiter verteilt werden | Mehr Schutz gegen Bot-/Spam-Missbrauch citeturn3view2turn20view0turn3view1 |
|
||||||
|
|
||||||
|
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`. citeturn20view0turn3view1turn3view2turn2view5
|
||||||
|
|
||||||
|
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. citeturn17search6turn35view0
|
||||||
|
|
||||||
|
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**. citeturn20view1turn32search0turn32search1
|
||||||
|
|
||||||
|
## 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. citeturn20view1turn12view0turn16view0turn27view0
|
||||||
|
|
||||||
|
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. citeturn31view1turn38view0
|
||||||
|
- **MAS Admin API erreichbar:** `/api/spec.json` bzw. das Anlegen eines Tokens funktioniert mit `urn:mas:admin`. citeturn20view1turn10view0
|
||||||
|
- **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. citeturn12view0turn37view2
|
||||||
|
- **Onboarding korrekt:** Testnutzer landet im Haupt-Space, in Welcome/Announcements und – falls aktiviert – in weiteren Zielräumen. citeturn16view0turn27view0
|
||||||
|
- **Missbrauchsschutz greift:** Ablaufzeit, CAPTCHA, Rate-Limits und Policy-Regeln sind aktiv. citeturn3view1turn3view2turn20view0
|
||||||
|
|
||||||
|
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 citeturn2view4turn1view2turn38view0 |
|
||||||
|
| `403` bei Token-Erzeugung | OAuth-Client nicht in `policy.data.admin_clients` oder falscher Scope | Client-/Policy-Fragment korrigieren, neuen Access Token holen citeturn20view1turn23view3 |
|
||||||
|
| `404` auf `/api/admin/v1/...` | `adminapi` nicht in `http.listeners.resources` aktiviert | Listener-Block korrigieren und Redeploy citeturn20view1 |
|
||||||
|
| 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 citeturn16view0turn16view1turn16view2 |
|
||||||
|
| Feingranulare Raumzuweisung klappt nicht | Du versuchst Membership über Claim-Mapping zu lösen | Membership über Auto-Join, Provisioner oder Synapse-Modul abbilden citeturn21search1turn34view0 |
|
||||||
|
| “Groups” lassen sich nicht mehr sinnvoll zuweisen | Groups/Communities sind im aktuellen Synapse-Modell entfernt | Auf Spaces + Rooms umstellen citeturn17search0turn17search2 |
|
||||||
|
|
||||||
|
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`. citeturn13view0turn27view0turn35view0
|
||||||
|
|
||||||
|
## 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. citeturn1view2
|
||||||
|
- ESS Chart-Values zur Bestätigung, dass `matrixAuthenticationService.additional`/`synapse.additional`/`elementWeb.additional` offizielle Wertepfade sind. citeturn31view1turn31view4
|
||||||
|
- MAS-Konfigurationsreferenz für `account.*`, `captcha`, `policy`, `rate_limiting`, `email`, `clients`, `admin_clients` und HTTP-Listener. citeturn2view4turn20view0turn22view0turn23view0
|
||||||
|
- MAS Admin API und OpenAPI-Schema für Token-Erzeugung, Update, Revoke, Validitätsbegriff und Automationsmodell. citeturn20view1turn12view0turn13view0turn37view1turn37view2
|
||||||
|
- MAS Scope- und Access-Token-Doku für den Unterschied zwischen `urn:mas:admin` und benutzergebundenem Synapse-Admin-Zugriff. citeturn32search0turn32search1
|
||||||
|
- Synapse-Konfigurationsmanual für `auto_join_rooms`, Space-Aliasse, `autocreate_auto_join_rooms` und `auto_join_mxid_localpart`. citeturn16view0turn16view1turn16view2
|
||||||
|
- Synapse-Admin- und Modul-Doku für Raumzuweisung per API und Callback-Punkte `on_user_registration` / `on_user_login`. citeturn27view0turn34view0turn35view0
|
||||||
|
- Element-Web-Konfiguration für Welcome-/Branding-/OIDC-nahe UX-Optionen. citeturn24search0
|
||||||
|
- LiveKit-/Element-Call-Doku als optionale, vom Registrierungsfluss getrennte RTC-Schicht. citeturn25search0turn25search13
|
||||||
|
- Authentik-Invitationsdoku nur für den Vergleich innerhalb der Optionen-Tabelle. citeturn36search0turn36search1
|
||||||
|
|
||||||
|
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. citeturn20view1turn32search0turn38view0
|
||||||
|
|
||||||
296
docs/ops-configmap-sync.md
Normal file
296
docs/ops-configmap-sync.md
Normal 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+
|
||||||
256
docs/troubleshooting/AUTHENTIK-CREATE-INVITATION-FLOW.md
Normal file
256
docs/troubleshooting/AUTHENTIK-CREATE-INVITATION-FLOW.md
Normal 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!** 🚀
|
||||||
314
docs/troubleshooting/AUTHENTIK-FIX-TEMPLATE.md
Normal file
314
docs/troubleshooting/AUTHENTIK-FIX-TEMPLATE.md
Normal 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.
|
||||||
244
docs/troubleshooting/AUTHENTIK-INVITATION-FLOW-FIX.md
Normal file
244
docs/troubleshooting/AUTHENTIK-INVITATION-FLOW-FIX.md
Normal 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?
|
||||||
261
docs/troubleshooting/DIAGNOSTIK-AUTHENTIK-FLOW.md
Normal file
261
docs/troubleshooting/DIAGNOSTIK-AUTHENTIK-FLOW.md
Normal 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! 🔗
|
||||||
112
docs/troubleshooting/README.md
Normal file
112
docs/troubleshooting/README.md
Normal 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
41
scripts/hooks/pre-commit
Executable 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
27
scripts/install-hooks.sh
Executable 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"
|
||||||
Loading…
x
Reference in New Issue
Block a user