at 25.11-pre 4.2 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7 8let 9 inherit (lib) 10 getExe 11 literalExpression 12 mkAfter 13 mkEnableOption 14 mkIf 15 mkMerge 16 mkOption 17 optionalAttrs 18 optionalString 19 ; 20 21 inherit (lib.types) 22 bool 23 listOf 24 nullOr 25 path 26 port 27 str 28 ; 29 30 cfg = config.services.netbird.server.coturn; 31in 32 33{ 34 options.services.netbird.server.coturn = { 35 enable = mkEnableOption "a Coturn server for Netbird, will also open the firewall on the configured range"; 36 37 useAcmeCertificates = mkOption { 38 type = bool; 39 default = false; 40 description = '' 41 Whether to use ACME certificates corresponding to the given domain for the server. 42 ''; 43 }; 44 45 domain = mkOption { 46 type = str; 47 description = "The domain under which the coturn server runs."; 48 }; 49 50 user = mkOption { 51 type = str; 52 default = "netbird"; 53 description = '' 54 The username used by netbird to connect to the coturn server. 55 ''; 56 }; 57 58 password = mkOption { 59 type = nullOr str; 60 default = null; 61 description = '' 62 The password of the user used by netbird to connect to the coturn server. 63 Be advised this will be world readable in the nix store. 64 ''; 65 }; 66 67 passwordFile = mkOption { 68 type = nullOr path; 69 default = null; 70 description = '' 71 The path to a file containing the password of the user used by netbird to connect to the coturn server. 72 ''; 73 }; 74 75 openPorts = mkOption { 76 type = listOf port; 77 default = with config.services.coturn; [ 78 listening-port 79 alt-listening-port 80 tls-listening-port 81 alt-tls-listening-port 82 ]; 83 defaultText = literalExpression '' 84 with config.services.coturn; [ 85 listening-port 86 alt-listening-port 87 tls-listening-port 88 alt-tls-listening-port 89 ]; 90 ''; 91 92 description = '' 93 The list of ports used by coturn for listening to open in the firewall. 94 ''; 95 }; 96 }; 97 98 config = mkIf cfg.enable (mkMerge [ 99 { 100 assertions = [ 101 { 102 assertion = (cfg.password == null) != (cfg.passwordFile == null); 103 message = "Exactly one of `password` or `passwordFile` must be given for the coturn setup."; 104 } 105 ]; 106 107 services.coturn = 108 { 109 enable = true; 110 111 realm = cfg.domain; 112 lt-cred-mech = true; 113 no-cli = true; 114 115 extraConfig = '' 116 fingerprint 117 user=${cfg.user}:${if cfg.password != null then cfg.password else "@password@"} 118 no-software-attribute 119 ''; 120 } 121 // (optionalAttrs cfg.useAcmeCertificates { 122 cert = "@cert@"; 123 pkey = "@pkey@"; 124 }); 125 126 systemd.services.coturn = 127 let 128 dir = config.security.acme.certs.${cfg.domain}.directory; 129 preStart' = 130 (optionalString (cfg.passwordFile != null) '' 131 ${getExe pkgs.replace-secret} @password@ ${cfg.passwordFile} /run/coturn/turnserver.cfg 132 '') 133 + (optionalString cfg.useAcmeCertificates '' 134 ${getExe pkgs.replace-secret} @cert@ <(echo -n "$CREDENTIALS_DIRECTORY/cert.pem") /run/coturn/turnserver.cfg 135 ${getExe pkgs.replace-secret} @pkey@ <(echo -n "$CREDENTIALS_DIRECTORY/pkey.pem") /run/coturn/turnserver.cfg 136 ''); 137 in 138 (optionalAttrs (preStart' != "") { preStart = mkAfter preStart'; }) 139 // (optionalAttrs cfg.useAcmeCertificates { 140 serviceConfig.LoadCredential = [ 141 "cert.pem:${dir}/fullchain.pem" 142 "pkey.pem:${dir}/key.pem" 143 ]; 144 }); 145 146 security.acme.certs = mkIf cfg.useAcmeCertificates { 147 ${cfg.domain}.postRun = '' 148 systemctl restart coturn.service 149 ''; 150 }; 151 152 networking.firewall = { 153 allowedUDPPorts = cfg.openPorts; 154 allowedTCPPorts = cfg.openPorts; 155 156 allowedUDPPortRanges = with config.services.coturn; [ 157 { 158 from = min-port; 159 to = max-port; 160 } 161 ]; 162 }; 163 } 164 ]); 165}