blob: cfb502467733a6de551e9d0890ca5d198c017153 [file] [log] [blame]
Piotr Dobrowolski690ed452022-05-07 11:27:24 +02001local kube = import "../../../kube/kube.libsonnet";
2
3{
4 local app = self,
5 local cfg = app.cfg,
6 cfg:: {
7 image: error "cfg.image must be set",
8 realm: error "cfg.realm must be set",
9 authSecret: error "cfg.authSecret must be set",
10 storageClassName: error "cfg.storageClassName must be set",
11
12 portStart: 49152,
13 portEnd: 49172,
14 loadBalancerIP: null,
15 },
16
17 ns:: error "ns needs to be provided",
radex99ed6a72023-11-24 11:42:55 +010018 local ns = app.ns,
Piotr Dobrowolski690ed452022-05-07 11:27:24 +020019
radex99ed6a72023-11-24 11:42:55 +010020 configMap: ns.Contain(kube.ConfigMap("coturn")) {
Piotr Dobrowolski690ed452022-05-07 11:27:24 +020021 data: {
22 "coturn.conf": |||
23 # VoIP traffic is all UDP. There is no reason to let users connect to arbitrary TCP endpoints via the relay.
24 no-tcp-relay
25
26 no-tls
27 no-dtls
28
29 # don't let the relay ever try to connect to private IP address ranges within your network (if any)
30 # given the turn server is likely behind your firewall, remember to include any privileged public IPs too.
31 denied-peer-ip=10.0.0.0-10.255.255.255
32 denied-peer-ip=192.168.0.0-192.168.255.255
33 denied-peer-ip=172.16.0.0-172.31.255.255
34
35 # recommended additional local peers to block, to mitigate external access to internal services.
36 # https://www.rtcsec.com/article/slack-webrtc-turn-compromise-and-bug-bounty/#how-to-fix-an-open-turn-relay-to-address-this-vulnerability
37 no-multicast-peers
38 denied-peer-ip=0.0.0.0-0.255.255.255
39 denied-peer-ip=100.64.0.0-100.127.255.255
40 denied-peer-ip=127.0.0.0-127.255.255.255
41 denied-peer-ip=169.254.0.0-169.254.255.255
42 denied-peer-ip=192.0.0.0-192.0.0.255
43 denied-peer-ip=192.0.2.0-192.0.2.255
44 denied-peer-ip=192.88.99.0-192.88.99.255
45 denied-peer-ip=198.18.0.0-198.19.255.255
46 denied-peer-ip=198.51.100.0-198.51.100.255
47 denied-peer-ip=203.0.113.0-203.0.113.255
48 denied-peer-ip=240.0.0.0-255.255.255.255
49
50 # special case the turn server itself so that client->TURN->TURN->client flows work
51 # this should be one of the turn server's listening IPs
52 # FIXME allowed-peer-ip=10.0.0.1
53
54 # consider whether you want to limit the quota of relayed streams per user (or total) to avoid risk of DoS.
55 user-quota=12 # 4 streams per video call, so 12 streams = 3 simultaneous relayed calls per user.
56 total-quota=1200
57
58 use-auth-secret
59 |||,
60 },
61 },
62
radex99ed6a72023-11-24 11:42:55 +010063 dataVolume: ns.Contain(kube.PersistentVolumeClaim("coturn-data")) {
radex36964dc2023-11-24 11:19:46 +010064 storage:: "10Gi",
65 storageClass:: cfg.storageClassName,
Piotr Dobrowolski690ed452022-05-07 11:27:24 +020066 },
67
radex99ed6a72023-11-24 11:42:55 +010068 deployment: ns.Contain(kube.Deployment("coturn")) {
Piotr Dobrowolski690ed452022-05-07 11:27:24 +020069 spec+: {
70 replicas: 1,
71 template+: {
72 spec+: {
73 volumes_: {
74 config: kube.ConfigMapVolume(app.configMap),
75 data: kube.PersistentVolumeClaimVolume(app.dataVolume),
76 },
77 containers_: {
78 coturn: kube.Container("coturn") {
79 image: cfg.image,
80 ports_: {
81 turn: { containerPort: 3478 },
82 } + {
83 ["fwd-%d" % [n]]: { containerPort: n }
84 for n in std.range(cfg.portStart, cfg.portEnd)
85 },
86
87 command: [
88 # This disgusting hack comes from the fact that
89 # official coturn containers have turnserver
90 # binary set up with CAP_NET_BIND_SERVICE=+ep,
91 # while there's really no use that in our case.
92 #
93 # Due to our PSP we can't exec said binary, nor
94 # can we chmod/chown/setcap on it, as we are
95 # running as an unprivileged user.
96 #
97 # Copying it over is the easiest method of
98 # stripping said spurious cap.
99 "/bin/sh", "-c",
100 "cp /usr/bin/turnserver /tmp/turnserver && \\
101 exec /tmp/turnserver \\
102 -c /config/coturn.conf \\
103 --log-binding \\
104 --realm=$(COTURN_REALM) \\
105 --static-auth-secret=$(COTRN_STATIC_AUTH_SECRET) \\
106 --min-port $(COTURN_MIN_PORT) \\
107 --max-port $(COTURN_MAX_PORT) \\
108 " + if cfg.loadBalancerIP != null then "-X $(COTURN_EXTERNAL_IP)" else "",
109 ],
110 volumeMounts_: {
111 config: { mountPath: "/config" },
112 data: { mountPath: "/var/lib/coturn" },
113 },
114 env_: {
115 COTURN_REALM: cfg.realm,
116 COTURN_STATIC_AUTH_SECRET: cfg.authSecret,
117 COTURN_EXTERNAL_IP: cfg.loadBalancerIP,
118 COTURN_MIN_PORT: cfg.portStart,
119 COTURN_MAX_PORT: cfg.portEnd,
120 },
121 },
122 },
123 securityContext: {
124 runAsUser: 1000,
125 runAsGroup: 1000,
126 fsGroup: 2000,
127 },
128 },
129 },
130 },
131 },
132
radex99ed6a72023-11-24 11:42:55 +0100133 svcTCP: ns.Contain(kube.Service("coturn-tcp")) {
radex8b8f3872023-11-24 11:09:46 +0100134 target:: app.deployment,
Piotr Dobrowolski690ed452022-05-07 11:27:24 +0200135 metadata+: {
136 annotations+: {
137 "metallb.universe.tf/allow-shared-ip": "coturn",
138 },
139 },
140 spec+: {
141 type: "LoadBalancer",
142 loadBalancerIP: cfg.loadBalancerIP,
143 externalTrafficPolicy: "Local",
144 ports: [
145 { name: "turn", port: 3478, protocol: "TCP" },
146 ] + [
147 { name: "fwd-%d" % [n], port: n, protocol: "TCP" }
148 for n in std.range(cfg.portStart, cfg.portEnd)
149 ],
150 },
151 },
152
radex99ed6a72023-11-24 11:42:55 +0100153 svcUDP: ns.Contain(kube.Service("coturn-udp")) {
radex8b8f3872023-11-24 11:09:46 +0100154 target:: app.deployment,
Piotr Dobrowolski690ed452022-05-07 11:27:24 +0200155 metadata+: {
156 annotations+: {
157 "metallb.universe.tf/allow-shared-ip": "coturn",
158 },
159 },
160 spec+: {
161 type: "LoadBalancer",
162 loadBalancerIP: cfg.loadBalancerIP,
163 externalTrafficPolicy: "Local",
164 ports: [
165 { name: "turn", port: 3478, protocol: "UDP" },
166 ] + [
167 { name: "fwd-%d" % [n], port: n, protocol: "UDP" }
168 for n in std.range(cfg.portStart, cfg.portEnd)
169 ],
170 },
171 },
172}