diff options
Diffstat (limited to 'nixpkgs/nixos/modules/services/networking/tailscale.nix')
-rw-r--r-- | nixpkgs/nixos/modules/services/networking/tailscale.nix | 56 |
1 files changed, 49 insertions, 7 deletions
diff --git a/nixpkgs/nixos/modules/services/networking/tailscale.nix b/nixpkgs/nixos/modules/services/networking/tailscale.nix index 3f41646bf01e..12ac6d6da5a8 100644 --- a/nixpkgs/nixos/modules/services/networking/tailscale.nix +++ b/nixpkgs/nixos/modules/services/networking/tailscale.nix @@ -2,9 +2,14 @@ with lib; -let cfg = config.services.tailscale; +let + cfg = config.services.tailscale; + firewallOn = config.networking.firewall.enable; + rpfMode = config.networking.firewall.checkReversePath; + isNetworkd = config.networking.useNetworkd; + rpfIsStrict = rpfMode == true || rpfMode == "strict"; in { - meta.maintainers = with maintainers; [ danderson mbaillie ]; + meta.maintainers = with maintainers; [ danderson mbaillie twitchyliquid64 ]; options.services.tailscale = { enable = mkEnableOption "Tailscale client daemon"; @@ -12,33 +17,70 @@ in { port = mkOption { type = types.port; default = 41641; - description = "The port to listen on for tunnel traffic (0=autoselect)."; + description = lib.mdDoc "The port to listen on for tunnel traffic (0=autoselect)."; }; interfaceName = mkOption { type = types.str; default = "tailscale0"; - description = ''The interface name for tunnel traffic. Use "userspace-networking" (beta) to not use TUN.''; + description = lib.mdDoc ''The interface name for tunnel traffic. Use "userspace-networking" (beta) to not use TUN.''; + }; + + permitCertUid = mkOption { + type = types.nullOr types.nonEmptyStr; + default = null; + description = lib.mdDoc "Username or user ID of the user allowed to to fetch Tailscale TLS certificates for the node."; }; package = mkOption { type = types.package; default = pkgs.tailscale; defaultText = literalExpression "pkgs.tailscale"; - description = "The package to use for tailscale"; + description = lib.mdDoc "The package to use for tailscale"; }; }; config = mkIf cfg.enable { + warnings = optional (firewallOn && rpfIsStrict) "Strict reverse path filtering breaks Tailscale exit node use and some subnet routing setups. Consider setting `networking.firewall.checkReversePath` = 'loose'"; environment.systemPackages = [ cfg.package ]; # for the CLI systemd.packages = [ cfg.package ]; systemd.services.tailscaled = { wantedBy = [ "multi-user.target" ]; - path = [ pkgs.openresolv pkgs.procps ]; + path = [ + config.networking.resolvconf.package # for configuring DNS in some configs + pkgs.procps # for collecting running services (opt-in feature) + pkgs.glibc # for `getent` to look up user shells + ]; serviceConfig.Environment = [ "PORT=${toString cfg.port}" ''"FLAGS=--tun ${lib.escapeShellArg cfg.interfaceName}"'' - ]; + ] ++ (lib.optionals (cfg.permitCertUid != null) [ + "TS_PERMIT_CERT_UID=${cfg.permitCertUid}" + ]); + # Restart tailscaled with a single `systemctl restart` at the + # end of activation, rather than a `stop` followed by a later + # `start`. Activation over Tailscale can hang for tens of + # seconds in the stop+start setup, if the activation script has + # a significant delay between the stop and start phases + # (e.g. script blocked on another unit with a slow shutdown). + # + # Tailscale is aware of the correctness tradeoff involved, and + # already makes its upstream systemd unit robust against unit + # version mismatches on restart for compatibility with other + # linux distros. + stopIfChanged = false; + }; + + networking.dhcpcd.denyInterfaces = [ cfg.interfaceName ]; + + systemd.network.networks."50-tailscale" = mkIf isNetworkd { + matchConfig = { + Name = cfg.interfaceName; + }; + linkConfig = { + Unmanaged = true; + ActivationPolicy = "manual"; + }; }; }; } |