diff options
| author | sinanmohd <sinan@sinanmohd.com> | 2025-12-27 09:01:13 +0530 |
|---|---|---|
| committer | sinanmohd <sinan@sinanmohd.com> | 2025-12-27 09:08:01 +0530 |
| commit | 5b32b947de3ac1adb4317e9c92094d67561d1230 (patch) | |
| tree | e0edc6f33674cd93c251e71d389d09923f4acf19 /os/kay/modules/network/headscale | |
| parent | 04381c13682a9a7f1e29595bf3edf2abdc55c3b3 (diff) | |
chore(os/kay): refactor sops
Diffstat (limited to 'os/kay/modules/network/headscale')
| -rw-r--r-- | os/kay/modules/network/headscale/default.nix | 210 | ||||
| -rw-r--r-- | os/kay/modules/network/headscale/secrets.yaml | 33 |
2 files changed, 243 insertions, 0 deletions
diff --git a/os/kay/modules/network/headscale/default.nix b/os/kay/modules/network/headscale/default.nix new file mode 100644 index 0000000..6f35c5d --- /dev/null +++ b/os/kay/modules/network/headscale/default.nix @@ -0,0 +1,210 @@ +{ + config, + pkgs, + lib, + headplane, + namescale, + ... +}: +let + url = "https://headscale.${config.global.userdata.domain}"; + stunPort = 3478; + + # A workaround generate a valid Headscale config accepted by Headplane when `config_strict == true`. + settings = lib.recursiveUpdate config.services.headscale.settings { + tls_cert_path = "/dev/null"; + tls_key_path = "/dev/null"; + policy.path = "/dev/null"; + }; + format = pkgs.formats.yaml { }; + headscaleConfig = format.generate "headscale.yml" settings; + + policyFormat = pkgs.formats.json { }; + policy = { + groups = { + "group:owner" = [ "sinan@" ]; + "group:bud" = [ + "sinan@" + "ann@" + ]; + }; + tagOwners = { + "tag:internal" = [ "group:owner" ]; + "tag:bud_clients" = [ "group:bud" ]; + "tag:cusat" = [ "group:owner" ]; + "tag:gaijin" = [ "group:owner" ]; + }; + autoApprovers = { + routes = { + "192.168.43.0/24" = [ + "group:owner" + "tag:internal" + ]; + "192.168.38.0/24" = [ + "group:owner" + "tag:internal" + ]; + }; + exitNode = [ + "group:owner" + "tag:internal" + ]; + }; + acls = [ + { + action = "accept"; + src = [ "*" ]; + dst = [ "namescale@:53" ]; + } + { + action = "accept"; + src = [ "headplane@" ]; + dst = [ "*:*" ]; + } + + { + action = "accept"; + src = [ "group:owner" ]; + dst = [ "*:*" ]; + } + { + action = "accept"; + src = [ "nazer@" ]; + dst = [ "autogroup:internet:*" ]; + } + + { + action = "accept"; + src = [ "group:bud" ]; + dst = [ "tag:bud_clients:*" ]; + } + { + action = "accept"; + src = [ "tag:bud_clients" ]; + dst = [ "tag:bud_clients:80,443" ]; + } + ]; + }; +in +{ + imports = [ + headplane.nixosModules.headplane + namescale.nixosModules.namescale + ]; + + nixpkgs.overlays = [ headplane.overlays.default ]; + environment.systemPackages = [ config.services.headscale.package ]; + + sops.secrets = { + # server + "headplane/cookie_secret" = { + owner = config.services.headscale.user; + sopsFile = ./secrets.yaml; + }; + "headplane/preauth_key" = { + owner = config.services.headscale.user; + sopsFile = ./secrets.yaml; + }; + "namescale/preauth_key".sopsFile = ./secrets.yaml; + "headscale/noise_private_key" = { + owner = config.services.headscale.user; + sopsFile = ./secrets.yaml; + }; + "headscale/derp_private_key" = { + owner = config.services.headscale.user; + sopsFile = ./secrets.yaml; + }; + # client + "headscale/pre_auth_key".sopsFile = ./secrets.yaml; + }; + + networking = { + nameservers = [ "100.100.100.100" ]; + search = [ config.services.headscale.settings.dns.base_domain ]; + + firewall = { + interfaces.ppp0.allowedUDPPorts = [ stunPort ]; + trustedInterfaces = [ config.services.tailscale.interfaceName ]; + }; + }; + # for exit node only + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = true; + "net.ipv6.conf.all.forwarding" = true; + }; + + services = { + headscale = { + enable = true; + port = 8139; + + settings = { + logtail.enabled = false; + server_url = url; + noise.private_key_path = config.sops.secrets."headscale/noise_private_key".path; + dns = { + base_domain = "tsnet.${config.global.userdata.domain}"; + override_local_dns = false; + nameservers.split."${config.services.headscale.settings.dns.base_domain}" = [ + "100.64.0.12" + "fd7a:115c:a1e0::c" + ]; + }; + derp = { + server = { + enabled = true; + private_key_path = config.sops.secrets."headscale/derp_private_key".path; + region_code = config.networking.hostName; + region_name = config.networking.hostName; + stun_listen_addr = "0.0.0.0:${toString stunPort}"; + region_id = 6969; + automatically_add_embedded_derp_region = true; + }; + urls = [ ]; + }; + policy = { + mode = "file"; + path = policyFormat.generate "acl.json" policy; + }; + }; + }; + + headplane = { + enable = true; + settings = { + server = { + port = 8140; + cookie_secret_path = config.sops.secrets."headplane/cookie_secret".path; + }; + headscale = { + inherit url; + config_path = "${headscaleConfig}"; + }; + integration.agent = { + enabled = true; + pre_authkey_path = config.sops.secrets."headplane/preauth_key".path; + }; + }; + }; + + tailscale = { + enable = true; + interfaceName = "headscale"; + openFirewall = true; + + authKeyFile = config.sops.secrets."headscale/pre_auth_key".path; + extraUpFlags = [ + "--login-server=${url}" + "--advertise-exit-node" + "--advertise-routes=192.168.43.0/24,192.168.38.0/24" + "--advertise-tags=tag:internal" + ]; + }; + + namescale = { + enable = true; + environmentFile = config.sops.secrets."namescale/preauth_key".path; + settings.tsnet.coordination_server_url = url; + }; + }; +} diff --git a/os/kay/modules/network/headscale/secrets.yaml b/os/kay/modules/network/headscale/secrets.yaml new file mode 100644 index 0000000..d45ed72 --- /dev/null +++ b/os/kay/modules/network/headscale/secrets.yaml @@ -0,0 +1,33 @@ +headplane: + cookie_secret: ENC[AES256_GCM,data:lJxNpktCyTn99/6ihN+Igz+u3V5LRvh3QxjIiwZ25bU=,iv:YppMXzI2raebGkgyGnFl7jDWtvQgyc5YRmNesby6iOE=,tag:LRWMzUiXqPA7Q1qakeABhQ==,type:str] + preauth_key: ENC[AES256_GCM,data:UthaalTL3pw5YLvDGU/j7FoKWstsize+Z3TQ8EGwEBS2769HaZFGwjArPM5emXEV,iv:3hbdnFUeUMoRyEC9EcoxTpK9YPI0wbPT9dP70X2bsFo=,tag:ety2kbaCU0VsJj8d6rvSSQ==,type:str] +namescale: + preauth_key: ENC[AES256_GCM,data:4gLo5nknO081l4YZ8oa0/PPQNcB/Ef2hv3OgjTb90gHj6jC3pccMKxf0FBKxbQSii7GNQbSd9cYXHkHRBg==,iv:XnwajNYuBtRTyjP+QDzsjgLeq5qUM3O+PmHX4eIPWuY=,tag:Khp+LU0lovF2hF/Ak8Lpqg==,type:str] +headscale: + noise_private_key: ENC[AES256_GCM,data:Hh67ck/aaWmWSPmWpWG8op8kruhVUg32TzBs6TgNZxy/FuB5CUqbWZ9C86yq9awS8fgZDFmqPtSUWQdtNP2AglC2PjVcZVlP,iv:unfxTZ5WV1a01dYZWFYGeQh4ytmruWq7Ytb0xbPERDg=,tag:qK7O4tA/Y38pwyDE4gyN/w==,type:str] + derp_private_key: ENC[AES256_GCM,data:H154flCLVnRv8U3hOXyaEtKPQQo4UWAiZnLZxpf99Cmppp6VEt5hXsu+PQYiUERWWjL3Bry5Az2JBBENOk75S2cXXuHzehkY,iv:ALLHs2S1xkNf/tFYCKYFLHOV9AXeCFUjgq65LoKtMqA=,tag:MDRlnksrUwWOD1KO086VgA==,type:str] + pre_auth_key: ENC[AES256_GCM,data:lFAVurZSbAIGLX+C/Y9IWHUdBnAK2+r8gfyptYDxxM1vUjfZLysc2Znl8J6hOTt9,iv:KnqejSz5Dso6Qt6AUEHL5WaKFkPjzfKPKcFPrQ08vak=,tag:cj20F8xBlUt+7YIH0898UQ==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBocjExRHZxTlBLQno5d0w1 + WjFuTnpRZjVDQTR0WnZxc1ZFVHVXZVpHVG1NCmVlbWdMS1RkeWtacE1rTTRaVE9h + RE1XRDhoU2JmbTJKR3RCMnMvZWZMWlkKLS0tIFIvVEtWb0F5QmRPRHNuU2xhcWdm + ZUpud0gveWlDNWl4andHTm85OWZuQ28KigPDOPCX3Q6LnTZAe8triJUpz0nhmJ+K + XD+VuUHhX/52GU7p3selEwn5O//Bc7zeneolniA79F69RDBpK4OYeA== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCQmRMaGRBcmJwZVI0RWlT + ajl0WHZwTnBLdEcybHRHYzVjTWlkczlYVEVBCmxrQXNiM1dRSlJoRDdtVDZEZjVZ + WUVtZjMrbGhjdWFITElWa3VGZHpxYUUKLS0tIGJ5eUovbHE2R1JzcTRwdXBkNVM4 + NExtOUJrT3pvTmNndUlxekVhbXAxNDAKVYgJ3XNqWyJ5XHYbNnODMUdufFTBG+xE + Nkks0GuJCWMyho4jkksF+mWohGJz50DAZCcve38fGcD9Zkhp1gcYgw== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:24:25Z" + mac: ENC[AES256_GCM,data:wDNxc6cPdUOILZKJ86dYdC+YuOYpC/tkrGQkFSaC84rjhYzYm5rSkwo4NNTqZVamNC5i+8IaFiR+zq8NJM88KUoiFij7FMda6yDdexhgeBLMwCdX6nrjIFavZpJEhwxyHfjuy2mBYO4TU5xGaAgG2Dr6N0eqBNDMJoZzlKmHgo0=,iv:09nC3k+fCCxp+u8qKba3m2mX7K5izUnPcmhGpXjDr7M=,tag:fQFMRFnIIUcmWJGQEfiBzQ==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 |
