fix(coturn): remove plaintext TURN shared secret, rotate leaked value
Auto-Deploy on Push / verify-and-notify (push) Canceled after 0s

Issue #38 discussion surfaced a real bug: the TURN shared secret was
duplicated - correctly SOPS-encrypted in coturn-secret.yaml, but also
hardcoded in plaintext in synapse-values.yaml (a plain, non-SOPS
ConfigMap), visible in git history. Also found turn_user_lifetime is
86400000ms (24h), not "short-lived" as previously assumed - raising the
stakes of the leak somewhat.

Extracted the turn config block into its own dedicated SOPS-encrypted
Secret (synapse-turn-secret.yaml), wired via a second HelmRelease
valuesFrom entry (same pattern already used for ess-mas-values-secret).
Rotated the value while doing this, so the leaked plaintext secret is no
longer live anywhere.

Added checksum/rotated-at annotations (matrix-stack HelmRelease's
existing element-config-checksum patch gets a sibling turn-secret-checksum;
coturn's Deployment pod template gets a rotated-at annotation) so future
rotations actually restart both consumers - Kubernetes doesn't restart
running pods when a referenced Secret's content changes on its own.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Thore Cimbal
2026-07-28 21:05:07 +02:00
co-authored by Claude Sonnet 5
parent 7b9d13199e
commit 0242238597
6 changed files with 43 additions and 17 deletions
+5 -5
View File
@@ -4,11 +4,10 @@ metadata:
name: coturn-secret name: coturn-secret
namespace: matrix namespace: matrix
stringData: stringData:
TURN_SECRET: ENC[AES256_GCM,data:SILIqMB+fmAMFITAL7lG1hOgICec6BJf1mOcK0gdmnCHWYqRuJv7jgjfGylG25xzQKi+zE7Qual9PnkZG2KiOA==,iv:+GZqLGusE4Q0x2jEEtFxj06rryyQmQhXdkTy4eE8ZHw=,tag:OpSZkinPTAi1ZKWyo8OX3A==,type:str] TURN_SECRET: ENC[AES256_GCM,data:XTkWEymgB8wz7yoXMXFkmwoTlQuW4dc7Z34UnONvKB5Qi+Wa3yVdACnFrnvE1HnzWYJ23YO+ssCNXRiixl9YVg==,iv:t4nvWH4rqWDHDzYOrrESwwtqMQ6YJ2CQzVbcyaYiaYM=,tag:KKMuQm41ZuvvjTzGpScbIA==,type:str]
sops: sops:
age: age:
- recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh - enc: |
enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyRk1mK3NWc1l4T0JCOFpF YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyRk1mK3NWc1l4T0JCOFpF
S0RuQ3ViZmo3QTNVL2JvZ0hzMy91R2l0TEhzCk01a1VGdk1sdVg4aWswTzRibXI4 S0RuQ3ViZmo3QTNVL2JvZ0hzMy91R2l0TEhzCk01a1VGdk1sdVg4aWswTzRibXI4
@@ -16,7 +15,8 @@ sops:
MEJleHFnd3oyT3VPL2dsYkpMUlRkOWMKcKUIgsQ/ff49pGGXMnYwJmwqPVC7woAR MEJleHFnd3oyT3VPL2dsYkpMUlRkOWMKcKUIgsQ/ff49pGGXMnYwJmwqPVC7woAR
IEzvhcNX97xx746SnrxZe5t2YadsYMkYIl0nvqBPJhSlvqMNafpQbQ== IEzvhcNX97xx746SnrxZe5t2YadsYMkYIl0nvqBPJhSlvqMNafpQbQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2026-04-29T21:06:21Z" recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
mac: ENC[AES256_GCM,data:UhyR5m1HYWrZHwNLW5sg2PxbpaydWbP5cekghGlzSpQg7CYEcvZw3tJ/qB8zA19xZSM7tdSHOXdD+QytRq6qW59M1unqMaumA43B6JxQg1C1NdXAW0mkSc2WiNchvgpVii9P/TVlzSSIRwC3YGCQUsfa3SSfNzI4Z6fMuBnhYLE=,iv:4HYxbrYSRJLe1KcQ6q8bpee8/Lx1m3pPmisb/L2Mu64=,tag:l7n3u+Pg6533OzwtNUZvNw==,type:str]
encrypted_regex: ^(data|stringData)$ encrypted_regex: ^(data|stringData)$
lastmodified: "2026-07-28T19:02:42Z"
mac: ENC[AES256_GCM,data:1NO8bBG47PDK5zGBYVvfUHjbLct9DP3eBDurtd7ChGFiQBPRUrlLric2cfUuB54+Z1x+VV2WIEpVt6gARNcG6+gc6H+ZKZZL1PRj3Pl3NYhgbjs05R/cHYAg3QimmnuvQlM8MvZGimB48l6mkvIN+ncmoB6l/6AXG1XfmwFW87o=,iv:AABJu2TglH2nB8PMV7ORpQ0EyzznrwmgpWImvm9mB6o=,tag:md5aQyK72iL+P28y/YDqLQ==,type:str]
version: 3.12.2 version: 3.12.2
+4
View File
@@ -74,6 +74,10 @@ spec:
app: coturn app: coturn
annotations: annotations:
prometheus.io/scrape: "false" 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:02:00Z"
spec: spec:
hostNetwork: true hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet dnsPolicy: ClusterFirstWithHostNet
@@ -58,15 +58,6 @@ data:
room_list_publication_rules: room_list_publication_rules:
- user_id: "*" - user_id: "*"
action: allow 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: oembed:
config: | config: |
oembed_enabled: true oembed_enabled: true
+4 -1
View File
@@ -25,7 +25,10 @@ spec:
- kind: Secret - kind: Secret
name: ess-mas-values-secret name: ess-mas-values-secret
valuesKey: values.yaml valuesKey: values.yaml
- kind: Secret
name: synapse-turn-secret
valuesKey: values.yaml
values: values:
# Top-Level: serverName das ist dein Matrix-Homeserver-Name # Top-Level: serverName das ist dein Matrix-Homeserver-Name
serverName: axion1337.chat serverName: axion1337.chat
+8 -2
View File
@@ -1,8 +1,10 @@
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 # Patch: Fügt Checksums der element-values.yaml und des turn_shared_secret zur
# Damit wird Flux die HelmRelease neu-synced wenn sich die ConfigMap ändert # 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: patches:
- target: - target:
kind: HelmRelease kind: HelmRelease
@@ -12,6 +14,9 @@ patches:
- op: add - op: add
path: /metadata/annotations/element-config-checksum path: /metadata/annotations/element-config-checksum
value: "401f8a87d0ef5d91d2e5032d4aede42c" value: "401f8a87d0ef5d91d2e5032d4aede42c"
- op: add
path: /metadata/annotations/turn-secret-checksum
value: "9b0383df36943da3b32198b6bd32bfcd"
resources: resources:
- matrix-postgres-auth.yaml - matrix-postgres-auth.yaml
@@ -26,6 +31,7 @@ resources:
# TURN Server für WebRTC # TURN Server für WebRTC
- coturn-secret.yaml - coturn-secret.yaml
- coturn.yaml - coturn.yaml
- synapse-turn-secret.yaml
# HelmRelease (muss ganz unten stehen, damit die ConfigMaps vorher da sind!) # HelmRelease (muss ganz unten stehen, damit die ConfigMaps vorher da sind!)
- element-server-suite.yaml - element-server-suite.yaml
# Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat # Custom Apex Ingress für Element Web + Well-Known auf axion1337.chat
+22
View File
@@ -0,0 +1,22 @@
apiVersion: v1
kind: Secret
metadata:
name: synapse-turn-secret
namespace: matrix
stringData:
values.yaml: ENC[AES256_GCM,data:fFKCOus4okAo98WwfNkbdLyBFfkp9C1znMeSHh/Og6Z/rRbivsHeKFYjW3O0rHOy9kds/mtWxE4f7ealjY+5gsslwi/Rzp56AD4O+m7OEs5wcIVQsv8UT5IkUDbrYE3LJwMrl+sqw/jmZ1BR22a2ZEYGk3r1Y5S/gDI99AiydwUiYdOueSCRQg6AEEr6LDR898J8ZVcMlaRZ+4ZkbVrIZcuKN6oxq3eqPR3kugIMjQpWh/XGKZKB/D0mATrrqPDAbJn3jY9DweW4R6R+hZCi8Ln0UBa+grIgiuc/gFhS8ElVfrLWhwmeMtPRjdWNjuYe2LJ/bmKl3/SQZZa/HvHOAPf8Jqt5B5Mc1aya7HGmQgtY0e46cid/6NUZUDJW2YlGJPm7uV/p3XWz9NyRY7GiioDF1F2+0cmTWqZJep6+fu2bRDdpfG9hdLEbVb5ZJykxmpfG3H6ETdOt7ld2+DgCDz2YSiQbjT8OYu23ra8xsvaenLV08sG4M2XZ1c/BzzNAgFHhQduBhE9y,iv:+DYUBkJC8FZIl+mXc5NWv1EfSRWq+ho1huwTerFhZwM=,tag:AoDD6kv6OLXY6zBkN6MiIw==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGWDFqMVBkbDU5eXhyM1Nt
OXBnY21teUw0UDE0NVBGN2RQamFBRzVQREJrCjFUM055VHdISnVMTXU5enJiYnR2
bEJ6VElobVlnaDNqbElVZEorTVd6em8KLS0tIEgyKy9pbG9RVkp6UzZYMXJweG1E
b2lFNkovbnc3LzdLRjZZZEtGUkxhTmcKRZhddlW9oN818aGqjLh7NGIEi2F0HPPj
5vhPq+X+VbHJORh6Ss/lPc43j8LvTRMpinGZTnaKHS2DUs+gPQbGOA==
-----END AGE ENCRYPTED FILE-----
recipient: age14l0hwfqylwpemz5y2ghh2yxk0phszlnj3qlejhue0fw0kz3tmfgqdsjzdh
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-07-28T19:02:52Z"
mac: ENC[AES256_GCM,data:/UUr3ME1NZjN6nAVm7DDXBGuEM9PCFxbPXSn+gSD0PSEB6iq1YwwmKSgKA/+Y5pDa/fJvSHsdEPka+PPdCB5/cGEr+qoMqtEW/jScqw8fVCXKHM/7/OCKPJILGZyQKHaFxoBGzEZn1osJrBoILpHR0Gf6gc3XcsTnWRLD9iGDQw=,iv:ixwKglOUHad513pXZcdc1mEHNXeceN0tqkevr38iUrc=,tag:51aB11R7gndUHE7eLJQ9Yw==,type:str]
version: 3.13.3