at master 4.1 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 enable = true; 109 110 realm = cfg.domain; 111 lt-cred-mech = true; 112 no-cli = true; 113 114 extraConfig = '' 115 fingerprint 116 user=${cfg.user}:${if cfg.password != null then cfg.password else "@password@"} 117 no-software-attribute 118 ''; 119 } 120 // (optionalAttrs cfg.useAcmeCertificates { 121 cert = "@cert@"; 122 pkey = "@pkey@"; 123 }); 124 125 systemd.services.coturn = 126 let 127 dir = config.security.acme.certs.${cfg.domain}.directory; 128 preStart' = 129 (optionalString (cfg.passwordFile != null) '' 130 ${getExe pkgs.replace-secret} @password@ ${cfg.passwordFile} /run/coturn/turnserver.cfg 131 '') 132 + (optionalString cfg.useAcmeCertificates '' 133 ${getExe pkgs.replace-secret} @cert@ <(echo -n "$CREDENTIALS_DIRECTORY/cert.pem") /run/coturn/turnserver.cfg 134 ${getExe pkgs.replace-secret} @pkey@ <(echo -n "$CREDENTIALS_DIRECTORY/pkey.pem") /run/coturn/turnserver.cfg 135 ''); 136 in 137 (optionalAttrs (preStart' != "") { preStart = mkAfter preStart'; }) 138 // (optionalAttrs cfg.useAcmeCertificates { 139 serviceConfig.LoadCredential = [ 140 "cert.pem:${dir}/fullchain.pem" 141 "pkey.pem:${dir}/key.pem" 142 ]; 143 }); 144 145 security.acme.certs = mkIf cfg.useAcmeCertificates { 146 ${cfg.domain}.postRun = '' 147 systemctl restart coturn.service 148 ''; 149 }; 150 151 networking.firewall = { 152 allowedUDPPorts = cfg.openPorts; 153 allowedTCPPorts = cfg.openPorts; 154 155 allowedUDPPortRanges = with config.services.coturn; [ 156 { 157 from = min-port; 158 to = max-port; 159 } 160 ]; 161 }; 162 } 163 ]); 164}