From 56366785aa196340dc8cccee43d0d11262a0e34b Mon Sep 17 00:00:00 2001
From: Michael Jerger <michael.jerger@meissa-gmbh.de>
Date: Thu, 20 Feb 2025 15:23:16 +0100
Subject: [PATCH] add stun server

---
 src/main/cljc/dda/c4k_jitsi/core.cljc         |  2 +
 src/main/cljc/dda/c4k_jitsi/jitsi.cljc        | 35 ++++++++-
 .../resources/jitsi/coturn-auth-secret.yaml   | 10 +++
 .../jitsi/coturn-config-default-cm.yaml       | 10 +++
 .../jitsi/coturn-config-deployment.yaml       | 72 +++++++++++++++++++
 .../jitsi/coturn-config-init-cm.yaml          | 20 ++++++
 .../jitsi/coturn-config-tcp-service.yaml      | 23 ++++++
 .../jitsi/coturn-config-udp-service.yaml      | 23 ++++++
 .../resources/jitsi/jvb-config-envs-cm.yaml   |  2 +-
 src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc   | 25 +++++++
 10 files changed, 220 insertions(+), 2 deletions(-)
 create mode 100644 src/main/resources/jitsi/coturn-auth-secret.yaml
 create mode 100644 src/main/resources/jitsi/coturn-config-default-cm.yaml
 create mode 100644 src/main/resources/jitsi/coturn-config-deployment.yaml
 create mode 100644 src/main/resources/jitsi/coturn-config-init-cm.yaml
 create mode 100644 src/main/resources/jitsi/coturn-config-tcp-service.yaml
 create mode 100644 src/main/resources/jitsi/coturn-config-udp-service.yaml

diff --git a/src/main/cljc/dda/c4k_jitsi/core.cljc b/src/main/cljc/dda/c4k_jitsi/core.cljc
index a7c92ee..1f09cd9 100644
--- a/src/main/cljc/dda/c4k_jitsi/core.cljc
+++ b/src/main/cljc/dda/c4k_jitsi/core.cljc
@@ -44,6 +44,7 @@
            (jitsi/etherpad-config resolved-config)
            (jitsi/excalidraw-config resolved-config)
            (jitsi/moderator-elector-config resolved-config)
+           (jitsi/coturn-config resolved-config)
            (ing/generate-ingress-and-cert (merge
                                            {:service-name "jitsi-meet-web"
                                             :service-port 80
@@ -76,5 +77,6 @@
         #(not (nil? %))
         (cm/concat-vec
          (jitsi/prosody-auth config auth)
+         (jitsi/coturn-auth config auth)
          (when (:contains? config :mon-cfg)
            (mon/generate-auth (:mon-cfg config) (:mon-auth auth))))))))
diff --git a/src/main/cljc/dda/c4k_jitsi/jitsi.cljc b/src/main/cljc/dda/c4k_jitsi/jitsi.cljc
index d8f0f8f..b59c9af 100644
--- a/src/main/cljc/dda/c4k_jitsi/jitsi.cljc
+++ b/src/main/cljc/dda/c4k_jitsi/jitsi.cljc
@@ -3,6 +3,7 @@
    [clojure.spec.alpha :as s]
    #?(:clj [orchestra.core :refer [defn-spec]]
       :cljs [orchestra.core :refer-macros [defn-spec]])
+   [clojure.string :as st]
    [dda.c4k-common.yaml :as yaml]
    [dda.c4k-common.common :as cm]
    [dda.c4k-common.base64 :as b64]
@@ -98,7 +99,8 @@
   (let [{:keys [fqdn namespace]} config]
     [(-> 
       (load-and-adjust-namespace "jitsi/jvb-config-envs-cm.yaml" namespace)
-      (cm/replace-key-value :XMPP_SERVER (str "prosody." namespace ".svc.cluster.local")))
+      (cm/replace-key-value :XMPP_SERVER (str "prosody." namespace ".svc.cluster.local"))
+      (cm/replace-key-value :JVB_STUN_SERVERS (str "stun." fqdn ":443")))
      (load-and-adjust-namespace "jitsi/jvb-config-service.yaml" namespace)
      (->
       (load-and-adjust-namespace "jitsi/jvb-config-deployment.yaml" namespace)
@@ -161,3 +163,34 @@
   (let [{:keys [namespace]} config]
     [(load-and-adjust-namespace "jitsi/modelector-config-service.yaml" namespace)
      (load-and-adjust-namespace "jitsi/modelector-config-deployment.yaml" namespace)]))
+
+(defn-spec coturn-auth cp/map-or-seq?
+  [config config?
+   auth auth?]
+  (let [{:keys [namespace]} config
+        {:keys []} auth]
+    [(load-and-adjust-namespace "jitsi/coturn-auth-secret.yaml" namespace)]))
+  
+(defn-spec coturn-config cp/map-or-seq?
+  [config config?]
+  (let [{:keys [namespace fqdn]} config]
+    [(load-and-adjust-namespace "jitsi/coturn-config-default-cm.yaml" namespace)
+     (-> 
+      (load-and-adjust-namespace "jitsi/coturn-config-init-cm.yaml" namespace)
+      (cm/replace-key-value
+       :data
+       {:turnserver.conf
+        (st/join "\n" [(str "realm: stun." fqdn)
+                       "listening-ip: 0.0.0.0"
+                       "listening-port: 3478"
+                       "tls-listening-port: 5349"
+                       "min-port: 49152"
+                       "max-port: 65535"
+                       "log-file: stdout"
+                       "pidfile: \"/var/tmp/turnserver.pid\""
+                       "pkey: \"/tls/tls.key\""
+                       "cert: \"/tls/tls.crt\""
+                       "userdb: \"/var/db/turndb\""])}))
+     (load-and-adjust-namespace "jitsi/coturn-config-tcp-service.yaml" namespace)
+     (load-and-adjust-namespace "jitsi/coturn-config-udp-service.yaml" namespace)
+     (load-and-adjust-namespace "jitsi/coturn-config-deployment.yaml" namespace)]))
diff --git a/src/main/resources/jitsi/coturn-auth-secret.yaml b/src/main/resources/jitsi/coturn-auth-secret.yaml
new file mode 100644
index 0000000..93223f2
--- /dev/null
+++ b/src/main/resources/jitsi/coturn-auth-secret.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: Secret
+metadata:
+  namespace: NAMESPACE
+  name: coturn-auth-secret
+  labels:
+    app.kubernetes.io/name: "coturn"
+data:
+  username: ""
+  password: ""
\ No newline at end of file
diff --git a/src/main/resources/jitsi/coturn-config-default-cm.yaml b/src/main/resources/jitsi/coturn-config-default-cm.yaml
new file mode 100644
index 0000000..677a970
--- /dev/null
+++ b/src/main/resources/jitsi/coturn-config-default-cm.yaml
@@ -0,0 +1,10 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  namespace: NAMESPACE
+  name: coturn-extra-config
+  labels:
+    app.kubernetes.io/name: "coturn"
+data:
+  turnserver.conf: |
+      verbose
diff --git a/src/main/resources/jitsi/coturn-config-deployment.yaml b/src/main/resources/jitsi/coturn-config-deployment.yaml
new file mode 100644
index 0000000..f8379fe
--- /dev/null
+++ b/src/main/resources/jitsi/coturn-config-deployment.yaml
@@ -0,0 +1,72 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  namespace: NAMESPACE
+  name: coturn-coturn
+  labels:
+    app.kubernetes.io/name: "coturn"
+spec:
+  replicas: 1
+  selector:
+    matchLabels:
+      app.kubernetes.io/name: coturn
+  template:
+    metadata:
+      labels:
+        app.kubernetes.io/name: coturn
+    spec:
+      securityContext:
+        runAsNonRoot: true
+        runAsUser: 1000
+        runAsGroup: 1000
+        fsGroup: 1000
+        seccompProfile:
+          type: RuntimeDefault
+      containers:
+        - name: "coturn"
+          image: coturn/coturn:4.6.3
+          imagePullPolicy: IfNotPresent
+          args: ["-c", "/turnserver.conf"]
+          ports:
+            - name: turn-udp
+              containerPort: 3478
+              protocol: UDP
+            - name: turn-tcp
+              containerPort: 3478
+              protocol: TCP
+            - name: turn-tcp-tls
+              containerPort: 5349
+              protocol: TCP
+            - name: turn-udp-dtls
+              containerPort: 5349
+              protocol: UDP
+          volumeMounts:
+            - name: coturn-config
+              mountPath: "/turnserver.conf"
+              subPath: turnserver.conf
+              readOnly: true
+            - name: var-tmp
+              mountPath: /var/tmp
+            - name: sqllite
+              mountPath: /var/db
+          securityContext:
+            capabilities:
+              add:
+                - NET_BIND_SERVICE
+              drop:
+                - ALL
+            readOnlyRootFilesystem: false
+            allowPrivilegeEscalation: false
+      volumes:
+        - name: coturn-initial-config
+          configMap:
+            name: coturn-initial-config
+        - name: coturn-extra-config
+          configMap:
+            name: coturn-extra-config
+        - name: coturn-config
+          emptyDir: {}
+        - name: var-tmp
+          emptyDir: {}
+        - name: sqllite
+          emptyDir: {}
diff --git a/src/main/resources/jitsi/coturn-config-init-cm.yaml b/src/main/resources/jitsi/coturn-config-init-cm.yaml
new file mode 100644
index 0000000..c3f8504
--- /dev/null
+++ b/src/main/resources/jitsi/coturn-config-init-cm.yaml
@@ -0,0 +1,20 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  namespace: NAMESPACE
+  name: coturn-initial-config
+  labels:
+    app.kubernetes.io/name: "coturn"
+data:
+  turnserver.conf: |-
+    realm: REPLACE_COTURN_FQDN
+    listening-ip: 0.0.0.0
+    listening-port: 3478
+    tls-listening-port: 5349
+    min-port: 49152
+    max-port: 65535
+    log-file: stdout
+    pidfile: "/var/tmp/turnserver.pid"
+    pkey: "/tls/tls.key"
+    cert: "/tls/tls.crt"
+    userdb: "/var/db/turndb"
\ No newline at end of file
diff --git a/src/main/resources/jitsi/coturn-config-tcp-service.yaml b/src/main/resources/jitsi/coturn-config-tcp-service.yaml
new file mode 100644
index 0000000..c255a57
--- /dev/null
+++ b/src/main/resources/jitsi/coturn-config-tcp-service.yaml
@@ -0,0 +1,23 @@
+apiVersion: v1
+kind: Service
+metadata:
+  namespace: NAMESPACE
+  name: coturn-turn-tcp
+  labels:
+    app.kubernetes.io/name: "coturn"
+  annotations:
+    metallb.universe.tf/allow-shared-ip: "shared-ip-service-group"
+    metallb.universe.tf/address-pool: public
+spec:
+  type: LoadBalancer
+  ports:
+    - name: turn-tcp
+      port: 3478
+      protocol: TCP
+      targetPort: 3478
+    - name: turn-tcp-tls
+      port: 5349
+      protocol: TCP
+      targetPort: 5349
+  selector:
+    app.kubernetes.io/name: coturn-coturn
\ No newline at end of file
diff --git a/src/main/resources/jitsi/coturn-config-udp-service.yaml b/src/main/resources/jitsi/coturn-config-udp-service.yaml
new file mode 100644
index 0000000..f394094
--- /dev/null
+++ b/src/main/resources/jitsi/coturn-config-udp-service.yaml
@@ -0,0 +1,23 @@
+apiVersion: v1
+kind: Service
+metadata:
+  namespace: NAMESPACE
+  name: coturn-turn-udp
+  labels:
+    app.kubernetes.io/name: "coturn"
+  annotations:
+    metallb.universe.tf/allow-shared-ip: "shared-ip-service-group"
+    metallb.universe.tf/address-pool: public
+spec:
+  type: LoadBalancer
+  ports:
+    - name: turn-udp
+      port: 3478
+      protocol: UDP
+      targetPort: 3478
+    - name: turn-udp-dtls
+      port: 5349
+      protocol: UDP
+      targetPort: 5349
+  selector:
+    app.kubernetes.io/name: coturn-coturn
\ No newline at end of file
diff --git a/src/main/resources/jitsi/jvb-config-envs-cm.yaml b/src/main/resources/jitsi/jvb-config-envs-cm.yaml
index 17602ea..93faa8c 100644
--- a/src/main/resources/jitsi/jvb-config-envs-cm.yaml
+++ b/src/main/resources/jitsi/jvb-config-envs-cm.yaml
@@ -9,7 +9,7 @@ metadata:
 data:
   JVB_BREWERY_MUC: 'jvbbrewery'
   JVB_PORT: '10000'
-  JVB_STUN_SERVERS: 'meet-jit-si-turnrelay.jitsi.net:443'
+  JVB_STUN_SERVERS: REPLACE_ME
   JVB_TCP_HARVESTER_DISABLED: '1'
   XMPP_SERVER: REPLACE_ME
   COLIBRI_REST_ENABLED: 'true'
diff --git a/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc b/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc
index 04d31d3..b3ba9d4 100644
--- a/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc
+++ b/src/test/cljc/dda/c4k_jitsi/jitsi_test.cljc
@@ -166,3 +166,28 @@
          (count (cut/restart-config
                  {:fqdn "xy.xy.xy"
                   :namespace "jitsi"})))))
+
+(deftest should-generate-coturn
+  (is (= 1
+         (count (cut/coturn-auth
+                 {:fqdn "xy.xy.xy"
+                  :namespace "jitsi"}
+                 {:jvb-auth-password "jvb-auth"
+                  :jicofo-auth-password "jicofo-auth"
+                  :jicofo-component-secret "jicofo-comp"}))))
+   (is (= 5
+         (count (cut/coturn-config
+                 {:fqdn "xy.xy.xy"
+                  :namespace "jitsi"}))))
+  (is (= {:apiVersion "v1",
+           :kind "ConfigMap",
+           :metadata
+           {:namespace "jitsi",
+            :name "coturn-initial-config",
+            :labels #:app.kubernetes.io{:name "coturn"}},
+           :data
+           {:turnserver.conf
+            "realm: stun.xy.xy.xy\nlistening-ip: 0.0.0.0\nlistening-port: 3478\ntls-listening-port: 5349\nmin-port: 49152\nmax-port: 65535\nlog-file: stdout\npidfile: \"/var/tmp/turnserver.pid\"\npkey: \"/tls/tls.key\"\ncert: \"/tls/tls.crt\"\nuserdb: \"/var/db/turndb\""}}
+         (second (cut/coturn-config
+                  {:fqdn "xy.xy.xy"
+                   :namespace "jitsi"})))))
\ No newline at end of file