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