Merge pull request 'tailscale: add support for multiple tailnets' (#26) from develop into release-25.11
All checks were successful
Deploy docs / build-and-deploy (push) Successful in 11s
All checks were successful
Deploy docs / build-and-deploy (push) Successful in 11s
Reviewed-on: #26
This commit is contained in:
commit
e801c318a7
1 changed files with 125 additions and 32 deletions
|
|
@ -1,9 +1,17 @@
|
|||
{ config, lib, ... }:
|
||||
{
|
||||
config,
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
|
||||
let
|
||||
cfg = config.services.tailscale;
|
||||
|
||||
inherit (lib)
|
||||
concatStrings
|
||||
filterAttrs
|
||||
mapAttrsToList
|
||||
mkIf
|
||||
mkOption
|
||||
optional
|
||||
|
|
@ -12,39 +20,124 @@ let
|
|||
in
|
||||
{
|
||||
options.services.tailscale = {
|
||||
tailnets = mkOption {
|
||||
default = { };
|
||||
type = types.attrsOf (
|
||||
types.submodule {
|
||||
options = {
|
||||
loginServer = mkOption {
|
||||
type = types.str;
|
||||
description = "The Tailscale login server to use.";
|
||||
description = "Login server for this tailnet.";
|
||||
};
|
||||
authKeyFile = mkOption {
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
description = "Path to auth key secret.";
|
||||
};
|
||||
enableSSH = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Enable Tailscale SSH functionality.";
|
||||
};
|
||||
acceptDNS = mkOption {
|
||||
type = types.bool;
|
||||
default = true;
|
||||
description = "Enable Tailscale's MagicDNS and custom DNS configuration.";
|
||||
};
|
||||
default = mkOption {
|
||||
type = types.bool;
|
||||
default = false;
|
||||
description = "Connect to this tailnet on boot.";
|
||||
};
|
||||
|
||||
config = mkIf cfg.enable {
|
||||
services.tailscale = {
|
||||
authKeyFile = config.sops.secrets."tailscale/auth-key".path;
|
||||
extraSetFlags = optional cfg.enableSSH "--ssh" ++ optional cfg.acceptDNS "--accept-dns";
|
||||
extraUpFlags = [
|
||||
"--login-server=${cfg.loginServer}"
|
||||
]
|
||||
++ optional cfg.enableSSH "--ssh"
|
||||
++ optional cfg.acceptDNS "--accept-dns";
|
||||
};
|
||||
|
||||
environment.shellAliases = {
|
||||
ts = "${cfg.package}/bin/tailscale";
|
||||
};
|
||||
|
||||
networking.firewall.trustedInterfaces = [ cfg.interfaceName ];
|
||||
|
||||
sops.secrets."tailscale/auth-key" = { };
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config =
|
||||
let
|
||||
defaultTailnets = filterAttrs (_: t: t.default) cfg.tailnets;
|
||||
defaultTailnet =
|
||||
if defaultTailnets == { } then null else builtins.head (builtins.attrValues defaultTailnets);
|
||||
|
||||
entries = mapAttrsToList (name: tcfg: ''
|
||||
TAILNETS["${name}"]="${tcfg.loginServer}|${if tcfg.enableSSH then "true" else "false"}|${
|
||||
if tcfg.acceptDNS then "true" else "false"
|
||||
}|${if tcfg.authKeyFile != null then tcfg.authKeyFile else ""}"
|
||||
'') cfg.tailnets;
|
||||
|
||||
tailnetSwitchCli = pkgs.writeShellScriptBin "tailnet-switch" ''
|
||||
set -euo pipefail
|
||||
|
||||
TAILSCALE="${cfg.package}/bin/tailscale"
|
||||
|
||||
declare -A TAILNETS
|
||||
${concatStrings entries}
|
||||
|
||||
CHOICE="''${1:-}"
|
||||
|
||||
if [[ -z "$CHOICE" ]]; then
|
||||
if [[ -t 0 ]]; then
|
||||
CHOICE=$(printf '%s\n' "''${!TAILNETS[@]}" | sort | ${pkgs.fzf}/bin/fzf --prompt="Switch tailnet: ")
|
||||
else
|
||||
echo "Usage: tailnet-switch <tailnet-name>" >&2
|
||||
printf 'Available tailnets: %s\n' "''${!TAILNETS[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z "''${TAILNETS[$CHOICE]+x}" ]]; then
|
||||
echo "Unknown tailnet: $CHOICE" >&2
|
||||
printf 'Available tailnets: %s\n' "''${!TAILNETS[@]}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
IFS='|' read -r LOGIN_SERVER ENABLE_SSH ACCEPT_DNS AUTH_KEY_FILE <<< "''${TAILNETS[$CHOICE]}"
|
||||
|
||||
echo "Switching to: $CHOICE ($LOGIN_SERVER)"
|
||||
|
||||
"$TAILSCALE" down --accept-risk=lose-ssh 2>/dev/null || true
|
||||
"$TAILSCALE" logout 2>/dev/null || true
|
||||
|
||||
UP_FLAGS=("--login-server=$LOGIN_SERVER")
|
||||
[[ "$ENABLE_SSH" == "true" ]] && UP_FLAGS+=("--ssh")
|
||||
[[ "$ACCEPT_DNS" == "true" ]] && UP_FLAGS+=("--accept-dns")
|
||||
[[ -n "$AUTH_KEY_FILE" ]] && UP_FLAGS+=("--auth-key=$(cat "$AUTH_KEY_FILE")")
|
||||
|
||||
"$TAILSCALE" up "''${UP_FLAGS[@]}"
|
||||
|
||||
echo "Switched to tailnet: $CHOICE"
|
||||
'';
|
||||
in
|
||||
mkIf cfg.enable {
|
||||
assertions = [
|
||||
{
|
||||
assertion =
|
||||
(builtins.length (builtins.attrValues (filterAttrs (_: t: t.default) cfg.tailnets))) <= 1;
|
||||
message = "services.tailscale.tailnets: Only one tailnet can be set as default.";
|
||||
}
|
||||
{
|
||||
assertion = cfg.tailnets != { };
|
||||
message = "services.tailscale.tailnets: At least one tailnet must be defined.";
|
||||
}
|
||||
];
|
||||
|
||||
services.tailscale = mkIf (defaultTailnet != null) (
|
||||
with defaultTailnet;
|
||||
{
|
||||
inherit authKeyFile;
|
||||
extraSetFlags = optional enableSSH "--ssh" ++ optional acceptDNS "--accept-dns";
|
||||
extraUpFlags = [
|
||||
"--login-server=${loginServer}"
|
||||
]
|
||||
++ optional enableSSH "--ssh"
|
||||
++ optional acceptDNS "--accept-dns";
|
||||
}
|
||||
);
|
||||
|
||||
environment.systemPackages = [ tailnetSwitchCli ];
|
||||
|
||||
environment.shellAliases.ts = "${cfg.package}/bin/tailscale";
|
||||
|
||||
networking.firewall.trustedInterfaces = [ cfg.interfaceName ];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue