tailscalesd/nix/modules/nixos/services/tailscalesd.nix

147 lines
4.4 KiB
Nix
Raw Normal View History

{
config,
lib,
tailscalesdPackage ? null,
...
}:
let
inherit (lib)
mkEnableOption
mkIf
mkOption
types
;
cfg = config.services.tailscalesd;
execStart = lib.concatStringsSep " " (
[ (lib.getExe' cfg.package "tailscalesd") ] ++ map lib.escapeShellArg cfg.extraArgs
);
in
{
options.services.tailscalesd = {
enable = mkEnableOption "tailscalesd Prometheus HTTP service discovery daemon";
package = mkOption {
type = types.nullOr types.package;
default = tailscalesdPackage;
defaultText = "self.packages.<system>.tailscalesd";
description = "Package that provides the tailscalesd executable.";
};
environment = mkOption {
type = types.attrsOf types.str;
default = { };
description = "Extra environment variables for tailscalesd.";
};
credentials = {
bearerTokenFile = mkOption {
type = types.nullOr types.str;
default = null;
example = "/run/secrets/tailscalesd/bearer-token";
description = "Path to bearer token secret loaded with systemd LoadCredential.";
};
clientIdFile = mkOption {
type = types.nullOr types.str;
default = null;
example = "/run/secrets/tailscalesd/client-id";
description = "Path to Tailscale OAuth client id secret loaded with systemd LoadCredential.";
};
clientSecretFile = mkOption {
type = types.nullOr types.str;
default = null;
example = "/run/secrets/tailscalesd/client-secret";
description = "Path to Tailscale OAuth client secret loaded with systemd LoadCredential.";
};
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
description = "Bind address for tailscalesd.";
};
port = mkOption {
type = types.port;
default = 9242;
description = "Bind port for tailscalesd.";
};
interval = mkOption {
type = types.ints.positive;
default = 60;
description = "Polling interval in seconds.";
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [ ];
description = "Extra CLI arguments appended to the tailscalesd command.";
};
openFirewall = mkOption {
type = types.bool;
default = false;
description = "Open the service port in the host firewall.";
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.package != null;
message = "services.tailscalesd.package must be set when services.tailscalesd.enable = true.";
}
{
assertion = cfg.credentials.bearerTokenFile != null;
message = "services.tailscalesd.credentials.bearerTokenFile must be set when services.tailscalesd.enable = true.";
}
{
assertion = cfg.credentials.clientIdFile != null;
message = "services.tailscalesd.credentials.clientIdFile must be set when services.tailscalesd.enable = true.";
}
{
assertion = cfg.credentials.clientSecretFile != null;
message = "services.tailscalesd.credentials.clientSecretFile must be set when services.tailscalesd.enable = true.";
}
];
networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ cfg.port ];
systemd.services.tailscalesd = {
description = "tailscalesd";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
ExecStart = execStart;
Restart = "on-failure";
RestartSec = "5s";
NoNewPrivileges = true;
PrivateTmp = true;
ProtectHome = true;
ProtectSystem = "strict";
WorkingDirectory = "/var/lib/tailscalesd";
StateDirectory = "tailscalesd";
LoadCredential = [
"bearer_token:${cfg.credentials.bearerTokenFile}"
"client_id:${cfg.credentials.clientIdFile}"
"client_secret:${cfg.credentials.clientSecretFile}"
];
};
environment = cfg.environment // {
TAILSCALESD_HOST = cfg.host;
TAILSCALESD_PORT = toString cfg.port;
TAILSCALESD_INTERVAL = toString cfg.interval;
TAILSCALESD_BEARER_TOKEN_FILE = "%d/bearer_token";
TAILSCALESD_CLIENT_ID_FILE = "%d/client_id";
TAILSCALESD_CLIENT_SECRET_FILE = "%d/client_secret";
};
};
};
}