Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2932ffffc3 | ||
|
|
0f7ff1a896 | ||
|
|
debf980d5f | ||
|
|
802e09cd9c | ||
|
|
d742c99ba5 | ||
|
|
ac7e65100d | ||
|
|
be95bd921c | ||
|
|
7795f89fc9 | ||
|
|
9fa947cc21 | ||
|
|
233b13f972 | ||
|
|
51ea51352b |
@@ -4,19 +4,28 @@ metadata:
|
||||
name: coturn-secret
|
||||
namespace: matrix
|
||||
stringData:
|
||||
TURN_SECRET: ENC[AES256_GCM,data:SILIqMB+fmAMFITAL7lG1hOgICec6BJf1mOcK0gdmnCHWYqRuJv7jgjfGylG25xzQKi+zE7Qual9PnkZG2KiOA==,iv:+GZqLGusE4Q0x2jEEtFxj06rryyQmQhXdkTy4eE8ZHw=,tag:OpSZkinPTAi1ZKWyo8OX3A==,type:str]
|
||||
TURN_SECRET: ENC[AES256_GCM,data:gab4MSNlRANQz/T/Xn0Z45tkUvQ3Uxn5u0MyYfhZTan49P865UbX4rYPf/KmKsekdwFdOGBzvCgcwxhddVbZ1w==,iv:INbz5UUxgA6xdsPBp5W9Mwe+kd9dhHh2Rx5l3yeNRIQ=,tag:dgk/iFjvst7Wul9Lai2QEQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
|
||||
enc: |
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyRk1mK3NWc1l4T0JCOFpF
|
||||
S0RuQ3ViZmo3QTNVL2JvZ0hzMy91R2l0TEhzCk01a1VGdk1sdVg4aWswTzRibXI4
|
||||
ZlJtNFF5MjBONEZOaWVpeU5taHl2bkEKLS0tIGxpUHY3NUFLWFBaWm1QSlZiVFkx
|
||||
MEJleHFnd3oyT3VPL2dsYkpMUlRkOWMKcKUIgsQ/ff49pGGXMnYwJmwqPVC7woAR
|
||||
IEzvhcNX97xx746SnrxZe5t2YadsYMkYIl0nvqBPJhSlvqMNafpQbQ==
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQMncxOEhRZC9jcHpjT3dW
|
||||
Q1RNaW5pc00zVnJhWHRnZHd3TGhURWNZU2dJCk85bXJkbTEyd1ZybjhDT05pL2c3
|
||||
ZU9EUSt1eDlSQWJyVGtsak1oS3FSR2sKLS0tIEFUdXVHL0V1ZW5VMVVBZEJaYUIw
|
||||
U1BrYlJyQVZkZFhBdmdwbDMyK3lTQkkKEaSy1o+IICf2uaT6olapRJa/duXxjOBg
|
||||
OqRS9axnJ71XxEnHjLTsCbkI5b+8Fux08qKaH9sMsJrWOiSHDdTXXQ==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
lastmodified: "2026-04-29T21:06:21Z"
|
||||
mac: ENC[AES256_GCM,data:UhyR5m1HYWrZHwNLW5sg2PxbpaydWbP5cekghGlzSpQg7CYEcvZw3tJ/qB8zA19xZSM7tdSHOXdD+QytRq6qW59M1unqMaumA43B6JxQg1C1NdXAW0mkSc2WiNchvgpVii9P/TVlzSSIRwC3YGCQUsfa3SSfNzI4Z6fMuBnhYLE=,iv:4HYxbrYSRJLe1KcQ6q8bpee8/Lx1m3pPmisb/L2Mu64=,tag:l7n3u+Pg6533OzwtNUZvNw==,type:str]
|
||||
recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwQk82eGdWRmdRNFJQR0xF
|
||||
SWhNRUtNWThZNFM0aXU3V0N4UkhtTy9NTFdnCi9pa3dsVXRja1dTL1pZTnoxQ0JT
|
||||
UUIxekZnVGUvdFgyblFiS0JLMjU3L2cKLS0tIE1IRTJ0M3kvMFZPWVVDYjJlVkk0
|
||||
eGJQOTVUc1NsNE5GdmJtODlmdHp3c2cKHTP6YRMTdYE/iBuSZs/Tjt4TwKCxHEIu
|
||||
f3jTblKIqWwRHKCgOIkC16QDbpMBlNLH3JknJEdIjkB2HIrXrw1MNA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1x4jjwc8nuttwr8us924pvdc6dll5npkc6c8f4zf2hx5d2qu75dtqx0fm0d
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
lastmodified: "2026-07-28T19:26:57Z"
|
||||
mac: ENC[AES256_GCM,data:zU3i1WGY1X4igBYzfC1WAWdtMQZWGBSacaJpXnUVt6+BCfucqaH807IRWpWbTR0+xuLteaqcdXuVuAlStqs/VV586Q4cD2FfWDeBq/O09HEwTrfekTjAyyu7zCFyZ2ja+kB4DQ83NoscCiNwNmfTZF+6RzMqx7yphPxK5go1r7c=,iv:6FIYWsNvz78zJscbxyDgy1u6ur20MnOMkMcsA4329OI=,tag:uSDpAWEixGcVmtOloMoKuw==,type:str]
|
||||
version: 3.12.2
|
||||
|
||||
@@ -65,6 +65,17 @@ metadata:
|
||||
namespace: matrix
|
||||
spec:
|
||||
replicas: 1
|
||||
# hostNetwork pods bind directly to the node's ports (3478/5349) - on this single-node
|
||||
# cluster, RollingUpdate's default "bring up the new pod before removing the old one"
|
||||
# can never schedule (port conflict). Recreate kills the old pod first.
|
||||
# Note: switching to Recreate on an existing Deployment that already had the
|
||||
# RollingUpdate defaults recorded required a one-time manual
|
||||
# `kubectl patch --type=merge -p '{"spec":{"strategy":{"rollingUpdate":null,"type":"Recreate"}}}'`
|
||||
# (2026-07-28) - a YAML `rollingUpdate: null` in this file is dropped before reaching the
|
||||
# API server (client-side omits null keys) rather than sent as an explicit field deletion,
|
||||
# so it can't clear an already-set field on its own.
|
||||
strategy:
|
||||
type: Recreate
|
||||
selector:
|
||||
matchLabels:
|
||||
app: coturn
|
||||
@@ -74,6 +85,10 @@ spec:
|
||||
app: coturn
|
||||
annotations:
|
||||
prometheus.io/scrape: "false"
|
||||
# Bumped on every TURN_SECRET rotation (Issue #38) to force a new pod, since
|
||||
# Kubernetes doesn't restart running pods when a referenced Secret's content
|
||||
# changes and the initContainer that reads it only runs once at pod start.
|
||||
rotated-at: "2026-07-28T19:26:57Z"
|
||||
spec:
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
|
||||
@@ -58,15 +58,6 @@ data:
|
||||
room_list_publication_rules:
|
||||
- user_id: "*"
|
||||
action: allow
|
||||
turn:
|
||||
config: |
|
||||
turn_uris:
|
||||
- "turn:turn.axion1337.chat?transport=udp"
|
||||
- "turn:turn.axion1337.chat?transport=tcp"
|
||||
- "turns:turn.axion1337.chat?transport=tcp"
|
||||
turn_shared_secret: "cab3c8408363515d9b4cdc3384a1f76ca17a973242fdfdc72b67ac4d86158527"
|
||||
turn_user_lifetime: 86400000
|
||||
turn_allow_guests: false
|
||||
oembed:
|
||||
config: |
|
||||
oembed_enabled: true
|
||||
@@ -4,7 +4,11 @@ metadata:
|
||||
name: matrix-stack
|
||||
namespace: matrix
|
||||
spec:
|
||||
interval: 5m
|
||||
# Shortened from 5m to match production-apps Kustomization's 1m interval - narrows the
|
||||
# window between coturn (Kustomization-only, no Helm indirection) and synapse-main
|
||||
# (behind this HelmRelease) picking up a rotated TURN secret after Issue #38's
|
||||
# automated-rotation PR gets merged. Self-heals either way, just faster now.
|
||||
interval: 1m
|
||||
chart:
|
||||
spec:
|
||||
chart: matrix-stack
|
||||
@@ -25,7 +29,10 @@ spec:
|
||||
- kind: Secret
|
||||
name: ess-mas-values-secret
|
||||
valuesKey: values.yaml
|
||||
|
||||
- kind: Secret
|
||||
name: synapse-turn-secret
|
||||
valuesKey: values.yaml
|
||||
|
||||
values:
|
||||
# Top-Level: serverName – das ist dein Matrix-Homeserver-Name
|
||||
serverName: axion1337.chat
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
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
|
||||
# Patch: Fügt Checksums der element-values.yaml und des turn_shared_secret zur
|
||||
# HelmRelease hinzu. Damit wird Flux die HelmRelease neu-synced (und synapse-main neu
|
||||
# gestartet), wenn sich die jeweilige ConfigMap/Secret ändert - siehe Issue #38's
|
||||
# Rotations-Mechanismus, der turn-secret-checksum bei jeder Rotation bumpt.
|
||||
patches:
|
||||
- target:
|
||||
kind: HelmRelease
|
||||
@@ -12,6 +14,9 @@ patches:
|
||||
- op: add
|
||||
path: /metadata/annotations/element-config-checksum
|
||||
value: "401f8a87d0ef5d91d2e5032d4aede42c"
|
||||
- op: add
|
||||
path: /metadata/annotations/turn-secret-checksum
|
||||
value: "d220c0e4ff8f7106328c8827d47e8734"
|
||||
|
||||
resources:
|
||||
- matrix-postgres-auth.yaml
|
||||
@@ -26,6 +31,7 @@ resources:
|
||||
# TURN Server für WebRTC
|
||||
- coturn-secret.yaml
|
||||
- coturn.yaml
|
||||
- synapse-turn-secret.yaml
|
||||
# HelmRelease (muss ganz unten stehen, damit die ConfigMaps vorher da sind!)
|
||||
- element-server-suite.yaml
|
||||
# Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat
|
||||
@@ -33,4 +39,7 @@ resources:
|
||||
- networkpolicy.yaml
|
||||
# Backup zur Hetzner Storage Box (Issues #6 + #15)
|
||||
- synapse-backup-secret.yaml
|
||||
- synapse-backup.yaml
|
||||
- synapse-backup.yaml
|
||||
# Automatisierte TURN-Secret-Rotation (Issue #38)
|
||||
- turn-secret-rotation-secret.yaml
|
||||
- turn-secret-rotation.yaml
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: synapse-turn-secret
|
||||
namespace: matrix
|
||||
stringData:
|
||||
values.yaml: ENC[AES256_GCM,data:An+GypE/btGmfnvL1rPzvbN1sAnZKQnHV20GxXkZiRb+Wi8BymAUA6JRBo5mdtvK1dgDMF6H1wN+Y7wjzwduteaoskVfgd7Xw+lL1SrZ/6pchGxlUIWSJlLTmp6IHZaruleDUsCKdrWfN9TQDE+WYdiECBktlGGXs8ZZMTzjHmHKJ3tNwSimaxuG662Amb0LiHLX+zBUKOuG0L4cWrp6JI3NKQFgNNiF6xwXjHDX550bGOQ2pi5UVPL9+HlH2tPeTzoCCZdJLWF+2kZg31bZ7dzRp8M23eDrzfGC9e9m0NrA2z1ljagbnuT0tixp6J8205qfBOIOVOWbXHmd/LQ8nphA64En6JXqU8XeZ+mgMUmFuGwyewLq4oilLoQfdZujEyGhc9Hd/yonRlc/RDBlONlI8d+IWqZxf0AaUYEAe9uE6MulqRs0CowPUpCmWtZjz68qQlIvJEAqxNdWEnp+SkExDNNe9y8tBOCXy726TRX0MLIlZ+CjPDCHhwDeKw5oQU0wXr9QezY=,iv:bPK1+PViBg046N3q2Eb1ZOJOYv7X/HgpCEU/MLp7o6k=,tag:/2Kyv7aB4baOL+3KdAeQ9w==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuK2xIT3M0cGtVOHdKYklF
|
||||
OHl1VHFRTkVSaHVQNUUyRlhZUjRWM3JUN0hBCnpUS2YzdG1mSjlRaEVvTHdKVkR4
|
||||
L1hrR05IRUdqdGp2aU95aWxRRXdsQWcKLS0tICtLbnFsK3Zza053VXFWdVErRy92
|
||||
WUUzZTBIRzUyWnp5a1ZScUVqb0NyencKvnFyJCR6j1/aH4gJvFmLPNlk5XpC08wF
|
||||
mTmL981uGfz4NULc+O3sDkonJ827glpefgWPgPW2HmKT88d4A9vyJw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVY0NXa1B5c2RzbzRReU1h
|
||||
RHBSbk9aK3d6VjRWZ1hzL3FDZFZJZGFqTVQ0Ck9ib0p3bkR6cU8yc0VFNjEzSFFi
|
||||
T3dWY1luQW1VZ1NjZFNoZFFLSCsvelkKLS0tIHIxV0d6TWhpSEc3d3c0L1VvOWxk
|
||||
eDhTM2pDbTNXZXlWRVYxR2tPQU5iLzgKrLLLSBU/g5ebeRNi7hWYbcuJ/2JOfiUn
|
||||
0DBnzMVJPBfqq/u8THiRYaMajx3k4D9+FN7qc5nBgTd85iGBo+OowA==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age1x4jjwc8nuttwr8us924pvdc6dll5npkc6c8f4zf2hx5d2qu75dtqx0fm0d
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
lastmodified: "2026-07-28T19:26:57Z"
|
||||
mac: ENC[AES256_GCM,data:UfD+QJel9FygoKPM02KdOLvP1id/21ghQ0uWAQJxEs/w+B2vVkpe/dXSJ7QnI0e528ns1HW81GAxkxyAupsUDq8/pBdEQgItwDs5DIgHvH+sTPAtj2Kyq2wMOeEt+XDGLRdOlAwbcKDS/LyfeZ5b9QnAbY2w/tTinTkzEvbudT8=,iv:WmmwjAmZmM0W8dvqBcv9XYZkYtan3lg0Sb8ypVuGoJk=,tag:3yzZhSFtbSbLUXSdDWGAtw==,type:str]
|
||||
version: 3.13.3
|
||||
@@ -0,0 +1,23 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: turn-secret-rotation-credentials
|
||||
namespace: matrix
|
||||
stringData:
|
||||
age-key.txt: ENC[AES256_GCM,data:4LAs9LLFo38UMHXCo4lun9RHxGnDyp7GWlaNdIqqkSL9lNv7+ILdlc03CxFVobCYxK65xMOn1xdEty+887JBMlawST04am/5MkAnUivKwXCw8OHmbZhCwKHFqSYH/NsgVNf+btZKIIny8XPVQAPj/vQIi+Ity+BQyPkEZ1WUcsqjDoaK9IFhQTePJtHgWivhOY2WpUt/TP7vTfub4TOrgVpzNd9LIpBkwq+zhpVXKwnYUWOuLMXlPe08kazy,iv:9A24HbTl24slj+qTCfyI01+dGqRFVPDUA0wp2kSUHpc=,tag:iQxU0dWD4Noo1m0HXhV6vQ==,type:str]
|
||||
gitea-token: ENC[AES256_GCM,data:cmZ1GCrqRYLtLn+cRVZCrO7UcCIavlQLJPt2PRMtBbgLdhDVTElUKA==,iv:9v29GXHRtDlrL3PoRCdOqYpBepZrX04+6UjoywRZX0E=,tag:ZvYXBOm9qgB1XA5lkV4LsQ==,type:str]
|
||||
sops:
|
||||
age:
|
||||
- enc: |
|
||||
-----BEGIN AGE ENCRYPTED FILE-----
|
||||
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5S3BtTHNLVGVVM2ZpTlZS
|
||||
Y3pGMS9CSkNsdUpPbWtkSTRHK0p6U2lwdEJnClVWdXp4SllyM1hvbTZyTU40SDc2
|
||||
QlVtMDduZWpaVENiYnhMNlFXd01QblEKLS0tIGNzTGRZcmoyaFltUHRDSHBPZE1N
|
||||
OCszUkl1VjQ5V3F2cVI4dXJFcER5YXcK+2Eh1JNLuMiCnpQ3cL/I7XTykkIZ3tqp
|
||||
O3c9UwYs1FAZWlMgElTBTqsmut1ShduIYfDFRKGeS0UxPEM4U+tIGw==
|
||||
-----END AGE ENCRYPTED FILE-----
|
||||
recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
|
||||
encrypted_regex: ^(data|stringData)$
|
||||
lastmodified: "2026-07-28T19:21:28Z"
|
||||
mac: ENC[AES256_GCM,data:vx6Bs/L0NXKUvvQdu6aYtuur/CYPkIBZzvFLqTyd08Errw0dGMrg73oHQ/imxpe42HgnO2mGwxNdEx2jYYbtc3RBWHE/yPH5m8y/XLoSL3fauzbkGsDwMSWzKiZXyIuGh7SxuB+CFY9qqFMK+dap1Ofno7a1/Gr1qibVDqscwxw=,iv:9AUQQuTCja09OohzVw73URMHE8xCW7iLLtBg7GSDcPA=,tag:g1ibnBIGqokvs2IEVOYq6Q==,type:str]
|
||||
version: 3.13.3
|
||||
@@ -0,0 +1,70 @@
|
||||
# Automated TURN shared-secret rotation (Issue #38). Generates a new secret, re-encrypts
|
||||
# apps/production/coturn-secret.yaml and synapse-turn-secret.yaml using a dedicated,
|
||||
# narrowly-scoped age key (see turn-secret-rotation-secret.yaml - it can only decrypt these
|
||||
# two files, not the repo's master sops-age key), bumps the checksum/rotated-at annotations
|
||||
# so a merge restarts both consumers automatically, and opens a Pull Request rather than
|
||||
# pushing straight to main - a human reviews and merges it.
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: turn-secret-rotation
|
||||
namespace: matrix
|
||||
spec:
|
||||
schedule: "0 4 1 * *"
|
||||
concurrencyPolicy: Forbid
|
||||
successfulJobsHistoryLimit: 3
|
||||
failedJobsHistoryLimit: 3
|
||||
jobTemplate:
|
||||
spec:
|
||||
backoffLimit: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: turn-secret-rotation
|
||||
app.kubernetes.io/component: rotation
|
||||
spec:
|
||||
restartPolicy: OnFailure
|
||||
# Public-internet reachability to the Gitea host has been flaky (see Issue #41);
|
||||
# both servers share a private Hetzner network. hostAliases (unlike the node-level
|
||||
# /etc/hosts fix used for image pulls) is actually honored by in-pod processes.
|
||||
hostAliases:
|
||||
- ip: "10.0.0.3"
|
||||
hostnames:
|
||||
- "rohana.axion1337.de"
|
||||
containers:
|
||||
- name: rotate
|
||||
image: rohana.axion1337.de/sorb/axion-secret-rotation:v1
|
||||
env:
|
||||
- name: GITEA_HOST
|
||||
value: "rohana.axion1337.de"
|
||||
- name: GITEA_REPO
|
||||
value: "sorb/axion1337.chat-gitops"
|
||||
- name: GITEA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: turn-secret-rotation-credentials
|
||||
key: gitea-token
|
||||
- name: SOPS_AGE_KEY_FILE
|
||||
value: /secrets/age/age-key.txt
|
||||
- name: GIT_AUTHOR_NAME
|
||||
value: "turn-secret-rotation"
|
||||
- name: GIT_AUTHOR_EMAIL
|
||||
value: "turn-secret-rotation@axion1337.chat"
|
||||
volumeMounts:
|
||||
- name: age-key
|
||||
mountPath: /secrets/age
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
memory: 128Mi
|
||||
volumes:
|
||||
- name: age-key
|
||||
secret:
|
||||
secretName: turn-secret-rotation-credentials
|
||||
items:
|
||||
- key: age-key.txt
|
||||
path: age-key.txt
|
||||
mode: 0400
|
||||
Reference in New Issue
Block a user