vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / jitsi-videobridge.nix
blob14eb64eae253599aab23e2d9c818a209c0cfbf9f
1 { config, lib, pkgs, ... }:
2 let
3   cfg = config.services.jitsi-videobridge;
4   attrsToArgs = a: lib.concatStringsSep " " (lib.mapAttrsToList (k: v: "${k}=${toString v}") a);
6   format = pkgs.formats.hocon { };
8   # We're passing passwords in environment variables that have names generated
9   # from an attribute name, which may not be a valid bash identifier.
10   toVarName = s: "XMPP_PASSWORD_" + lib.stringAsChars (c: if builtins.match "[A-Za-z0-9]" c != null then c else "_") s;
12   defaultJvbConfig = {
13     videobridge = {
14       ice = {
15         tcp = {
16           enabled = true;
17           port = 4443;
18         };
19         udp.port = 10000;
20       };
21       stats = {
22         enabled = true;
23         transports = [ { type = "muc"; } ];
24       };
25       apis.xmpp-client.configs = lib.flip lib.mapAttrs cfg.xmppConfigs (name: xmppConfig: {
26         hostname = xmppConfig.hostName;
27         domain = xmppConfig.domain;
28         username = xmppConfig.userName;
29         password = format.lib.mkSubstitution (toVarName name);
30         muc_jids = xmppConfig.mucJids;
31         muc_nickname = xmppConfig.mucNickname;
32         disable_certificate_verification = xmppConfig.disableCertificateVerification;
33       });
34       apis.rest.enabled = cfg.colibriRestApi;
35     };
36   };
38   # Allow overriding leaves of the default config despite types.attrs not doing any merging.
39   jvbConfig = lib.recursiveUpdate defaultJvbConfig cfg.config;
42   imports = [
43     (lib.mkRemovedOptionModule [ "services" "jitsi-videobridge" "apis" ]
44       "services.jitsi-videobridge.apis was broken and has been migrated into the boolean option services.jitsi-videobridge.colibriRestApi. It is set to false by default, setting it to true will correctly enable the private /colibri rest API."
45     )
46   ];
47   options.services.jitsi-videobridge = with lib.types; {
48     enable = lib.mkEnableOption "Jitsi Videobridge, a WebRTC compatible video router";
50     config = lib.mkOption {
51       type = attrs;
52       default = { };
53       example = lib.literalExpression ''
54         {
55           videobridge = {
56             ice.udp.port = 5000;
57             websockets = {
58               enabled = true;
59               server-id = "jvb1";
60             };
61           };
62         }
63       '';
64       description = ''
65         Videobridge configuration.
67         See <https://github.com/jitsi/jitsi-videobridge/blob/master/jvb/src/main/resources/reference.conf>
68         for default configuration with comments.
69       '';
70     };
72     xmppConfigs = lib.mkOption {
73       description = ''
74         XMPP servers to connect to.
76         See <https://github.com/jitsi/jitsi-videobridge/blob/master/doc/muc.md> for more information.
77       '';
78       default = { };
79       example = lib.literalExpression ''
80         {
81           "localhost" = {
82             hostName = "localhost";
83             userName = "jvb";
84             domain = "auth.xmpp.example.org";
85             passwordFile = "/var/lib/jitsi-meet/videobridge-secret";
86             mucJids = "jvbbrewery@internal.xmpp.example.org";
87           };
88         }
89       '';
90       type = attrsOf (submodule ({ name, ... }: {
91         options = {
92           hostName = lib.mkOption {
93             type = str;
94             example = "xmpp.example.org";
95             description = ''
96               Hostname of the XMPP server to connect to. Name of the attribute set is used by default.
97             '';
98           };
99           domain = lib.mkOption {
100             type = nullOr str;
101             default = null;
102             example = "auth.xmpp.example.org";
103             description = ''
104               Domain part of JID of the XMPP user, if it is different from hostName.
105             '';
106           };
107           userName = lib.mkOption {
108             type = str;
109             default = "jvb";
110             description = ''
111               User part of the JID.
112             '';
113           };
114           passwordFile = lib.mkOption {
115             type = str;
116             example = "/run/keys/jitsi-videobridge-xmpp1";
117             description = ''
118               File containing the password for the user.
119             '';
120           };
121           mucJids = lib.mkOption {
122             type = str;
123             example = "jvbbrewery@internal.xmpp.example.org";
124             description = ''
125               JID of the MUC to join. JiCoFo needs to be configured to join the same MUC.
126             '';
127           };
128           mucNickname = lib.mkOption {
129             # Upstream DEBs use UUID, let's use hostname instead.
130             type = str;
131             description = ''
132               Videobridges use the same XMPP account and need to be distinguished by the
133               nickname (aka resource part of the JID). By default, system hostname is used.
134             '';
135           };
136           disableCertificateVerification = lib.mkOption {
137             type = bool;
138             default = false;
139             description = ''
140               Whether to skip validation of the server's certificate.
141             '';
142           };
143         };
144         config = {
145           hostName = lib.mkDefault name;
146           mucNickname = lib.mkDefault (builtins.replaceStrings [ "." ] [ "-" ] (
147             config.networking.fqdnOrHostName
148           ));
149         };
150       }));
151     };
153     nat = {
154       localAddress = lib.mkOption {
155         type = nullOr str;
156         default = null;
157         example = "192.168.1.42";
158         description = ''
159           Local address to assume when running behind NAT.
160         '';
161       };
163       publicAddress = lib.mkOption {
164         type = nullOr str;
165         default = null;
166         example = "1.2.3.4";
167         description = ''
168           Public address to assume when running behind NAT.
169         '';
170       };
172       harvesterAddresses = lib.mkOption {
173         type = listOf str;
174         default = [
175           "stunserver.stunprotocol.org:3478"
176           "stun.framasoft.org:3478"
177           "meet-jit-si-turnrelay.jitsi.net:443"
178         ];
179         example = [];
180         description = ''
181           Addresses of public STUN services to use to automatically find
182           the public and local addresses of this Jitsi-Videobridge instance
183           without the need for manual configuration.
185           This option is ignored if {option}`services.jitsi-videobridge.nat.localAddress`
186           and {option}`services.jitsi-videobridge.nat.publicAddress` are set.
187         '';
188       };
189     };
191     extraProperties = lib.mkOption {
192       type = attrsOf str;
193       default = { };
194       description = ''
195         Additional Java properties passed to jitsi-videobridge.
196       '';
197     };
199     openFirewall = lib.mkOption {
200       type = bool;
201       default = false;
202       description = ''
203         Whether to open ports in the firewall for the videobridge.
204       '';
205     };
207     colibriRestApi = lib.mkOption {
208       type = bool;
209       description = ''
210         Whether to enable the private rest API for the COLIBRI control interface.
211         Needed for monitoring jitsi, enabling scraping of the /colibri/stats endpoint.
212       '';
213       default = false;
214     };
215   };
217   config = lib.mkIf cfg.enable {
218     users.groups.jitsi-meet = {};
220     services.jitsi-videobridge.extraProperties =
221       if (cfg.nat.localAddress != null) then {
222         "org.ice4j.ice.harvest.NAT_HARVESTER_LOCAL_ADDRESS" = cfg.nat.localAddress;
223         "org.ice4j.ice.harvest.NAT_HARVESTER_PUBLIC_ADDRESS" = cfg.nat.publicAddress;
224       } else {
225         "org.ice4j.ice.harvest.STUN_MAPPING_HARVESTER_ADDRESSES" = lib.concatStringsSep "," cfg.nat.harvesterAddresses;
226       };
228     systemd.services.jitsi-videobridge2 = let
229       jvbProps = {
230         "-Dnet.java.sip.communicator.SC_HOME_DIR_LOCATION" = "/etc/jitsi";
231         "-Dnet.java.sip.communicator.SC_HOME_DIR_NAME" = "videobridge";
232         "-Djava.util.logging.config.file" = "/etc/jitsi/videobridge/logging.properties";
233         "-Dconfig.file" = format.generate "jvb.conf" jvbConfig;
234         # Mitigate CVE-2021-44228
235         "-Dlog4j2.formatMsgNoLookups" = true;
236       } // (lib.mapAttrs' (k: v: lib.nameValuePair "-D${k}" v) cfg.extraProperties);
237     in
238     {
239       aliases = [ "jitsi-videobridge.service" ];
240       description = "Jitsi Videobridge";
241       after = [ "network.target" ];
242       wantedBy = [ "multi-user.target" ];
244       environment.JAVA_SYS_PROPS = attrsToArgs jvbProps;
246       script = (lib.concatStrings (lib.mapAttrsToList (name: xmppConfig:
247         "export ${toVarName name}=$(cat ${xmppConfig.passwordFile})\n"
248       ) cfg.xmppConfigs))
249       + ''
250         ${pkgs.jitsi-videobridge}/bin/jitsi-videobridge
251       '';
253       serviceConfig = {
254         Type = "exec";
256         DynamicUser = true;
257         User = "jitsi-videobridge";
258         Group = "jitsi-meet";
260         CapabilityBoundingSet = "";
261         NoNewPrivileges = true;
262         ProtectSystem = "strict";
263         ProtectHome = true;
264         PrivateTmp = true;
265         PrivateDevices = true;
266         ProtectHostname = true;
267         ProtectKernelTunables = true;
268         ProtectKernelModules = true;
269         ProtectControlGroups = true;
270         RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
271         RestrictNamespaces = true;
272         LockPersonality = true;
273         RestrictRealtime = true;
274         RestrictSUIDSGID = true;
276         TasksMax = 65000;
277         LimitNPROC = 65000;
278         LimitNOFILE = 65000;
279       };
280     };
282     environment.etc."jitsi/videobridge/logging.properties".source =
283       lib.mkDefault "${pkgs.jitsi-videobridge}/etc/jitsi/videobridge/logging.properties-journal";
285     # (from videobridge2 .deb)
286     # this sets the max, so that we can bump the JVB UDP single port buffer size.
287     boot.kernel.sysctl."net.core.rmem_max" = lib.mkDefault 10485760;
288     boot.kernel.sysctl."net.core.netdev_max_backlog" = lib.mkDefault 100000;
290     networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall
291       [ jvbConfig.videobridge.ice.tcp.port ];
292     networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall
293       [ jvbConfig.videobridge.ice.udp.port ];
295     assertions = [{
296       message = "publicAddress must be set if and only if localAddress is set";
297       assertion = (cfg.nat.publicAddress == null) == (cfg.nat.localAddress == null);
298     }];
299   };
301   meta.maintainers = lib.teams.jitsi.members;