From 5b32b947de3ac1adb4317e9c92094d67561d1230 Mon Sep 17 00:00:00 2001 From: sinanmohd Date: Sat, 27 Dec 2025 09:01:13 +0530 Subject: chore(os/kay): refactor sops --- os/kay/modules/dns/default.nix | 1 + os/kay/modules/dns/secrets.yaml | 25 +++ os/kay/modules/network/default.nix | 80 ---------- os/kay/modules/network/headscale.nix | 198 ----------------------- os/kay/modules/network/headscale/default.nix | 210 +++++++++++++++++++++++++ os/kay/modules/network/headscale/secrets.yaml | 33 ++++ os/kay/modules/network/hurricane.nix | 132 ---------------- os/kay/modules/network/hurricane/default.nix | 132 ++++++++++++++++ os/kay/modules/network/hurricane/secrets.yaml | 28 ++++ os/kay/modules/network/ppp/default.nix | 74 +++++++++ os/kay/modules/network/ppp/secrets.yaml | 28 ++++ os/kay/modules/services/alina.nix | 30 ---- os/kay/modules/services/alina/default.nix | 30 ++++ os/kay/modules/services/alina/secrets.yaml | 26 +++ os/kay/modules/services/mail.nix | 173 -------------------- os/kay/modules/services/mail/default.nix | 173 ++++++++++++++++++++ os/kay/modules/services/mail/secrets.yaml | 28 ++++ os/kay/modules/services/matrix/default.nix | 2 +- os/kay/modules/services/matrix/dendrite.nix | 2 +- os/kay/modules/services/matrix/secrets.yaml | 27 ++++ os/kay/modules/services/nix-cache.nix | 12 -- os/kay/modules/services/nix-cache/default.nix | 12 ++ os/kay/modules/services/nix-cache/secrets.yaml | 26 +++ 23 files changed, 855 insertions(+), 627 deletions(-) create mode 100644 os/kay/modules/dns/secrets.yaml delete mode 100644 os/kay/modules/network/default.nix delete mode 100644 os/kay/modules/network/headscale.nix create mode 100644 os/kay/modules/network/headscale/default.nix create mode 100644 os/kay/modules/network/headscale/secrets.yaml delete mode 100644 os/kay/modules/network/hurricane.nix create mode 100644 os/kay/modules/network/hurricane/default.nix create mode 100644 os/kay/modules/network/hurricane/secrets.yaml create mode 100644 os/kay/modules/network/ppp/default.nix create mode 100644 os/kay/modules/network/ppp/secrets.yaml delete mode 100644 os/kay/modules/services/alina.nix create mode 100644 os/kay/modules/services/alina/default.nix create mode 100644 os/kay/modules/services/alina/secrets.yaml delete mode 100644 os/kay/modules/services/mail.nix create mode 100644 os/kay/modules/services/mail/default.nix create mode 100644 os/kay/modules/services/mail/secrets.yaml create mode 100644 os/kay/modules/services/matrix/secrets.yaml delete mode 100644 os/kay/modules/services/nix-cache.nix create mode 100644 os/kay/modules/services/nix-cache/default.nix create mode 100644 os/kay/modules/services/nix-cache/secrets.yaml (limited to 'os/kay/modules') diff --git a/os/kay/modules/dns/default.nix b/os/kay/modules/dns/default.nix index 6179527..a11f4cd 100644 --- a/os/kay/modules/dns/default.nix +++ b/os/kay/modules/dns/default.nix @@ -29,6 +29,7 @@ in sops.secrets.dns = { owner = config.systemd.services.knot.serviceConfig.User; group = config.systemd.services.knot.serviceConfig.Group; + sopsFile = ./secrets.yaml; }; services.knot = { diff --git a/os/kay/modules/dns/secrets.yaml b/os/kay/modules/dns/secrets.yaml new file mode 100644 index 0000000..e3b8c63 --- /dev/null +++ b/os/kay/modules/dns/secrets.yaml @@ -0,0 +1,25 @@ +dns: ENC[AES256_GCM,data:Nma42ej1Q7cbX3TMgqMYbWLnnHA75B5QDa303/KAeRkdPJNtE92UBIL8VN6+UcEmR00/aQciFmne8tp7Qn3e5DJypbZRXwsiLHCSi3vW8wLn5BwCUq/V9aA0Wm9e22aalqIe/ofpnZElAco=,iv:Ql2SUbUjCaN49kShDVPF41rRXAmNAJKdRhpfVWaJffU=,tag:1NX2tsUClgDu2Q5Y+tgvTw==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmaFR1cWZiS3VjS2RocFYy + THY5UndoT09CTmNRTXVPTGNIV3dMMEplQmcwClJBWFloenlQcU4wd1h1UzdVdEFo + OTJVZkZtVG1nNGJPanZ4KytFcFJBRDAKLS0tIGNmYi9JbUd1TkJYcnVIcVRERFkr + Rkllb3pSdTNlWE5aMkdYSVk4aHVPZFEKniDSHQ7BAYVmlThPP/xh2qS3ai/ZmJ5/ + y+MFVVCUPqCYCt3PXc+YijE3NMV/3uxg81r3t9PVAvUXJLcLGrGQsg== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByOHVuNUtGakZIMHhSK1pM + cFVyNWZ6aDQ1eEE1WEVDVzdtajNFb3BoUnlZCkYyaHgwVHZMS3prazJGYVBCeWxV + b3NyUVhsOUViM2tTVUxlR0R5V25WUXcKLS0tIHA4UkRmVHkwc2tKTHVHZWs1QWl1 + V3J4L3B0YTJ6eTRuVFBCckcyYTlJaFUKFu++nbDHaixxRS6ybqztQAvYWF3vYtTq + Gid9hEmcNrSQf3hLNavHw0fLI3CYO5wKriODZ+bShg4xOPFW62g6Bg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:16:27Z" + mac: ENC[AES256_GCM,data:EdJnlxHdpGmoOhKtD1pjfvq47cPGKRShqqLzmdQAveGbS50Vc/ytyGznDctWi7BhUrBq1xnduskvrDKh0iRQs6Eg72iVmY/QgDA4eQN95lSaIWsHH5lL61WcvVzur/Ya8F2cUivgp3CejM2bi+eZa0LeYD+kuDt0NhnUa8pZai4=,iv:Coit8Z0pLpckN7ZKDBbqkJu+q6BfQL7eu/o9muAcCvI=,tag:UVz4WHPNDpeVNOiXthHqLg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/os/kay/modules/network/default.nix b/os/kay/modules/network/default.nix deleted file mode 100644 index 281751a..0000000 --- a/os/kay/modules/network/default.nix +++ /dev/null @@ -1,80 +0,0 @@ -{ config, pkgs, ... }: - -let - inetVlan = 1003; - wanInterface = "enp3s0"; - nameServer = [ - "1.0.0.1" - "1.1.1.1" - ]; -in -{ - imports = [ - ./router.nix - ./hurricane.nix - ./headscale.nix - ]; - - sops.secrets = { - "ppp/chap-secrets" = { }; - "ppp/pap-secrets" = { }; - "ppp/username" = { }; - }; - - networking = { - tempAddresses = "disabled"; - vlans.wan = { - id = inetVlan; - interface = wanInterface; - }; - }; - - services = { - dnsmasq = { - enable = true; - settings = { - server = nameServer; - bind-interfaces = true; - }; - }; - - pppd = { - enable = true; - - config = '' - plugin pppoe.so - debug - - nic-wan - defaultroute - ipv6 ::1337, - noauth - - persist - lcp-echo-adaptive - lcp-echo-interval 1 - lcp-echo-failure 5 - ''; - - script."01-ipv6-ra" = { - type = "ip-up"; - runtimeInputs = [ pkgs.procps ]; - - text = '' - sysctl net.ipv6.conf.ppp0.accept_ra=2 - ''; - }; - - peers.keralavision = { - enable = true; - autostart = true; - configFile = config.sops.secrets."ppp/username".path; - }; - - secret = { - chap = config.sops.secrets."ppp/chap-secrets".path; - pap = config.sops.secrets."ppp/pap-secrets".path; - }; - }; - }; -} diff --git a/os/kay/modules/network/headscale.nix b/os/kay/modules/network/headscale.nix deleted file mode 100644 index 077aa8b..0000000 --- a/os/kay/modules/network/headscale.nix +++ /dev/null @@ -1,198 +0,0 @@ -{ - 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; - "headplane/preauth_key".owner = config.services.headscale.user; - "namescale/preauth_key" = { }; - "headscale/noise_private_key".owner = config.services.headscale.user; - "headscale/derp_private_key".owner = config.services.headscale.user; - # client - "headscale/pre_auth_key" = { }; - }; - - 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/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 diff --git a/os/kay/modules/network/hurricane.nix b/os/kay/modules/network/hurricane.nix deleted file mode 100644 index e815136..0000000 --- a/os/kay/modules/network/hurricane.nix +++ /dev/null @@ -1,132 +0,0 @@ -{ - config, - pkgs, - lib, - ... -}: - -let - iface = "hurricane"; - remote = "216.218.221.42"; - - clinet = "2001:470:35:72a::2"; - server = "2001:470:35:72a::1"; - - prefix64 = "2001:470:36:72a::/64"; - prefix48 = "2001:470:ee65::/48"; - - makeAddr = - prefix: host: - let - split = lib.strings.splitString "/" prefix; - in - { - address = "${lib.head split}${host}"; - prefixLength = lib.toInt (lib.last split); - }; -in -{ - networking = { - sits.${iface} = { - inherit remote; - ttl = 225; - }; - interfaces.${iface} = { - mtu = 1472; # 1492(ppp0) - 20 - ipv6.addresses = [ - { - address = clinet; - prefixLength = 64; - } - - (makeAddr prefix64 "1") - (makeAddr prefix48 "1") - (makeAddr prefix48 "1337") - ]; - }; - - iproute2 = { - enable = true; - rttablesExtraConfig = "200 hurricane"; - }; - - firewall = { - extraCommands = "iptables -A INPUT --proto 41 --source ${remote} --jump ACCEPT"; - extraStopCommands = "iptables -D INPUT --proto 41 --source ${remote} --jump ACCEPT"; - }; - }; - - sops.secrets = { - "hurricane/username" = { }; - "hurricane/update_key" = { }; - "hurricane/tunnel_id" = { }; - }; - - systemd.services."network-route-${iface}" = { - description = "Routing configuration of ${iface}"; - wantedBy = [ - "network-setup.service" - "network.target" - ]; - before = [ "network-setup.service" ]; - bindsTo = [ "network-addresses-hurricane.service" ]; - after = [ - "network-pre.target" - "network-addresses-hurricane.service" - ]; - # restart rather than stop+start this unit to prevent the - # network from dying during switch-to-configuration. - stopIfChanged = false; - - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - - path = [ pkgs.iproute2 ]; - script = '' - echo -n "adding route" - - ip -6 rule add from ${clinet}/64 table hurricane || exit 1 - ip -6 rule add from ${prefix64} table hurricane || exit 1 - ip -6 rule add from ${prefix48} table hurricane || exit 1 - - ip -6 route add default via ${server} dev hurricane table hurricane || exit 1 - ''; - preStop = '' - echo -n "deleting route" - - ip -6 route del default via ${server} dev hurricane table hurricane || exit 1 - - ip -6 rule del from ${prefix48} table hurricane || exit 1 - ip -6 rule del from ${prefix64} table hurricane || exit 1 - ip -6 rule del from ${clinet}/64 table hurricane || exit 1 - ''; - }; - - services.pppd.script."01-${iface}" = { - runtimeInputs = with pkgs; [ - curl - coreutils - iproute2 - iputils - ]; - text = '' - wan_ip="$4" - username="$(cat ${config.sops.secrets."hurricane/username".path})" - update_key="$(cat ${config.sops.secrets."hurricane/update_key".path})" - tunnel_id="$(cat ${config.sops.secrets."hurricane/tunnel_id".path})" - - auth_url="https://$username:$update_key@ipv4.tunnelbroker.net/nic/update?hostname=$tunnel_id" - until curl --silent "$auth_url"; do - sleep 1 - done - - while [ ! -e /sys/class/net/${iface} ]; do - sleep 1 # make sure ${iface} is up - done - - ip tunnel change ${iface} local "$wan_ip" mode sit - ''; - }; -} diff --git a/os/kay/modules/network/hurricane/default.nix b/os/kay/modules/network/hurricane/default.nix new file mode 100644 index 0000000..63be43e --- /dev/null +++ b/os/kay/modules/network/hurricane/default.nix @@ -0,0 +1,132 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + iface = "hurricane"; + remote = "216.218.221.42"; + + clinet = "2001:470:35:72a::2"; + server = "2001:470:35:72a::1"; + + prefix64 = "2001:470:36:72a::/64"; + prefix48 = "2001:470:ee65::/48"; + + makeAddr = + prefix: host: + let + split = lib.strings.splitString "/" prefix; + in + { + address = "${lib.head split}${host}"; + prefixLength = lib.toInt (lib.last split); + }; +in +{ + networking = { + sits.${iface} = { + inherit remote; + ttl = 225; + }; + interfaces.${iface} = { + mtu = 1472; # 1492(ppp0) - 20 + ipv6.addresses = [ + { + address = clinet; + prefixLength = 64; + } + + (makeAddr prefix64 "1") + (makeAddr prefix48 "1") + (makeAddr prefix48 "1337") + ]; + }; + + iproute2 = { + enable = true; + rttablesExtraConfig = "200 hurricane"; + }; + + firewall = { + extraCommands = "iptables -A INPUT --proto 41 --source ${remote} --jump ACCEPT"; + extraStopCommands = "iptables -D INPUT --proto 41 --source ${remote} --jump ACCEPT"; + }; + }; + + sops.secrets = { + "hurricane/username".sopsFile = ./secrets.yaml; + "hurricane/update_key".sopsFile = ./secrets.yaml; + "hurricane/tunnel_id".sopsFile = ./secrets.yaml; + }; + + systemd.services."network-route-${iface}" = { + description = "Routing configuration of ${iface}"; + wantedBy = [ + "network-setup.service" + "network.target" + ]; + before = [ "network-setup.service" ]; + bindsTo = [ "network-addresses-hurricane.service" ]; + after = [ + "network-pre.target" + "network-addresses-hurricane.service" + ]; + # restart rather than stop+start this unit to prevent the + # network from dying during switch-to-configuration. + stopIfChanged = false; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + + path = [ pkgs.iproute2 ]; + script = '' + echo -n "adding route" + + ip -6 rule add from ${clinet}/64 table hurricane || exit 1 + ip -6 rule add from ${prefix64} table hurricane || exit 1 + ip -6 rule add from ${prefix48} table hurricane || exit 1 + + ip -6 route add default via ${server} dev hurricane table hurricane || exit 1 + ''; + preStop = '' + echo -n "deleting route" + + ip -6 route del default via ${server} dev hurricane table hurricane || exit 1 + + ip -6 rule del from ${prefix48} table hurricane || exit 1 + ip -6 rule del from ${prefix64} table hurricane || exit 1 + ip -6 rule del from ${clinet}/64 table hurricane || exit 1 + ''; + }; + + services.pppd.script."01-${iface}" = { + runtimeInputs = with pkgs; [ + curl + coreutils + iproute2 + iputils + ]; + text = '' + wan_ip="$4" + username="$(cat ${config.sops.secrets."hurricane/username".path})" + update_key="$(cat ${config.sops.secrets."hurricane/update_key".path})" + tunnel_id="$(cat ${config.sops.secrets."hurricane/tunnel_id".path})" + + auth_url="https://$username:$update_key@ipv4.tunnelbroker.net/nic/update?hostname=$tunnel_id" + until curl --silent "$auth_url"; do + sleep 1 + done + + while [ ! -e /sys/class/net/${iface} ]; do + sleep 1 # make sure ${iface} is up + done + + ip tunnel change ${iface} local "$wan_ip" mode sit + ''; + }; +} diff --git a/os/kay/modules/network/hurricane/secrets.yaml b/os/kay/modules/network/hurricane/secrets.yaml new file mode 100644 index 0000000..bbb0b57 --- /dev/null +++ b/os/kay/modules/network/hurricane/secrets.yaml @@ -0,0 +1,28 @@ +hurricane: + username: ENC[AES256_GCM,data:qPZB7icdzaYt,iv:EeucYLIWUOTKeWsnbzc5KrNwXj3EGAECoz5wdPrfMiY=,tag:65zQIFgUL8jNejzIGN56zQ==,type:str] + update_key: ENC[AES256_GCM,data:q9tzqMMT9nI69KeC9utyiRQuzPuPnwwn4pEU01QF074m+J+FP53RDQ==,iv:8ZZ0Nc/8fIQYxC51Fsz5NwEXytgMYvLoqS2uqLDP5sw=,tag:QyKcz9IgOjcvSiEP8HrROQ==,type:str] + tunnel_id: ENC[AES256_GCM,data:at2gf+GP,iv:ilIJ+MUXUugRGZMJjHIs/E7nt/daDBxjmCODcldkCC8=,tag:qB3xE6WP4O4aQgyb+jO5SQ==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1M250TTZNT0U5TE14T1Ar + OGF3MzZKanFWeVJ6NDVyR0ptNWdqVmFQUDMwCmhESnVwTlpSaEJSRDg4dUo3d0Jp + M2ZzZmlYZ3BCcWpHcXYwU1NZbXFsejAKLS0tIDd3ZkdmRTczN3V1ZFN0VXhOM0hz + NC9IWU80RkdrTUFGTWhjOXpwTTdzK3cKX6P58b/Zf81CkQopzQgXEH38BVJ8dm3c + T3il1Di+oV4da29QOdgQPLthpoa8c/6Mfw70XC1pCqJViTYGQSV/ww== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFd3dDTmFiRjkwSTNlY2lQ + bWpMTHpCNFhVei9EcUR1RkxteUtXdzRsMUUwCjNqYW5UdTFXdzFWMW1HL1pZL2pz + Q2lIbktpUGtVSStoekdrQUJkcDZGSFkKLS0tIFIwZUo1SDd5UUxvaHU5aDg2alFO + K1ZsMGtjb0ZJUzdRNllxc3lxRVpPb2MK7jYH9Vd/BQW6M2w4gpZ/7/Fvup2enPct + z8b9coCmFfYkQMOopar5Qq+1Tf+sXmt+e9T4XWdRTGer3si8/X+jmA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:19:40Z" + mac: ENC[AES256_GCM,data:kHw69RgfHhmMzaIUoPL0DziPOmY+7dBXWVzLO2Yo8fun7egtqPLqjmDT11BSvGO7SBBBJkzTUjoV/8kQuui2mEaNZ9Pu6yaLEuGoWU/yN8rwGyEAvMW/jsyRKI/featE1kUgmWrTrRdHw/oXCDUEABRGk51v67NwQef0nlGhjM8=,iv:GWRU/avtXRSJ3tjgt4tKH5A6srOp/N7jV0kZAC/GX8Q=,tag:2k/1UwWj56mUXMVQBBM5ng==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/os/kay/modules/network/ppp/default.nix b/os/kay/modules/network/ppp/default.nix new file mode 100644 index 0000000..43059b6 --- /dev/null +++ b/os/kay/modules/network/ppp/default.nix @@ -0,0 +1,74 @@ +{ config, pkgs, ... }: + +let + inetVlan = 1003; + wanInterface = "enp3s0"; + nameServer = [ + "1.0.0.1" + "1.1.1.1" + ]; +in +{ + sops.secrets = { + "ppp/chap-secrets".sopsFile = ./secrets.yaml; + "ppp/pap-secrets".sopsFile = ./secrets.yaml; + "ppp/username".sopsFile = ./secrets.yaml; + }; + + networking = { + tempAddresses = "disabled"; + vlans.wan = { + id = inetVlan; + interface = wanInterface; + }; + }; + + services = { + dnsmasq = { + enable = true; + settings = { + server = nameServer; + bind-interfaces = true; + }; + }; + + pppd = { + enable = true; + + config = '' + plugin pppoe.so + debug + + nic-wan + defaultroute + ipv6 ::1337, + noauth + + persist + lcp-echo-adaptive + lcp-echo-interval 1 + lcp-echo-failure 5 + ''; + + script."01-ipv6-ra" = { + type = "ip-up"; + runtimeInputs = [ pkgs.procps ]; + + text = '' + sysctl net.ipv6.conf.ppp0.accept_ra=2 + ''; + }; + + peers.keralavision = { + enable = true; + autostart = true; + configFile = config.sops.secrets."ppp/username".path; + }; + + secret = { + chap = config.sops.secrets."ppp/chap-secrets".path; + pap = config.sops.secrets."ppp/pap-secrets".path; + }; + }; + }; +} diff --git a/os/kay/modules/network/ppp/secrets.yaml b/os/kay/modules/network/ppp/secrets.yaml new file mode 100644 index 0000000..3df903a --- /dev/null +++ b/os/kay/modules/network/ppp/secrets.yaml @@ -0,0 +1,28 @@ +ppp: + chap-secrets: ENC[AES256_GCM,data:WAQwrIt66iL7rOPR0WQgRxTYHHjrMNXUqf/DoiE=,iv:ZOs3OQ0Lu9zr/6slG/q07jZ94VRx8XaomNFP1isHo9o=,tag:I1dzfINQvU2fiVku8IDK9A==,type:str] + pap-secrets: ENC[AES256_GCM,data:QWMpPeJSUd3KJa6c//3Zu3nlsnE4l0FBhEqFggw=,iv:uTziGG8dSaklA3uRn+JqfONde6oL/3q5wXS2TP2e264=,tag:R5+q4k2XAEW+8nYPMLVObg==,type:str] + username: ENC[AES256_GCM,data:PBZlPw8SgUfm0apbVf6GVNkn,iv:ivYn9irS7hwdvN8f3kDDGs8gGx+kWtW1YHheKgQMF2w=,tag:VPokCflGM4pDL/+VBfbTsA==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIcUt4blkrZzZHMjFjT1o2 + TDRUZ09DckRNQzhhNmgvZi9tRVQ0WUdIZXhjCmpXQ0craFRkQU5neFdnZTVmbHcx + STFSYk51cDVyZ3I2UmFwT1pHQnJKc2sKLS0tIFNhKzNKRzJ4OVBUVm00ZjJ5NHZi + RDNTZDVLM05heXh3cXdMZFF4TVhCeFEK0YogisCvzPS1KgQFGjziGFLpiqBtfIAx + 90qk4c/8Wmqnt2bW5GBCEl5iUHW7S7etCIZHTZp7WY6Y/y4KEQcFQA== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWTkt0SjA1YXd6OGx0N2Ix + RmZzVHNOZUZ1V0taeGk4TDFrNi96bi9CTUhzClpDcGVQTFJqZWgzUWxLTmJXd0pT + UGhlUTlpS1QxRmFmbTIxYzlLbGxpTWMKLS0tIHIxTHduRXNJdHpkdm1xYWZlbjZ3 + bWdUcDlLVVljcTVoVEpaTWFIeDlUZGsKMFwWXXb0CsVdb2neSbZlPuKH4p+esW8u + fNzL8nrZmqqcRzncXFB0PHU4iNKhwzouHEC+6Ny4V7v5bbOSyb2jAg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:17:57Z" + mac: ENC[AES256_GCM,data:43K/T2qFlgHh9008KAiRoYDB9K0B+PqDQfy9pRconml37FuSQhFHowpsjGXEh/md78i6xr4B1wQal+G2BLlWNF5BEKFpZ59Bkpe3OUa/I8yTDUIHPjvoSLAMVdsRxpn3qgFUeLhEpYEycB0sYwQY3XS9Vu3cOx1T+5I9jn6K6d4=,iv:OGvhVzYUtncE1LaSDOFVLhDuD+uOKA1bgYUavgqgLf8=,tag:P9gKH394XXWggXgVBCcspg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/os/kay/modules/services/alina.nix b/os/kay/modules/services/alina.nix deleted file mode 100644 index c567953..0000000 --- a/os/kay/modules/services/alina.nix +++ /dev/null @@ -1,30 +0,0 @@ -{ config, alina, ... }: -let - domain = "alinafs.com"; -in -{ - imports = [ alina.nixosModules.alina ]; - - sops.secrets."misc/alina" = { }; - - services.postgresql = { - ensureDatabases = [ "alina" ]; - ensureUsers = [ - { - name = "alina"; - ensureDBOwnership = true; - } - ]; - }; - - services.alina = { - enable = true; - port = 8006; - environmentFile = config.sops.secrets."misc/alina".path; - settings.server = { - data = "/hdd/alina"; - file_size_limit = 1024 * 1024 * 1024; # 1GB - public_url = "https://${domain}"; - }; - }; -} diff --git a/os/kay/modules/services/alina/default.nix b/os/kay/modules/services/alina/default.nix new file mode 100644 index 0000000..a2a18dd --- /dev/null +++ b/os/kay/modules/services/alina/default.nix @@ -0,0 +1,30 @@ +{ config, alina, ... }: +let + domain = "alinafs.com"; +in +{ + imports = [ alina.nixosModules.alina ]; + + sops.secrets."misc/alina".sopsFile = ./secrets.yaml; + + services.postgresql = { + ensureDatabases = [ "alina" ]; + ensureUsers = [ + { + name = "alina"; + ensureDBOwnership = true; + } + ]; + }; + + services.alina = { + enable = true; + port = 8006; + environmentFile = config.sops.secrets."misc/alina".path; + settings.server = { + data = "/hdd/alina"; + file_size_limit = 1024 * 1024 * 1024; # 1GB + public_url = "https://${domain}"; + }; + }; +} diff --git a/os/kay/modules/services/alina/secrets.yaml b/os/kay/modules/services/alina/secrets.yaml new file mode 100644 index 0000000..b56b3ed --- /dev/null +++ b/os/kay/modules/services/alina/secrets.yaml @@ -0,0 +1,26 @@ +misc: + alina: ENC[AES256_GCM,data:wLxE9pcr+m3XVtHjraZvSSgUWpH+JggTUPedUtRwD/KtR6Ic1miRwqOLudlHrR9OH8dTE96nZ+DYbj1b0Nkf8iITeC+3OCFZ7SSAdF5B11squQc=,iv:XkJU0nuCShGxj92hEsUo9648WfcUssXuHWXLQMrhBC8=,tag:ygpcXyDRaUNJ5g26SV+yqQ==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuSGwzd1J5aFRQZTlFb2Z4 + bHN0WkVTYVEwMkRsSmZ5bi9rQnoySDdqRmdBCm82Q0xzVnZySVoyZjZNbWRhNkdH + eHhsL01KMkZlM004cmpEcjRVRExIV2sKLS0tIDd4UTlrSStpQnJlVTBZL3JkcEVO + Z0lQckhtajgxM0M4ZUhZU2VDRm1CTm8KuGXWhWLI1bL/y7xGaWyKX0Ku3oqCYqHj + 6i4cW2x/4tRWqjNE2kzAPTRYlWlKq4P3Db+AUnwONbcOVvvW+HWy1g== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVRjhnZWZhWnV4YlRMNHMy + aS9LRmVlZGhwTUtnWGdESGY4RUIvMDBuV2tJCkxmVC9nY2h6RmZTeS9UT3VEMVVK + UTJWdCtrd2pWTkFYSXdoUnhaR0ZTblUKLS0tIGxLL3p5eWVJZUNWM2JXc0tZYmJC + ZFI3c0Z5VzBqYTBVRncvcHpCVXZqemMKQ6hJqsPvGXvzDe2jGy4fGZjTjHZLRdqZ + teGkXgxrTBmoAwt8EnFCeORzzxe27JteG6Yyjh/bLqqmND9Za4w2kA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:26:57Z" + mac: ENC[AES256_GCM,data:z5Lt2boUz8BTGV79gkO5VRfN2htlc54PcbSmMJiJp1IrIV+PUtnr0CtZDK6/SY83Wl947ECKJBLHlJ2pFfEK97joDDyKmwEKX+51hyoSAcDJ1ldEzHQ7TGZtxGTG2yTSSJl15hW3twF7bn3IQtSp0xzHfYJd1+5rGhtzh+RlCoE=,iv:kTtQbFxDCnbic9wLu8tFx5TroMkVUTlvK/0rE+u3aHQ=,tag:SxvowKnokavo3aXBkF6eRA==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/os/kay/modules/services/mail.nix b/os/kay/modules/services/mail.nix deleted file mode 100644 index 685461f..0000000 --- a/os/kay/modules/services/mail.nix +++ /dev/null @@ -1,173 +0,0 @@ -{ config, pkgs, ... }: -let - ipv6 = "2001:470:ee65::1337"; - domain = config.global.userdata.domain; - username = config.global.userdata.name; - email = [ - "${username}@${domain}" - - # used by github automation - # https://github.com/nocodb/nocodb/blob/32826d4b24e9285b898bb3547fdf550f81c930bb/nix/bumper/bumper.sh#L5 - "auto@${domain}" - # used by mail.sinanmohd.com - "postmaster@${domain}" - # used by ns1.sinanmohd.com - "hostmaster@${domain}" - ]; - - credentials_directory = "/run/credentials/stalwart-mail.service"; -in -{ - security.acme.certs.${domain}.postRun = "systemctl restart stalwart-mail.service"; - sops.secrets = { - "mail.${domain}/dkim_rsa" = { }; - "mail.${domain}/dkim_ed25519" = { }; - "mail.${domain}/password" = { }; - }; - - systemd.services.stalwart-mail.serviceConfig.LoadCredential = [ - "password:${config.sops.secrets."mail.${domain}/password".path}" - - "dkim_rsa:${config.sops.secrets."mail.${domain}/dkim_rsa".path}" - "dkim_ed25519:${config.sops.secrets."mail.${domain}/dkim_ed25519".path}" - - "cert:${config.security.acme.certs.${domain}.directory}/fullchain.pem" - "key:${config.security.acme.certs.${domain}.directory}/key.pem" - ]; - - services.postgresql = { - ensureDatabases = [ "stalwart" ]; - ensureUsers = [ - { - name = "stalwart"; - ensureDBOwnership = true; - } - ]; - }; - - services.stalwart-mail = { - enable = true; - openFirewall = true; - - settings = { - queue.outbound = { - ip-strategy = "ipv6_then_ipv4"; - source-ip.v6 = "['${ipv6}']"; - tls.starttls = "optional"; - }; - http.url = "'https://stalwart.${domain}'"; - - server = { - hostname = "mail.${domain}"; - listener = { - smtp = { - bind = [ - "[${ipv6}]:25" - "0.0.0.0:25" - ]; - protocol = "smtp"; - }; - submission = { - bind = "[::]:587"; - protocol = "smtp"; - }; - submissions = { - bind = "[::]:465"; - protocol = "smtp"; - tls.implicit = true; - }; - imaptls = { - bind = "[::]:993"; - protocol = "imap"; - tls.implicit = true; - }; - http = { - bind = "[::]:8085"; - protocol = "http"; - }; - }; - }; - - signature = { - rsa = { - private-key = "%{file:${credentials_directory}/dkim_rsa}%"; - inherit domain; - selector = "rsa"; - headers = [ - "From" - "To" - "Date" - "Subject" - "Message-ID" - ]; - algorithm = "rsa-sha-256"; - canonicalization = "simple/simple"; - - set-body-length = true; - expire = "2d"; - report = true; - }; - ed25519 = { - private-key = "%{file:${credentials_directory}/dkim_ed25519}%"; - inherit domain; - selector = "ed25519"; - headers = [ - "From" - "To" - "Date" - "Subject" - "Message-ID" - ]; - algorithm = "ed25519-sha256"; - canonicalization = "simple/simple"; - - set-body-length = true; - expire = "2d"; - report = true; - }; - }; - - certificate."default" = { - cert = "%{file:${credentials_directory}/cert}%"; - private-key = "%{file:${credentials_directory}/key}%"; - }; - - storage = { - data = "postgresql"; - fts = "postgresql"; - blob = "postgresql"; - lookup = "postgresql"; - directory = "memory"; - }; - store.postgresql = { - type = "postgresql"; - host = "localhost"; - database = "stalwart"; - user = "stalwart"; - timeout = "15s"; - tls.enable = false; - pool.max-connections = 10; - }; - - directory."memory" = { - type = "memory"; - - principals = [ - { - class = "admin"; - name = "${username}@${domain}"; - secret = "%{file:${credentials_directory}/password}%"; - inherit email; - } - { - # for mta-sts & dmarc reports - class = "individual"; - name = "reports@${domain}"; - secret = "%{file:${credentials_directory}/password}%"; - email = [ "reports@${domain}" ]; - } - ]; - }; - }; - }; -} diff --git a/os/kay/modules/services/mail/default.nix b/os/kay/modules/services/mail/default.nix new file mode 100644 index 0000000..01f44bb --- /dev/null +++ b/os/kay/modules/services/mail/default.nix @@ -0,0 +1,173 @@ +{ config, ... }: +let + ipv6 = "2001:470:ee65::1337"; + domain = config.global.userdata.domain; + username = config.global.userdata.name; + email = [ + "${username}@${domain}" + + # used by github automation + # https://github.com/nocodb/nocodb/blob/32826d4b24e9285b898bb3547fdf550f81c930bb/nix/bumper/bumper.sh#L5 + "auto@${domain}" + # used by mail.sinanmohd.com + "postmaster@${domain}" + # used by ns1.sinanmohd.com + "hostmaster@${domain}" + ]; + + credentials_directory = "/run/credentials/stalwart-mail.service"; +in +{ + security.acme.certs.${domain}.postRun = "systemctl restart stalwart-mail.service"; + sops.secrets = { + "mail.${domain}/dkim_rsa".sopsFile = ./secrets.yaml; + "mail.${domain}/dkim_ed25519".sopsFile = ./secrets.yaml; + "mail.${domain}/password".sopsFile = ./secrets.yaml; + }; + + systemd.services.stalwart-mail.serviceConfig.LoadCredential = [ + "password:${config.sops.secrets."mail.${domain}/password".path}" + + "dkim_rsa:${config.sops.secrets."mail.${domain}/dkim_rsa".path}" + "dkim_ed25519:${config.sops.secrets."mail.${domain}/dkim_ed25519".path}" + + "cert:${config.security.acme.certs.${domain}.directory}/fullchain.pem" + "key:${config.security.acme.certs.${domain}.directory}/key.pem" + ]; + + services.postgresql = { + ensureDatabases = [ "stalwart" ]; + ensureUsers = [ + { + name = "stalwart"; + ensureDBOwnership = true; + } + ]; + }; + + services.stalwart-mail = { + enable = true; + openFirewall = true; + + settings = { + queue.outbound = { + ip-strategy = "ipv6_then_ipv4"; + source-ip.v6 = "['${ipv6}']"; + tls.starttls = "optional"; + }; + http.url = "'https://stalwart.${domain}'"; + + server = { + hostname = "mail.${domain}"; + listener = { + smtp = { + bind = [ + "[${ipv6}]:25" + "0.0.0.0:25" + ]; + protocol = "smtp"; + }; + submission = { + bind = "[::]:587"; + protocol = "smtp"; + }; + submissions = { + bind = "[::]:465"; + protocol = "smtp"; + tls.implicit = true; + }; + imaptls = { + bind = "[::]:993"; + protocol = "imap"; + tls.implicit = true; + }; + http = { + bind = "[::]:8085"; + protocol = "http"; + }; + }; + }; + + signature = { + rsa = { + private-key = "%{file:${credentials_directory}/dkim_rsa}%"; + inherit domain; + selector = "rsa"; + headers = [ + "From" + "To" + "Date" + "Subject" + "Message-ID" + ]; + algorithm = "rsa-sha-256"; + canonicalization = "simple/simple"; + + set-body-length = true; + expire = "2d"; + report = true; + }; + ed25519 = { + private-key = "%{file:${credentials_directory}/dkim_ed25519}%"; + inherit domain; + selector = "ed25519"; + headers = [ + "From" + "To" + "Date" + "Subject" + "Message-ID" + ]; + algorithm = "ed25519-sha256"; + canonicalization = "simple/simple"; + + set-body-length = true; + expire = "2d"; + report = true; + }; + }; + + certificate."default" = { + cert = "%{file:${credentials_directory}/cert}%"; + private-key = "%{file:${credentials_directory}/key}%"; + }; + + storage = { + data = "postgresql"; + fts = "postgresql"; + blob = "postgresql"; + lookup = "postgresql"; + directory = "memory"; + }; + store.postgresql = { + type = "postgresql"; + host = "localhost"; + database = "stalwart"; + user = "stalwart"; + timeout = "15s"; + tls.enable = false; + pool.max-connections = 10; + }; + + directory."memory" = { + type = "memory"; + + principals = [ + { + class = "admin"; + name = "${username}@${domain}"; + secret = "%{file:${credentials_directory}/password}%"; + inherit email; + } + { + # for mta-sts & dmarc reports + class = "individual"; + name = "reports@${domain}"; + secret = "%{file:${credentials_directory}/password}%"; + email = [ "reports@${domain}" ]; + } + ]; + }; + }; + }; +} diff --git a/os/kay/modules/services/mail/secrets.yaml b/os/kay/modules/services/mail/secrets.yaml new file mode 100644 index 0000000..e3b4c5d --- /dev/null +++ b/os/kay/modules/services/mail/secrets.yaml @@ -0,0 +1,28 @@ +mail.sinanmohd.com: + dkim_rsa: ENC[AES256_GCM,data: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,iv:W8YAldq0KjrNe7WhGSUNI2+bq2CJrLhq+XPQVR9QsBo=,tag:LRfmBBFuFR8QR8pCj8OzSw==,type:str] + dkim_ed25519: ENC[AES256_GCM,data:gmI789Z7c9QZMRWOD300cDw0vLNLv4VMhV2jF4M/1roraLqKE/2cA4qv9i8qFmBMJjsq3iUKJBUJ+tBLsUkIR9UnwplQDjAyNaMZsxg0eT3HyssUZ2w2Dnd+EdJb+n/fGwsezHizYORz5qVU/ZUuSiCtuE4LEg==,iv:eAmJgIu++veapN1M3sYkYPAMP8CROFWdDIBmkXuzofw=,tag:hkCDPDDCBxE7DXSuSBFsGg==,type:str] + password: ENC[AES256_GCM,data:LJi8+a1dGus+XLt3k/K/3Mb0tNUJj7HDpPdqfYhU,iv:Iurz9YegxJ/coDQ6PbezeSni2DWYzpzlju6mJ90WLe8=,tag:2HgYlwDGqaklpdc+LOA0bQ==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2MVBCNE45ZFFBeVVrSHpU + UnJSTlk0TyttQlg1R1BnK2plYm5uMm95NnkwCmFjNmhxRFBNQVMzNzlJeFcva0Q4 + cUtzZjF2RnJMd1JLUTMxU1YxQXJOR2sKLS0tIFpBamM5MktOYWwwaS9lcHhFWDVM + YlpwKzd1MkNlcXdmNDhpb3lXSjFKS28KngLhoabp4GBdfsGkMwTkClddEI6LgKet + EXTJ1PrLm3+5mp/2Ypgo325Cp9xIQKi7BYF9C6783mfN+dpbZ0QcbA== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwb3d4R0dORXZXOENUSDha + bWh3N1lYYVpNVTk2WE4xdXBSVzhrWTJHL0R3Ck1GbU5iTDVVaUpZVm9YK05rNzhs + c1dtQmVNSWlCNjg5SENHR3c1TGhwUkkKLS0tIFE0MzlRSkk3T0YyRVptdEpwak1T + enJZVFAxdEprdTVzbC8yWGJyWnFNREkK3/OgnLjS/sj4MzZPLH3QhEWd6WKiu4nM + wRNvhl7nDe1IwLoHbNSqTwEkalyEA3yIVlst3KyEpKb5q9H2+avqAQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:23:15Z" + mac: ENC[AES256_GCM,data:vlks8inOi7qmCKmx1SsCf1ipbwMNFfHsJGny4YGCUr+GWvvtdsLXsf8+AGUfoDa/2fBp7Wv2h1HIx1QY1JX3JgzKoyjEa1rRczJyWW9C/sR5UjyjUa0/t1MNMB7X1l9GGZObDQj9lrWm1e9JUIR6+63mESeykUzh3Wt8qhEgBAo=,iv:l1JWmFqR3lvsyYbPzHzCT6/Yj5qAvMv18jhhXdh2Ex4=,tag:JgXSqfeFVHzg5SeP/5bE+g==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/os/kay/modules/services/matrix/default.nix b/os/kay/modules/services/matrix/default.nix index 1b9564d..811539d 100644 --- a/os/kay/modules/services/matrix/default.nix +++ b/os/kay/modules/services/matrix/default.nix @@ -8,7 +8,7 @@ in ./matrix-sliding-sync.nix ]; - sops.secrets."matrix-${domain}/sliding_sync" = { }; + sops.secrets."matrix-${domain}/sliding_sync".sopsFile = ./secrets.yaml; services.matrix-sliding-sync-dirty = { enable = true; diff --git a/os/kay/modules/services/matrix/dendrite.nix b/os/kay/modules/services/matrix/dendrite.nix index e66c5a5..5b05c97 100644 --- a/os/kay/modules/services/matrix/dendrite.nix +++ b/os/kay/modules/services/matrix/dendrite.nix @@ -10,7 +10,7 @@ let }; in { - sops.secrets."matrix-${domain}/key" = { }; + sops.secrets."matrix-${domain}/key".sopsFile = ./secrets.yaml; systemd.services.dendrite.after = [ "postgresql.service" ]; services = { diff --git a/os/kay/modules/services/matrix/secrets.yaml b/os/kay/modules/services/matrix/secrets.yaml new file mode 100644 index 0000000..fc53c35 --- /dev/null +++ b/os/kay/modules/services/matrix/secrets.yaml @@ -0,0 +1,27 @@ +matrix-sinanmohd.com: + key: ENC[AES256_GCM,data:9GOvsuZLCvSLXXFhJCBE5eTb9nLk4S5SYGuAFx3Mz8jmqweC3AwQWYIobAg4dKWfI170/kC1mqPe3BdRrUSVw/j9AKRr8wQfucOk1StMhV/50x0hKJ40RyAmO1b4enzn21cBbLdromgn5ScXPY+Dzp932wrwuIEltL+uhrfoxI/jDHsJ1AZdBg==,iv:L5NszYBM/9CSj7RtTXj/7DS59MmueVZBXI7xZ3kB8yg=,tag:RAHWcpy7iv1ZYtImsTE+Rg==,type:str] + sliding_sync: ENC[AES256_GCM,data:XcypFVl0Lgw7dEJ68cSygR5XFV+CRV1wWWTU0PAyLQR4QiYk1tG1TCHoR+99nCT8Rhmq2oH8ifvjJ10h7StJKOm0dmA0jKrcHJFp/30/,iv:0mLPUKqfUZoHnoCdR4gjQtViFu8Z7WqdDbhGsygl/5A=,tag:ZTnf61BmZcjf2IYfJ1+6bw==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpc3ZrNVVLZmtGdHc1WUMw + STFSekNWRVl4aGdOajc5SXowTFRaMnhBcENNClpCUnA0cXUveFhRRTRKSS9iUEtJ + WEZRejcxcStHSEtJWm8vWTc0U0NWaFkKLS0tIDFxelpxQzloVTAyWVZOOCtNOWl2 + RHN5bXlNRVRWMzkxNXJYMlo2SFVXazgKEbvi/uJ1JZF1VYqLeVaWqWMZkDOC1fUU + lQRnT3wMqiYt0s5apBBbQ1HnZ7F7TsM11xG2D3miboCrzLRcz1sbkQ== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaSWJ0UmJvdlNaRC9YMXNu + T01sem12MzZPbnVXS1NLSTA0QStoaWE0U0dFCkY0eDlvbE9aajlpT1V0RVJFZFhE + VEJkOWorMk1aa1BSUXA4RDQ4NnpDbHcKLS0tIEhIRXpNUkxPdC84cy93SnZKNHRH + U0NOaC9hSVlicEs0dnl1VEp0ZlBneFkKaY/9eux5tBo1r6LbAkoWDhWv47AuwWtH + 8uOaPUu2wHNm1s8DjwyCeOXeN0BzX+8U/Rjh9/p4px1O0Z9ARUR9mg== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:21:22Z" + mac: ENC[AES256_GCM,data:QDzTSUUyy59c2gMjut2z8qyQGXlcWHnwHxOxFN5N5yy6k1yFgZxPpxsKeyY2yltOSE+qeduy5NLbLon1Exp9kMoXQomutYO4wlZrbXJFGoB4Mobhjv9WbE0FDwHeNAYLeRDF5GUZGxSnDg3i5mAM4kvXItXKYuKe331WCrKCvoQ=,iv:MN4ey+QDUMcAoqAkXAFXKraXs+gcGMuHZwsmCs0CuI0=,tag:Sfkzgv6bjlhD2Z8MVpw3eg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 diff --git a/os/kay/modules/services/nix-cache.nix b/os/kay/modules/services/nix-cache.nix deleted file mode 100644 index 9c81b56..0000000 --- a/os/kay/modules/services/nix-cache.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, ... }: -let - keyname = "misc/nixbin.${config.global.userdata.domain}"; -in -{ - sops.secrets.${keyname} = { }; - - services.nix-serve = { - enable = true; - secretKeyFile = config.sops.secrets.${keyname}.path; - }; -} diff --git a/os/kay/modules/services/nix-cache/default.nix b/os/kay/modules/services/nix-cache/default.nix new file mode 100644 index 0000000..483240e --- /dev/null +++ b/os/kay/modules/services/nix-cache/default.nix @@ -0,0 +1,12 @@ +{ config, ... }: +let + keyname = "misc/nixbin.${config.global.userdata.domain}"; +in +{ + sops.secrets.${keyname}.sopsFile = ./secrets.yaml; + + services.nix-serve = { + enable = true; + secretKeyFile = config.sops.secrets.${keyname}.path; + }; +} diff --git a/os/kay/modules/services/nix-cache/secrets.yaml b/os/kay/modules/services/nix-cache/secrets.yaml new file mode 100644 index 0000000..bf5c2c4 --- /dev/null +++ b/os/kay/modules/services/nix-cache/secrets.yaml @@ -0,0 +1,26 @@ +misc: + nixbin.sinanmohd.com: ENC[AES256_GCM,data:kep0jdkItABm/rLVcllq/K3/P3eP/3MCNhTTV+E5Oh2nfhbQFxaon1iVzq48CzuSk0I0viOelLIiPNZk9ALIqMKBTva0lU3GD/QO/7zjUC2YQ39bDRpraftRk1wHBz0qMWk+2PnwYDn61XkiKQ==,iv:Ue56rg0w0t6AlEOV2KDhZ34yV23Zy+3zIlkMf4m2+Cs=,tag:O4h1Nfi1VJWn+HJJrMTrGQ==,type:str] +sops: + age: + - recipient: age1q5sfy74d53n6jxlgsc2zrsz4wcl9d830nxuagc3wfmdkrrp55ckq9ev6nv + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmcjBBYmZOQkRsVlRWcWpE + cUpkVlVSQndnQ2NmVURVNnpsNjA3RHBsbXpRCjZOaVlnaEVTVW5SWGZGZFpWejJ3 + RjlGK0VVT3hwcVlOQldGWVZKM1B6bE0KLS0tIGdZdVpPYWpQS0tIUWhYV3p1V1pK + VUwrTDlBSEd1WFJCazhuVTNsNk1NNGsK2kTSv9l9nEO0td57TghhklEFVQSaynPE + uUrdVnPantk9vPQDtpuYTKPhBBSxjgiUfBflKKhAaG54Yh0ckwhXsg== + -----END AGE ENCRYPTED FILE----- + - recipient: age15989j5lkkf2kn5wa2p6qc8wlxjjksc63k5ync8rz8t4e87394pzqm7h4rm + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBST2I3RlJsRGEyTWpNVUFl + OFRpemw4WWJPcDhYcGNhb282SVFVK2FpMmhBCmZoT0ZCZktRM0t2aGxCd0J4R0lF + TkNSRWhaYmRJQjI5dFc0NHBMTUhyTFEKLS0tIHdwRXJGWUtUd3pxOXZ2UzErVlpU + SWVRbVNZWFRzOWNFb0lqdnJOVlBoZ1kKzu5Hr+peARgyU0AmUfxLqam7BgxEHyJS + yCJN0AJrQF7zgv/NQDELcphN5SNbkTZdVU90tiYohKw8wgGTTobTSQ== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-12-27T03:27:58Z" + mac: ENC[AES256_GCM,data:G0fEhc1V6udu0QcaMLc4iGIDelIcpXiSTIJPKl2O3faUGZzwWN+pJ9xKiBKAgA3KLIxJARlidwVl4LQK1cE+quMrK2ln/VjxwJBAJumalpZaQtYHQYVXDUreNy7NnUeqIr+fsD7baAXvi2V4DlY9tQg6rhqmb7YZyx1YL0gIaXc=,iv:TfCS4d/2k91B901nJ+kiOEqL2JuQoMyokAKFDF/r0Ls=,tag:th2ntLcU5dXugGYez7Bs2g==,type:str] + unencrypted_suffix: _unencrypted + version: 3.11.0 -- cgit v1.2.3