diff --git a/infra/libkookie/configuration/server/acme/gaia.nix b/infra/libkookie/configuration/server/acme/gaia.nix new file mode 100644 index 00000000000..96d25c1162a --- /dev/null +++ b/infra/libkookie/configuration/server/acme/gaia.nix @@ -0,0 +1,30 @@ +{ config, ... }: + +{ + # HACK (doesn't work): solution to failing ACME services due to + # failing DNS // See: https://github.com/NixOS/nixpkgs/issues/106862 + systemd.services."acme-fixperms".wants = [ "bind.service" ]; + systemd.services."acme-fixperms".after = [ "bind.service" ]; + + security.acme.acceptTerms = true; + security.acme.certs."alarei.kookie.space" = { + email = "letsencrypt@spacekookie.de"; + webroot = "/var/lib/acme/acme-challenge"; + extraDomainNames = [ + "kookiejar.tech" + "media.kookiejar.tech" + "media.alarei.kookie.space" + "sync.kookiejar.tech" + "sync.alarei.kookie.space" + "cloud.kookiejar.tech" + "could.alarei.kookie.space" + "music.kookiejar.tech" + "music.alarei.kookie.space" + ]; + group = "nginx"; + }; + + users.users.nginx.extraGroups = [ "core" ]; + + services.nginx.clientMaxBodySize = "2048M"; +} diff --git a/infra/libkookie/configuration/server/datacore/default.nix b/infra/libkookie/configuration/server/datacore/default.nix new file mode 100644 index 00000000000..34b1e671e8c --- /dev/null +++ b/infra/libkookie/configuration/server/datacore/default.nix @@ -0,0 +1,11 @@ +/** A special module to handle the datacore zfs storage + * + * Sets up special archive modes for ZFS and tools to manage the + * encrypted data sets. + * + */ +{ config, ... }: + +{ + users.groups.core = {}; +} diff --git a/infra/libkookie/configuration/server/ferm2/gaia.nix b/infra/libkookie/configuration/server/ferm2/gaia.nix new file mode 100644 index 00000000000..2fa6ad5fe63 --- /dev/null +++ b/infra/libkookie/configuration/server/ferm2/gaia.nix @@ -0,0 +1,64 @@ +/** Custom ferm2 configuration on gaia + * + * This set of configuration options is required to make the wireguard + * uplink to osmos.pbb.dev work. It does so by tagging all packets + * coming in over a particular interface (public-ip) with a mark, and + * then sorts replies to these connections into a special firewall + * table to send them out over this link again as well. + * + * This module assumes that wireguard is enabled and configured + */ + +{ config, ... }: + +{ + # Main firewall configuration + services.ferm2 = { + enable = true; + extraConfig = '' + table mangle { + chain PREROUTING { + # Mark all connections coming in from public-ip with mark 1312 + interface public-ip CONNMARK set-mark 1312; + } + + chain OUTPUT { + # Mark all packets that are responses to incoming public-ip + # connetions with mark 1312 (we can filter this in the fw later) + CONNMARK restore-mark; + } + } + ''; + }; + + # Additional ip commands to configure the firewall + # + # FIXME: create a firewall module that wraps around this + networking.localCommands = '' + set -x + ip -6 rule flush + ip -4 rule flush + ip -6 rule add lookup main prio 32000 + ip -4 rule add lookup main prio 32000 + + # Take packets with fwmark and sort it into 1312 table + ip -6 rule add from all fwmark 1312 lookup 1312 pref 9000 + ip -4 rule add from all fwmark 1312 lookup 1312 pref 9000 + ''; + + networking.wireguard.interfaces."public-ip" = { + ips = [ "2a0f:4ac0::18" "195.39.247.18" ]; + privateKeyFile = "/var/lib/wireguard/keys/milan.private"; + allowedIPsAsRoutes = true; + table = "1312"; + postSetup = "ip link set dev public-ip mtu 1500"; + peers = [ + { publicKey = "kih/GnR4Bov/DM/7Rd21wK+PFQRUNH6sywVuNKkUAkk="; + allowedIPs = [ "0.0.0.0/0" "::/0" ]; + # TODO: Currently telecom ipv6 handling is broken + # endpoint = "2a01:581:1:9::1:51820"; + endpoint = "62.176.250.82:51820"; + persistentKeepalive = 25; } + ]; + }; +} diff --git a/infra/libkookie/configuration/server/jellyfin/default.nix b/infra/libkookie/configuration/server/jellyfin/default.nix new file mode 100644 index 00000000000..b1ad60a98bb --- /dev/null +++ b/infra/libkookie/configuration/server/jellyfin/default.nix @@ -0,0 +1,45 @@ +{ config, lib, ... }: + +{ + # Default port should be 8096 + services.jellyfin = { + enable = true; + group = "core"; + }; + + # Required for chromecast stuff... + networking.firewall.allowedTCPPorts = [ 8096 ]; + + # Give jellyfin "core" group + users.users.jellyfin.extraGroups = [ "core" ]; + + # Enable nginx if not already + services.nginx.enable = true; + services.nginx.virtualHosts."media.kookiejar.tech" = { + serverAliases = [ "media.alarei.kookie.space" "kookiejar.tech" ]; + useACMEHost = "alarei.kookie.space"; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:8096"; + }; + + locations."/socket" = { + proxyPass = "http://127.0.0.1:8096"; + extraConfig = '' + # global proxy conf + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host:$server_port; + proxy_set_header X-Forwarded-Port $server_port; + + # websocket support + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + ''; + }; + }; + +} diff --git a/infra/libkookie/configuration/server/nextcloud/default.nix b/infra/libkookie/configuration/server/nextcloud/default.nix new file mode 100644 index 00000000000..54504691659 --- /dev/null +++ b/infra/libkookie/configuration/server/nextcloud/default.nix @@ -0,0 +1,44 @@ +{ config, lib, pkgs, ... }: + +{ + services.nginx.enable = true; + services.nginx.virtualHosts."cloud.kookiejar.tech" = { + serverAliases = [ "cloud.alarei.kookie.space"]; + useACMEHost = "alarei.kookie.space"; + forceSSL = true; + }; + + # Give nextcloud "core" group + users.users.nextcloud.extraGroups = [ "core" ]; + + # Enable nextcloud and php settings + services.phpfpm.phpPackage = pkgs.php73; + services.nextcloud = { + enable = true; + package = pkgs.nextcloud19; + hostName = "cloud.kookiejar.tech"; + https = true; + autoUpdateApps.enable = true; + config = { + dbtype = "pgsql"; + dbuser = "nextcloud"; + dbhost = "/run/postgresql"; + dbname = "nextcloud"; + adminpassFile = "/var/lib/nextcloud.admin.pw"; + adminuser = "spacekookie"; + }; + home = "/datacore/cloud"; + }; + + # Setup postgres (currently only used by nextcloud) + services.postgresql = { + enable = true; + ensureDatabases = [ "nextcloud" ]; + ensureUsers = [ + { name = "nextcloud"; + ensurePermissions."DATABASE nextcloud" = "ALL PRIVILEGES"; + } + ]; + }; + +} diff --git a/infra/libkookie/configuration/server/openssh/default.nix b/infra/libkookie/configuration/server/openssh/default.nix new file mode 100644 index 00000000000..df15b7128b6 --- /dev/null +++ b/infra/libkookie/configuration/server/openssh/default.nix @@ -0,0 +1,18 @@ +{ config, ... }: + +{ + services.openssh = { + enable = true; + permitRootLogin = "prohibit-password"; + passwordAuthentication = false; + + # Required for root + extraConfig = '' + Match Address 127.0.0.1 + PermitRootLogin yes + ''; + }; + + # Also enable mosh because /shrug + programs.mosh.enable = true; +} diff --git a/infra/libkookie/configuration/server/syncthing/default.nix b/infra/libkookie/configuration/server/syncthing/default.nix new file mode 100644 index 00000000000..10287d88fa4 --- /dev/null +++ b/infra/libkookie/configuration/server/syncthing/default.nix @@ -0,0 +1,21 @@ +{ config, lib, ... }: + +{ + services.syncthing = { + enable = true; + user = "spacekookie"; + group = "core"; + openDefaultPorts = true; + guiAddress = "0.0.0.0:8384"; + }; + + services.nginx.enable = true; + services.nginx.virtualHosts."sync.kookiejar.tech" = { + serverAliases = [ "sync.alarei.kookie.space" ]; + useACMEHost = "alarei.kookie.space"; + forceSSL = true; + locations."/" = { + proxyPass = "http://127.0.0.1:8384"; + }; + }; +} diff --git a/infra/libkookie/configuration/server/wireguard/gaia.nix b/infra/libkookie/configuration/server/wireguard/gaia.nix new file mode 100644 index 00000000000..0f3768fa9bb --- /dev/null +++ b/infra/libkookie/configuration/server/wireguard/gaia.nix @@ -0,0 +1,14 @@ +{ config, ... }: + +{ + networking.wireguard.interfaces."intranet" = { + ips = [ "10.13.12.2" ]; + privateKeyFile = "/var/lib/wireguard/keys/private"; + peers = [ + { publicKey = "ugHG/NOqM/9hde9EmWpu7XsCpjT3WQbjLK99IGHtdjQ="; + allowedIPs = [ "10.13.12.0/24" "10.172.171.0/24" ]; + endpoint = "hyperion.kookie.space:51820"; + persistentKeepalive = 25; } + ]; + }; +} diff --git a/infra/libkookie/modules/default.nix b/infra/libkookie/modules/default.nix index 227d6e83aa6..c7a2ba3ba5c 100644 --- a/infra/libkookie/modules/default.nix +++ b/infra/libkookie/modules/default.nix @@ -7,6 +7,7 @@ # Add modules based on use-case ./workstation + ./server ./base ]; } diff --git a/infra/libkookie/modules/harness/lib.nix b/infra/libkookie/modules/harness/lib.nix index d4da08a8de4..842f02adfd3 100644 --- a/infra/libkookie/modules/harness/lib.nix +++ b/infra/libkookie/modules/harness/lib.nix @@ -15,4 +15,10 @@ in # Load a simple path with the standard set of arguments load = path: (import path) args; + + # Patch an attribute set with access to the original set + # + # This function wraps around lib.recursiveUpdate to make it slighly + # less cumbersome to work with in one-liners. + patchAttrs = attrs: f: (lib.recursiveUpdate attrs (f attrs)); } diff --git a/infra/libkookie/modules/server/default.nix b/infra/libkookie/modules/server/default.nix new file mode 100644 index 00000000000..27ee9a21737 --- /dev/null +++ b/infra/libkookie/modules/server/default.nix @@ -0,0 +1,7 @@ +{ config, ... }: + +{ + imports = [ + ./ferm2 + ]; +} diff --git a/infra/libkookie/modules/server/ferm2/default.nix b/infra/libkookie/modules/server/ferm2/default.nix new file mode 100644 index 00000000000..8eecec68c0a --- /dev/null +++ b/infra/libkookie/modules/server/ferm2/default.nix @@ -0,0 +1,226 @@ +/** Taken from git.petabyte.dev + * + * https://git.petabyte.dev/petabyteboy/nixfiles/raw/branch/master/modules/ferm2/default.nix + * + * TODO: split the config block into its own file (core.nix) like + */ +{ lib, config, ... }: + +let + fwcfg = config.networking.firewall; + cfg = config.services.ferm2; +in { + options = with lib; { + services.ferm2 = { + enable = mkEnableOption "Ferm easy rule making"; + extraConfig = mkOption { + type = types.lines; + default = ""; + }; + extraConfig6 = mkOption { + type = types.lines; + default = ""; + }; + extraConfig4 = mkOption { + type = types.lines; + default = ""; + }; + extraInput = mkOption { + type = types.lines; + default = ""; + }; + extraInput6 = mkOption { + type = types.lines; + default = ""; + }; + extraInput4 = mkOption { + type = types.lines; + default = ""; + }; + extraOutput = mkOption { + type = types.lines; + default = ""; + }; + extraOutput6 = mkOption { + type = types.lines; + default = ""; + }; + extraOutput4 = mkOption { + type = types.lines; + default = ""; + }; + extraForward = mkOption { + type = types.lines; + default = ""; + }; + extraForward6 = mkOption { + type = types.lines; + default = ""; + }; + extraForward4 = mkOption { + type = types.lines; + default = ""; + }; + inputPolicy = mkOption { + type = types.str; + default = "DROP"; + }; + outputPolicy = mkOption { + type = types.str; + default = "ACCEPT"; + }; + forwardPolicy = mkOption { + type = types.str; + default = "ACCEPT"; + }; + }; + }; + + config = lib.mkIf cfg.enable { + networking.firewall.enable = false; + services.ferm.enable = true; + services.ferm.config = '' + domain ip6 { + table filter { + chain INPUT { + policy ${cfg.inputPolicy}; + + proto ipv6-icmp icmpv6-type redirect DROP; + proto ipv6-icmp icmpv6-type 139 DROP; + proto ipv6-icmp ACCEPT; + + mod state state INVALID DROP; + mod state state (ESTABLISHED RELATED) ACCEPT; + + interface (lo ${ + lib.concatStringsSep " " fwcfg.trustedInterfaces + }) ACCEPT; + + proto tcp dport (${ + lib.concatStringsSep " " (map toString fwcfg.allowedTCPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + fwcfg.allowedTCPPortRanges) + }) ACCEPT; + proto udp dport (${ + lib.concatStringsSep " " (map toString fwcfg.allowedUDPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + fwcfg.allowedUDPPortRanges) + }) ACCEPT; + + ${ + lib.concatStringsSep "\n" (lib.mapAttrsToList (name: config: '' + interface ${name} proto udp dport (${ + lib.concatStringsSep " " (map toString config.allowedUDPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + config.allowedUDPPortRanges) + }) ACCEPT; + interface ${name} proto tcp dport (${ + lib.concatStringsSep " " (map toString config.allowedTCPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + config.allowedTCPPortRanges) + }) ACCEPT; + '') fwcfg.interfaces) + } + + proto udp dport 546 daddr fe80::/64 ACCEPT; + + ${cfg.extraInput} + ${cfg.extraInput6} + } + chain OUTPUT { + policy ${cfg.outputPolicy}; + + ${cfg.extraOutput} + ${cfg.extraOutput6} + } + chain FORWARD { + policy ${cfg.forwardPolicy}; + + ${cfg.extraForward} + ${cfg.extraForward6} + } + } + + ${cfg.extraConfig} + ${cfg.extraConfig6} + } + + domain ip { + table filter { + chain INPUT { + policy ${cfg.inputPolicy}; + + proto icmp icmp-type echo-request ACCEPT; + + mod state state INVALID DROP; + mod state state (ESTABLISHED RELATED) ACCEPT; + + interface (lo ${ + lib.concatStringsSep " " fwcfg.trustedInterfaces + }) ACCEPT; + + proto tcp dport (${ + lib.concatStringsSep " " (map toString fwcfg.allowedTCPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + fwcfg.allowedTCPPortRanges) + }) ACCEPT; + proto udp dport (${ + lib.concatStringsSep " " (map toString fwcfg.allowedUDPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + fwcfg.allowedUDPPortRanges) + }) ACCEPT; + + ${ + lib.concatStringsSep "\n" (lib.mapAttrsToList (name: config: '' + interface ${name} proto udp dport (${ + lib.concatStringsSep " " (map toString config.allowedUDPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + config.allowedUDPPortRanges) + }) ACCEPT; + interface ${name} proto tcp dport (${ + lib.concatStringsSep " " (map toString config.allowedTCPPorts) + } ${ + lib.concatStringsSep " " + (map (range: "${toString range.from}:${toString range.to}") + config.allowedTCPPortRanges) + }) ACCEPT; + '') fwcfg.interfaces) + } + + ${cfg.extraInput} + ${cfg.extraInput4} + } + chain OUTPUT { + policy ${cfg.outputPolicy}; + + ${cfg.extraOutput} + ${cfg.extraOutput4} + } + chain FORWARD { + policy ${cfg.forwardPolicy}; + + ${cfg.extraForward} + ${cfg.extraForward4} + } + } + + ${cfg.extraConfig} + ${cfg.extraConfig4} + } + ''; + }; +} diff --git a/infra/libkookie/roots/gaia.nix b/infra/libkookie/roots/gaia.nix new file mode 100644 index 00000000000..37b18fedd0a --- /dev/null +++ b/infra/libkookie/roots/gaia.nix @@ -0,0 +1,136 @@ +/* TOP LEVEL DEVICE CONFIGURATION FOR + * + * gaia (data storage node) + * + * + * This file is part of LIBKOOKIE, a collection of nix expressions. + * LIBKOOKIE is licensed under the GPL-3.0 (or later) -- see LICENSE + */ + +{ lib, config, pkgs, ... } @ args: + +let klib = (import ) args; +in +{ + ################################################################### + # libkookie configuration + # + # + # + + + imports = with klib; [ + # Load base modules required to bootstrap libkookie + + + # BUILD A BETTER LOADER GOD DAMN IT + + + + + + + + + + ]; + + # TODO: build a klib function to patch cfg here + libkookie.activeUsers = with klib; [ + (patchAttrs(load ) (a: { cfg.extraGroups = a.cfg.extraGroups ++ [ "core" ]; })) + (patchAttrs(load ) ({ ... }: { cfg.extraGroups = [ "core" ]; })) + ]; + + # Enable fish shell handling on the system + libkookie.base.fish.enable = true; + + + # + # + # + # + ################################################################### + + ################################################################### + # NixOS base system options + # + # + # + + + boot.cleanTmpDir = true; + boot.tmpOnTmpfs = true; + boot.supportedFilesystems = [ "zfs" "exfat" ]; + + boot.initrd.availableKernelModules = [ "xhci_pci" "ahci" "usb_storage" "usbhid" "sd_mod" ]; + boot.initrd.kernelModules = [ ]; + boot.kernelModules = [ "kvm-amd" ]; + boot.extraModulePackages = [ ]; + boot.loader.grub.device = "/dev/sdg"; + + fileSystems."/" = + { device = "zroot"; + fsType = "zfs"; + }; + + fileSystems."/boot" = + { device = "/dev/disk/by-uuid/e5b36b2d-bdc7-4963-9a60-c2e1611a9676"; + fsType = "ext4"; + }; + + swapDevices = [ ]; + nix.maxJobs = 4; + + networking = { + defaultGateway = "10.7.1.1"; + nameservers = [ "10.7.1.2" "1.1.1.1" ]; + interfaces.eno1 = { + ipv4.addresses = [ { address = "10.7.1.3"; prefixLength = 24; } ]; + }; + hostName = "gaia"; + hostId = "59405489"; + dhcpcd.enable = false; + + firewall.allowedTCPPorts = [ 80 443 ]; + nat = { + enable = true; + internalInterfaces = ["ve-+"]; + externalInterface = "eno1"; + }; + }; + + time.timeZone = "Europe/Berlin"; + programs.mtr.enable = true; + + # Torrenting container + # containers.trnsmssn = + # { autoStart = true; + # privateNetwork = true; + # hostAddress = "10.7.1.3"; + # localAddress = "10.7.1.13"; + # config = { config, pkgs, ... }: + # { services.mullvad.enable = true; + # services.transmission = { enable = true; }; + # environment.systemPackages = with pkgs; [ transmission openvpn ]; + # }; + # }; + + users.users."spacekookie".hashedPassword = "$6$rounds=1000000$Nnlc.bdBdGIVXtL$Ndb0WoOT.xl3eV2ba4jHe0ajbrGfVSf.RoS2hdaU8hvV8.UHBAZbDtLtXLqQ59Q6eUfjui3YIY6XWUGxAZNYF."; + + # users.users."spacekookie" = { + # hashedPassword = + # openssh.authorizedKeys.keys = [ + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBALMtai+K3wBvpSf9ntuBH1GNte7quhIA4/ZWKlvF0A" # uwu + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBdIsXiaE3YLuqekTg8Xq65n1GUX5IQc8/FKMrbCsCWY" # tempest + + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEMN1iwhQinXxg9H+wJn34EawgzdrrdfBzT0N0wy8yz9 spacekookie@alarei" + # "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICPQ7alBckvMjRL/Tp38dSkZDTR/cLHRcJPwhP5+/fdM" + # ]; + # }; + + # This is pinned here because nextcloud/postgres is being unstable + # at version 18. In the future you might wanna look at upgrading + # again, but for now, just be happily one major version behind! + system.stateVersion = "20.09"; +} +