167 lines
5.2 KiB
Nix
167 lines
5.2 KiB
Nix
{ config, lib, pkgs, ...}:
|
|
|
|
with lib;
|
|
let
|
|
cfg = config.services.headscale;
|
|
|
|
userOptions = { config, ... }: {
|
|
options = {
|
|
enablePreAuth = mkOption {
|
|
type = types.bool;
|
|
default = true;
|
|
description = lib.mdDoc ''
|
|
Generate Pre Authorized Token with User
|
|
'';
|
|
};
|
|
preAuthEphemeral = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = lib.mdDoc ''
|
|
Should the token be ephemeral, making the user
|
|
dissappear after no usage
|
|
'';
|
|
};
|
|
preAuthExpiration = mkOption {
|
|
type = types.str;
|
|
default = "1h";
|
|
description = lib.mdDoc ''
|
|
How long should the token be active for
|
|
'';
|
|
};
|
|
preAuthReusable = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = lib.mdDoc ''
|
|
Should the token be able to be used more than once
|
|
'';
|
|
};
|
|
preAuthTags = mkOption {
|
|
type = types.listOf types.str;
|
|
default = [];
|
|
description = lib.mdDoc ''
|
|
How should this login token be tagged
|
|
'';
|
|
};
|
|
preAuthRegen = mkOption {
|
|
type = types.bool;
|
|
default = false;
|
|
description = lib.mdDoc ''
|
|
Should a timer be built to regenerate the token
|
|
'';
|
|
};
|
|
path = mkOption {
|
|
type = types.path;
|
|
default = "/run/headscale_${config._module.args.name}_auth/auth";
|
|
description = mdDoc ''
|
|
Path of generated token
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
mkUserService = name: options: {
|
|
"headscale-ensureUser-${name}" = {
|
|
description = "Ensure '${name}' user exists for headscale";
|
|
wantedBy = ["multi-user.target" "headscale.service"];
|
|
after = ["headscale.service"];
|
|
requires = ["headscale.service"];
|
|
partOf = ["headscale.service"];
|
|
|
|
script = ''
|
|
${pkgs.bash}/bin/bash -c '${cfg.package}/bin/headscale users create ${name} || true'
|
|
'';
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = cfg.user;
|
|
Group = cfg.user;
|
|
};
|
|
};
|
|
};
|
|
|
|
# Make Auth token readable with given set of perms and also user?
|
|
# also generate on timer
|
|
|
|
mkUserPreAuth = name: options: optionalAttrs options.enablePreAuth {
|
|
"headscale-preauth-${name}" = {
|
|
description = "Generate Headscale Preauth Token for '${name}'";
|
|
wantedBy = ["multi-user.target"];
|
|
after = ["headscale-ensureUser-${name}.service"];
|
|
requires = ["headscale-ensureUser-${name}.service"];
|
|
partOf = ["headscale.service"];
|
|
|
|
script = ''
|
|
${cfg.package}/bin/headscale preauthkeys -u ${name} create \
|
|
${lib.optionalString options.preAuthEphemeral "--ephemeral"} \
|
|
${lib.optionalString options.preAuthReusable "--reusable"} \
|
|
--expiration ${options.preAuthExpiration} \
|
|
${lib.optionalString (options.preAuthTags != []) "--tags ${toString options.preAuthTags}"} \
|
|
> /run/headscale_${name}_auth/auth; echo /run/headscale_${name}_auth/auth created
|
|
'';
|
|
|
|
# TODO: Use Activation Script to Generate On Boot
|
|
# with option to regenerate with timer
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
PermissionsStartOnly = "true";
|
|
# Directory Creation Issues Don't Belong To User/Aren't Passed
|
|
# with the specified user, resulting in %t resolving to root's
|
|
# runtime directory
|
|
# https://github.com/containers/podman/issues/12778
|
|
RuntimeDirectory = "headscale_${name}_auth";
|
|
RuntimeDirectoryMode = "0775";
|
|
User = cfg.user;
|
|
Group = cfg.user;
|
|
RemainAfterExit = "yes";
|
|
};
|
|
};
|
|
};
|
|
|
|
mkUserPreAuthRegen = name: options: {
|
|
"headscale-preauth-regen-${name}" = {
|
|
wantedBy = ["multi-user.target" "headscale-ensureUser-${name}.service"];
|
|
after = ["headscale-ensureUser-${name}.service"];
|
|
|
|
script = ''
|
|
${pkgs.systemd}/bin/systemctl restart headscale-preauth-${name}.service
|
|
'';
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
};
|
|
};
|
|
};
|
|
|
|
mkServices = name: options: (mkUserService name options) //
|
|
(mkUserPreAuth name options) //
|
|
(mkUserPreAuthRegen name options);
|
|
|
|
mkTimer = name: options: optionalAttrs options.preAuthRegen {
|
|
wantedBy = ["multi-user.target" "headscale-ensureUser-${name}.service"];
|
|
after = ["headscale-ensureUser-${name}.service"];
|
|
requires = ["headscale-ensureUser-${name}.service"];
|
|
bindsTo = ["headscale.service"];
|
|
partOf = ["headscale.service"];
|
|
|
|
timerConfig = {
|
|
OnUnitActiveSec = options.preAuthExpiration;
|
|
Unit = "headscale-preauth-regen-${name}.service";
|
|
};
|
|
};
|
|
|
|
in
|
|
{
|
|
options.services.headscale.ensureUsers = mkOption {
|
|
default = {};
|
|
type = types.attrsOf (types.submodule userOptions);
|
|
description = lib.mdDoc "Ensure these users exist in headscale";
|
|
};
|
|
config = lib.mkIf (cfg.enable && cfg.ensureUsers != {}) {
|
|
systemd.services = (foldl' (a: b: a // b) {} (attrValues ((mapAttrs
|
|
(n: v: (mkServices n v)) cfg.ensureUsers))));
|
|
|
|
systemd.timers = filterAttrs (n: v: v !={}) (mapAttrs'
|
|
(n: v: nameValuePair "headscale-preauth-${n}" (mkTimer n v)) cfg.ensureUsers);
|
|
};
|
|
}
|