diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 5b8be7a969ba..5e69834a26d4 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -973,6 +973,7 @@ ./services/networking/clatd.nix ./services/networking/cloudflare-dyndns.nix ./services/networking/cloudflared.nix + ./services/networking/cloudflare-warp.nix ./services/networking/cntlm.nix ./services/networking/connman.nix ./services/networking/consul.nix diff --git a/nixos/modules/services/networking/cloudflare-warp.nix b/nixos/modules/services/networking/cloudflare-warp.nix new file mode 100644 index 000000000000..2ab5f287ac49 --- /dev/null +++ b/nixos/modules/services/networking/cloudflare-warp.nix @@ -0,0 +1,91 @@ +{ config, lib, pkgs, ... }: +let + cfg = config.services.cloudflare-warp; +in +{ + options.services.cloudflare-warp = { + enable = lib.mkEnableOption "Cloudflare Zero Trust client daemon"; + + package = lib.mkPackageOption pkgs "cloudflare-warp" { }; + + rootDir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/cloudflare-warp"; + description = '' + Working directory for the warp-svc daemon. + ''; + }; + + udpPort = lib.mkOption { + type = lib.types.port; + default = 2408; + description = '' + The UDP port to open in the firewall. Warp uses port 2408 by default, but fallback ports can be used + if that conflicts with another service. See the [firewall documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-devices/warp/deployment/firewall#warp-udp-ports) + for the pre-configured available fallback ports. + ''; + }; + + openFirewall = lib.mkEnableOption "opening UDP ports in the firewall" // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + + networking.firewall = lib.mkIf cfg.openFirewall { + allowedUDPPorts = [ cfg.udpPort ]; + }; + + systemd.tmpfiles.rules = [ + "d ${cfg.rootDir} - root root" + "z ${cfg.rootDir} - root root" + ]; + + systemd.services.cloudflare-warp = { + enable = true; + description = "Cloudflare Zero Trust Client Daemon"; + + # lsof is used by the service to determine which UDP port to bind to + # in the case that it detects collisions. + path = [ pkgs.lsof ]; + requires = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = + let + caps = [ + "CAP_NET_ADMIN" + "CAP_NET_BIND_SERVICE" + "CAP_SYS_PTRACE" + ]; + in + { + Type = "simple"; + ExecStart = "${cfg.package}/bin/warp-svc"; + ReadWritePaths = [ "${cfg.rootDir}" "/etc/resolv.conf" ]; + CapabilityBoundingSet = caps; + AmbientCapabilities = caps; + Restart = "always"; + RestartSec = 5; + Environment = [ "RUST_BACKTRACE=full" ]; + WorkingDirectory = cfg.rootDir; + + # See the systemd.exec docs for the canonicalized paths, the service + # makes use of them for logging, and account state info tracking. + # https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#RuntimeDirectory= + StateDirectory = "cloudflare-warp"; + RuntimeDirectory = "cloudflare-warp"; + LogsDirectory = "cloudflare-warp"; + + # The service needs to write to /etc/resolv.conf to configure DNS, so that file would have to + # be world read/writable to run as anything other than root. + User = "root"; + Group = "root"; + }; + }; + }; + + meta.maintainers = with lib.maintainers; [ treyfortmuller ]; +}