From 5ec7ee21e036f7bc1cbdec714271c619cb3fdb3d Mon Sep 17 00:00:00 2001 From: seth Date: Sun, 27 Oct 2024 20:12:19 -0400 Subject: modules: restructure (#487) * seth: remove unused pkgs * modules: restructure from archetypes back to profiles make less actual modules for everything use lib.mkDefault like it's supposed to move mixins out of server * nixos/resolved: use modern options --- modules/nixos/README.md | 20 ++-- modules/nixos/archetypes/default.nix | 6 -- modules/nixos/archetypes/personal.nix | 24 ----- modules/nixos/archetypes/server.nix | 37 -------- modules/nixos/base/default.nix | 33 ------- modules/nixos/base/networking.nix | 31 ------- modules/nixos/base/nix.nix | 15 --- modules/nixos/base/programs.nix | 12 --- modules/nixos/base/security.nix | 42 --------- modules/nixos/base/users.nix | 58 ------------ modules/nixos/default.nix | 7 +- modules/nixos/defaults/default.nix | 8 ++ modules/nixos/defaults/nix.nix | 10 ++ modules/nixos/defaults/programs.nix | 6 ++ modules/nixos/defaults/security.nix | 13 +++ modules/nixos/defaults/users.nix | 18 ++++ modules/nixos/desktop/programs.nix | 24 ++--- modules/nixos/mixins/acme.nix | 52 +++++++++++ modules/nixos/mixins/cloudflared.nix | 60 ++++++++++++ modules/nixos/mixins/default.nix | 9 ++ modules/nixos/mixins/hercules.nix | 55 +++++++++++ modules/nixos/mixins/nginx.nix | 22 +++++ modules/nixos/mixins/promtail.nix | 48 ++++++++++ modules/nixos/profiles/default.nix | 6 ++ modules/nixos/profiles/personal.nix | 22 +++++ modules/nixos/profiles/server.nix | 66 ++++++++++++++ modules/nixos/server/default.nix | 45 --------- modules/nixos/server/github-mirror/default.nix | 101 --------------------- .../nixos/server/github-mirror/update-mirror.sh | 78 ---------------- modules/nixos/server/host-user.nix | 44 --------- modules/nixos/server/mixins/acme.nix | 52 ----------- modules/nixos/server/mixins/cloudflared.nix | 60 ------------ modules/nixos/server/mixins/default.nix | 9 -- modules/nixos/server/mixins/hercules.nix | 55 ----------- modules/nixos/server/mixins/nginx.nix | 22 ----- modules/nixos/server/mixins/promtail.nix | 48 ---------- modules/nixos/services/default.nix | 3 + modules/nixos/services/github-mirror/default.nix | 101 +++++++++++++++++++++ .../nixos/services/github-mirror/update-mirror.sh | 78 ++++++++++++++++ modules/nixos/traits/default.nix | 2 + modules/nixos/traits/nvd-diff.nix | 27 ++++++ modules/nixos/traits/resolved.nix | 41 +++++++++ modules/nixos/traits/secrets.nix | 50 ++++++++-- 43 files changed, 711 insertions(+), 809 deletions(-) delete mode 100644 modules/nixos/archetypes/default.nix delete mode 100644 modules/nixos/archetypes/personal.nix delete mode 100644 modules/nixos/archetypes/server.nix delete mode 100644 modules/nixos/base/default.nix delete mode 100644 modules/nixos/base/networking.nix delete mode 100644 modules/nixos/base/nix.nix delete mode 100644 modules/nixos/base/programs.nix delete mode 100644 modules/nixos/base/security.nix delete mode 100644 modules/nixos/base/users.nix create mode 100644 modules/nixos/defaults/default.nix create mode 100644 modules/nixos/defaults/nix.nix create mode 100644 modules/nixos/defaults/programs.nix create mode 100644 modules/nixos/defaults/security.nix create mode 100644 modules/nixos/defaults/users.nix create mode 100644 modules/nixos/mixins/acme.nix create mode 100644 modules/nixos/mixins/cloudflared.nix create mode 100644 modules/nixos/mixins/default.nix create mode 100644 modules/nixos/mixins/hercules.nix create mode 100644 modules/nixos/mixins/nginx.nix create mode 100644 modules/nixos/mixins/promtail.nix create mode 100644 modules/nixos/profiles/default.nix create mode 100644 modules/nixos/profiles/personal.nix create mode 100644 modules/nixos/profiles/server.nix delete mode 100644 modules/nixos/server/default.nix delete mode 100644 modules/nixos/server/github-mirror/default.nix delete mode 100755 modules/nixos/server/github-mirror/update-mirror.sh delete mode 100644 modules/nixos/server/host-user.nix delete mode 100644 modules/nixos/server/mixins/acme.nix delete mode 100644 modules/nixos/server/mixins/cloudflared.nix delete mode 100644 modules/nixos/server/mixins/default.nix delete mode 100644 modules/nixos/server/mixins/hercules.nix delete mode 100644 modules/nixos/server/mixins/nginx.nix delete mode 100644 modules/nixos/server/mixins/promtail.nix create mode 100644 modules/nixos/services/default.nix create mode 100644 modules/nixos/services/github-mirror/default.nix create mode 100755 modules/nixos/services/github-mirror/update-mirror.sh create mode 100644 modules/nixos/traits/nvd-diff.nix create mode 100644 modules/nixos/traits/resolved.nix (limited to 'modules/nixos') diff --git a/modules/nixos/README.md b/modules/nixos/README.md index 5a78133..5204795 100644 --- a/modules/nixos/README.md +++ b/modules/nixos/README.md @@ -1,20 +1,24 @@ # ./modules/nixos/ -## archetypes +## defaults -The high-level "type" of a machine (i.e., `personal` or `server`) +Defaults (mostly) shared across all configurations -## base +## desktop -Low level options shared for (almost) any kind of system +Installs cool GUI stuff for desktops and laptops -## desktop +## mixins -Installs cool GUI stuff for desktops...or laptops too I guess +Small modules that add onto existing ones; mean to be "mixed in" with your regular configurations + +## profiles + +The high-level "type" of a machine (i.e., `personal` or `server`) -## server +## services -Installs cool daemons and such for servers +Custom service modules ## traits diff --git a/modules/nixos/archetypes/default.nix b/modules/nixos/archetypes/default.nix deleted file mode 100644 index 0d11285..0000000 --- a/modules/nixos/archetypes/default.nix +++ /dev/null @@ -1,6 +0,0 @@ -{ - imports = [ - ./personal.nix - ./server.nix - ]; -} diff --git a/modules/nixos/archetypes/personal.nix b/modules/nixos/archetypes/personal.nix deleted file mode 100644 index 4200269..0000000 --- a/modules/nixos/archetypes/personal.nix +++ /dev/null @@ -1,24 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.archetypes.personal; -in -{ - options.archetypes = { - personal.enable = lib.mkEnableOption "the Personal archetype"; - }; - - config = lib.mkIf cfg.enable { - base.enable = true; - - traits = { - home-manager.enable = true; - - secrets.enable = true; - tailscale.enable = true; - - users = { - seth.enable = true; - }; - }; - }; -} diff --git a/modules/nixos/archetypes/server.nix b/modules/nixos/archetypes/server.nix deleted file mode 100644 index 780e1b4..0000000 --- a/modules/nixos/archetypes/server.nix +++ /dev/null @@ -1,37 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.archetypes.server; -in -{ - options.archetypes = { - server.enable = lib.mkEnableOption "the Server archetype"; - }; - - config = lib.mkIf cfg.enable { - base = { - enable = true; - defaultPrograms.enable = false; - }; - - server = { - enable = true; - mixins = { - cloudflared.enable = true; - nginx.enable = true; - }; - }; - - traits = { - autoUpgrade.enable = true; - - secrets.enable = true; - - tailscale = { - enable = true; - ssh.enable = true; - }; - - zram.enable = true; - }; - }; -} diff --git a/modules/nixos/base/default.nix b/modules/nixos/base/default.nix deleted file mode 100644 index 3a6412e..0000000 --- a/modules/nixos/base/default.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -let - cfg = config.base; -in -{ - imports = [ - ./networking.nix - ./nix.nix - ./programs.nix - ./security.nix - ./users.nix - ]; - - config = lib.mkIf cfg.enable { - services.journald.extraConfig = '' - MaxRetentionSec=1w - ''; - - system.activationScripts."upgrade-diff" = { - supportsDryActivation = true; - text = '' - ${lib.getExe pkgs.nvd} \ - --nix-bin-dir=${config.nix.package}/bin \ - diff /run/current-system "$systemConfig" - ''; - }; - }; -} diff --git a/modules/nixos/base/networking.nix b/modules/nixos/base/networking.nix deleted file mode 100644 index c4514df..0000000 --- a/modules/nixos/base/networking.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.base.networking; -in -{ - options.base.networking = { - enable = lib.mkEnableOption "base network settings" // { - default = config.base.enable; - defaultText = lib.literalExpression "config.base.enable"; - }; - }; - - config = lib.mkIf cfg.enable { - networking.networkmanager = { - enable = lib.mkDefault true; - dns = "systemd-resolved"; - }; - - services = { - resolved = { - enable = lib.mkDefault true; - dnssec = "allow-downgrade"; - extraConfig = lib.mkDefault '' - [Resolve] - DNS=1.1.1.1 1.0.0.1 - DNSOverTLS=yes - ''; - }; - }; - }; -} diff --git a/modules/nixos/base/nix.nix b/modules/nixos/base/nix.nix deleted file mode 100644 index e49eb17..0000000 --- a/modules/nixos/base/nix.nix +++ /dev/null @@ -1,15 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.base.nixSettings; -in -{ - config = lib.mkIf cfg.enable { - nix = { - channel.enable = lib.mkDefault false; - settings.trusted-users = [ - "root" - "@wheel" - ]; - }; - }; -} diff --git a/modules/nixos/base/programs.nix b/modules/nixos/base/programs.nix deleted file mode 100644 index 55424dc..0000000 --- a/modules/nixos/base/programs.nix +++ /dev/null @@ -1,12 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.base.defaultPrograms; -in -{ - config = lib.mkIf cfg.enable { - programs = { - git.enable = true; - vim.defaultEditor = true; - }; - }; -} diff --git a/modules/nixos/base/security.nix b/modules/nixos/base/security.nix deleted file mode 100644 index 66a1e7e..0000000 --- a/modules/nixos/base/security.nix +++ /dev/null @@ -1,42 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.base.security; -in -{ - options.base.security = { - enable = lib.mkEnableOption "basic security settings" // { - default = config.base.enable; - defaultText = lib.literalExpression "config.base.enable"; - }; - - apparmor = lib.mkEnableOption "AppArmor support" // { - default = true; - }; - - auditing = lib.mkEnableOption "auditing support" // { - default = true; - }; - }; - - # much here is sourced from https://xeiaso.net/blog/paranoid-nixos-2021-07-18/ - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - security = { - polkit.enable = true; - sudo.execWheelOnly = true; - }; - } - (lib.mkIf cfg.auditing { - security = { - audit.enable = true; - auditd.enable = true; - }; - }) - (lib.mkIf cfg.apparmor { - security.apparmor.enable = true; - services.dbus.apparmor = lib.mkDefault "enabled"; - }) - ] - ); -} diff --git a/modules/nixos/base/users.nix b/modules/nixos/base/users.nix deleted file mode 100644 index b757fc5..0000000 --- a/modules/nixos/base/users.nix +++ /dev/null @@ -1,58 +0,0 @@ -{ - config, - lib, - pkgs, - secretsDir, - ... -}: -let - cfg = config.base.users; -in -{ - options.base.users = { - enable = lib.mkEnableOption "basic user configurations" // { - default = config.base.enable; - defaultText = lib.literalExpression "config.base.enable"; - }; - - defaultRoot = { - enable = lib.mkEnableOption "default root user configuration" // { - default = false; - }; - - manageSecrets = lib.mkEnableOption "automatic management of secrets" // { - default = config.traits.secrets.enable; - defaultText = lib.literalExpression "config.traits.secrets.enable"; - }; - }; - }; - - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - users = { - defaultUserShell = pkgs.bash; - mutableUsers = false; - }; - } - - (lib.mkIf cfg.defaultRoot.enable { - users.users.root = { - home = lib.mkDefault "/root"; - uid = lib.mkDefault config.ids.uids.root; - group = lib.mkDefault "root"; - }; - }) - - (lib.mkIf (cfg.defaultRoot.enable && cfg.defaultRoot.manageSecrets) { - age.secrets = { - rootPassword.file = secretsDir + "/rootPassword.age"; - }; - - users.users.root = { - hashedPasswordFile = config.age.secrets.rootPassword.path; - }; - }) - ] - ); -} diff --git a/modules/nixos/default.nix b/modules/nixos/default.nix index acc9d59..82e4b93 100644 --- a/modules/nixos/default.nix +++ b/modules/nixos/default.nix @@ -1,10 +1,11 @@ { imports = [ ../shared - ./archetypes - ./base + ./defaults ./desktop - ./server + ./mixins + ./profiles + ./services ./traits ]; } diff --git a/modules/nixos/defaults/default.nix b/modules/nixos/defaults/default.nix new file mode 100644 index 0000000..bcd3554 --- /dev/null +++ b/modules/nixos/defaults/default.nix @@ -0,0 +1,8 @@ +{ + imports = [ + ./nix.nix + ./programs.nix + ./security.nix + ./users.nix + ]; +} diff --git a/modules/nixos/defaults/nix.nix b/modules/nixos/defaults/nix.nix new file mode 100644 index 0000000..8716f00 --- /dev/null +++ b/modules/nixos/defaults/nix.nix @@ -0,0 +1,10 @@ +{ lib, ... }: +{ + nix = { + channel.enable = lib.mkDefault false; + settings.trusted-users = [ + "root" + "@wheel" + ]; + }; +} diff --git a/modules/nixos/defaults/programs.nix b/modules/nixos/defaults/programs.nix new file mode 100644 index 0000000..c7d655f --- /dev/null +++ b/modules/nixos/defaults/programs.nix @@ -0,0 +1,6 @@ +{ + programs = { + git.enable = true; + vim.defaultEditor = true; + }; +} diff --git a/modules/nixos/defaults/security.nix b/modules/nixos/defaults/security.nix new file mode 100644 index 0000000..65ce729 --- /dev/null +++ b/modules/nixos/defaults/security.nix @@ -0,0 +1,13 @@ +# Much of this is sourced from https://xeiaso.net/blog/paranoid-nixos-2021-07-18/ +{ lib, ... }: +{ + security = { + apparmor.enable = lib.mkDefault true; + audit.enable = lib.mkDefault true; + auditd.enable = lib.mkDefault true; + polkit.enable = true; + sudo.execWheelOnly = true; + }; + + services.dbus.apparmor = lib.mkDefault "enabled"; +} diff --git a/modules/nixos/defaults/users.nix b/modules/nixos/defaults/users.nix new file mode 100644 index 0000000..0cec52a --- /dev/null +++ b/modules/nixos/defaults/users.nix @@ -0,0 +1,18 @@ +{ + config, + lib, + pkgs, + ... +}: +{ + users = { + defaultUserShell = pkgs.bash; + mutableUsers = false; + + users.root = { + home = lib.mkDefault "/root"; + uid = config.ids.uids.root; + group = "root"; + }; + }; +} diff --git a/modules/nixos/desktop/programs.nix b/modules/nixos/desktop/programs.nix index 01a9928..2830943 100644 --- a/modules/nixos/desktop/programs.nix +++ b/modules/nixos/desktop/programs.nix @@ -4,29 +4,17 @@ pkgs, ... }: -let - cfg = config.desktop.defaultPrograms; -in { - options.desktop.defaultPrograms = { - enable = lib.mkEnableOption "default desktop programs" // { - default = config.desktop.enable; - defaultText = lib.literalExpression "config.desktop.enable"; - }; - }; - - config = lib.mkIf cfg.enable { - environment.systemPackages = with pkgs; [ - wl-clipboard - xclip + config = lib.mkIf config.desktop.enable { + environment.systemPackages = [ + pkgs.wl-clipboard ]; programs = { - chromium.enable = true; - firefox.enable = true; - xwayland.enable = true; + chromium.enable = lib.mkDefault true; + firefox.enable = lib.mkDefault true; }; - xdg.portal.enable = true; + xdg.portal.enable = lib.mkDefault true; }; } diff --git a/modules/nixos/mixins/acme.nix b/modules/nixos/mixins/acme.nix new file mode 100644 index 0000000..3b49caf --- /dev/null +++ b/modules/nixos/mixins/acme.nix @@ -0,0 +1,52 @@ +{ + config, + lib, + secretsDir, + ... +}: +let + cfg = config.mixins.acme; +in +{ + options.mixins.acme = { + enable = lib.mkEnableOption "ACME mixin"; + + manageSecrets = lib.mkEnableOption "automatic management of secrets" // { + default = config.traits.secrets.enable; + defaultText = lib.literalExpression "config.traits.secrets.enable"; + }; + + useDns = lib.mkEnableOption "the use of Cloudflare to obtain certs" // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + security.acme = { + acceptTerms = true; + defaults = { + email = "getchoo@tuta.io"; + }; + }; + } + + (lib.mkIf cfg.useDns { + security.acme.defaults = { + dnsProvider = "cloudflare"; + }; + }) + + (lib.mkIf cfg.manageSecrets { + age.secrets = { + cloudflareApiKey.file = secretsDir + "/cloudflareApiKey.age"; + }; + + security.acme.defaults = { + credentialsFile = config.age.secrets.cloudflareApiKey.path; + }; + }) + ] + ); +} diff --git a/modules/nixos/mixins/cloudflared.nix b/modules/nixos/mixins/cloudflared.nix new file mode 100644 index 0000000..372103b --- /dev/null +++ b/modules/nixos/mixins/cloudflared.nix @@ -0,0 +1,60 @@ +{ + config, + lib, + secretsDir, + ... +}: +let + cfg = config.mixins.cloudflared; + inherit (config.services) nginx; +in +{ + options.mixins.cloudflared = { + enable = lib.mkEnableOption "cloudflared mixin"; + tunnelName = lib.mkOption { + description = '' + Name of the default tunnel being created + ''; + type = lib.types.str; + default = "${config.networking.hostName}-nginx"; + defaultText = lib.literalExpression "\${config.networking.hostName}-nginx"; + example = "my-tunnel"; + }; + + manageSecrets = lib.mkEnableOption "automatic management of secrets" // { + default = config.traits.secrets.enable; + defaultText = lib.literalExpression "config.traits.secrets.enable"; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + services.cloudflared = { + enable = true; + tunnels.${cfg.tunnelName} = { + default = "http_status:404"; + + # map our virtualHosts from nginx to ingress rules + ingress = lib.mapAttrs (_: _: { + service = "http://localhost:${toString nginx.defaultHTTPListenPort}"; + }) nginx.virtualHosts; + }; + }; + } + + (lib.mkIf cfg.manageSecrets { + age.secrets.cloudflaredCreds = { + file = secretsDir + "/cloudflaredCreds.age"; + mode = "400"; + owner = "cloudflared"; + group = "cloudflared"; + }; + + services.cloudflared.tunnels.${cfg.tunnelName} = { + credentialsFile = config.age.secrets.cloudflaredCreds.path; + }; + }) + ] + ); +} diff --git a/modules/nixos/mixins/default.nix b/modules/nixos/mixins/default.nix new file mode 100644 index 0000000..461cd34 --- /dev/null +++ b/modules/nixos/mixins/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./acme.nix + ./cloudflared.nix + ./hercules.nix + ./nginx.nix + ./promtail.nix + ]; +} diff --git a/modules/nixos/mixins/hercules.nix b/modules/nixos/mixins/hercules.nix new file mode 100644 index 0000000..de209a3 --- /dev/null +++ b/modules/nixos/mixins/hercules.nix @@ -0,0 +1,55 @@ +{ + config, + lib, + unstable, + secretsDir, + ... +}: +let + cfg = config.mixins.hercules-ci; +in +{ + options.mixins.hercules-ci = { + enable = lib.mkEnableOption "Hercules CI mixin"; + manageSecrets = lib.mkEnableOption "automatic management of secrets" // { + default = config.traits.secrets.enable; + defaultText = lib.literalExpression "config.traits.secrets.enable"; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + services.hercules-ci-agent = { + enable = true; + # we want newer features + package = unstable.hercules-ci-agent; + }; + } + + ( + let + secretNames = [ + "binaryCaches" + "clusterJoinToken" + "secretsJson" + ]; + in + lib.mkIf cfg.manageSecrets { + age.secrets = lib.genAttrs secretNames (file: { + file = "${secretsDir}/${file}.age"; + mode = "400"; + owner = "hercules-ci-agent"; + group = "hercules-ci-agent"; + }); + + services.hercules-ci-agent = { + settings = lib.mapAttrs' (name: lib.nameValuePair (name + "Path")) ( + lib.genAttrs secretNames (name: config.age.secrets.${name}.path) + ); + }; + } + ) + ] + ); +} diff --git a/modules/nixos/mixins/nginx.nix b/modules/nixos/mixins/nginx.nix new file mode 100644 index 0000000..67d0c25 --- /dev/null +++ b/modules/nixos/mixins/nginx.nix @@ -0,0 +1,22 @@ +{ config, lib, ... }: +let + cfg = config.mixins.nginx; +in +{ + options.mixins.nginx = { + enable = lib.mkEnableOption "NGINX mixin"; + }; + + config = lib.mkIf cfg.enable { + services.nginx = { + enable = true; + + recommendedBrotliSettings = true; + recommendedGzipSettings = true; + recommendedOptimisation = true; + recommendedProxySettings = true; + recommendedTlsSettings = true; + recommendedZstdSettings = true; + }; + }; +} diff --git a/modules/nixos/mixins/promtail.nix b/modules/nixos/mixins/promtail.nix new file mode 100644 index 0000000..022c271 --- /dev/null +++ b/modules/nixos/mixins/promtail.nix @@ -0,0 +1,48 @@ +{ config, lib, ... }: +let + cfg = config.mixins.promtail; + inherit (lib) types; +in +{ + options.mixins.promtail = { + enable = lib.mkEnableOption "Promtail mixin"; + + clients = lib.mkOption { + type = types.listOf types.attrs; + default = [ { } ]; + defaultText = lib.literalExpression "[ { } ]"; + description = "Clients for promtail"; + }; + }; + + config = lib.mkIf cfg.enable { + services.promtail = { + enable = true; + configuration = { + inherit (cfg) clients; + server.disable = true; + + scrape_configs = [ + { + job_name = "journal"; + + journal = { + max_age = "12h"; + labels = { + job = "systemd-journal"; + host = "${config.networking.hostName}"; + }; + }; + + relabel_configs = [ + { + source_labels = [ "__journal__systemd_unit" ]; + target_label = "unit"; + } + ]; + } + ]; + }; + }; + }; +} diff --git a/modules/nixos/profiles/default.nix b/modules/nixos/profiles/default.nix new file mode 100644 index 0000000..0d11285 --- /dev/null +++ b/modules/nixos/profiles/default.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./personal.nix + ./server.nix + ]; +} diff --git a/modules/nixos/profiles/personal.nix b/modules/nixos/profiles/personal.nix new file mode 100644 index 0000000..df52696 --- /dev/null +++ b/modules/nixos/profiles/personal.nix @@ -0,0 +1,22 @@ +{ config, lib, ... }: +let + cfg = config.profiles.personal; +in +{ + options.profiles.personal = { + enable = lib.mkEnableOption "the Personal profile"; + }; + + config = lib.mkIf cfg.enable { + traits = { + home-manager.enable = true; + + secrets.enable = true; + tailscale.enable = true; + + users = { + seth.enable = true; + }; + }; + }; +} diff --git a/modules/nixos/profiles/server.nix b/modules/nixos/profiles/server.nix new file mode 100644 index 0000000..e3e785b --- /dev/null +++ b/modules/nixos/profiles/server.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + pkgs, + inputs, + ... +}: +let + cfg = config.profiles.server; +in +{ + options.profiles.server = { + enable = lib.mkEnableOption "the Server profile"; + + hostUser = lib.mkEnableOption "a default interactive user" // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + # All servers are most likely on stable, so we want to pull in some newer packages from time to time + _module.args.unstable = inputs.nixpkgs.legacyPackages.${pkgs.stdenv.hostPlatform.system}; + + boot.tmp.cleanOnBoot = lib.mkDefault true; + + # We don't need it here + documentation.enable = false; + + environment.defaultPackages = lib.mkForce [ ]; + + mixins = { + cloudflared.enable = true; + nginx.enable = true; + }; + + nix.gc = { + # Every ~2 days + dates = "Mon,Wed,Fri *-*-* 00:00:00"; + options = "-d --delete-older-than 2d"; + }; + + traits = { + autoUpgrade.enable = true; + secrets.enable = true; + tailscale = { + enable = true; + ssh.enable = true; + }; + zram.enable = true; + }; + } + + (lib.mkIf cfg.hostUser { + # Hardening access to `nix` as no other users *should* ever really touch it + nix.settings.allowed-users = [ config.networking.hostName ]; + + users.users.${config.networking.hostName} = { + isNormalUser = true; + extraGroups = [ "wheel" ]; + }; + }) + ] + ); +} diff --git a/modules/nixos/server/default.nix b/modules/nixos/server/default.nix deleted file mode 100644 index 3cc60fb..0000000 --- a/modules/nixos/server/default.nix +++ /dev/null @@ -1,45 +0,0 @@ -{ - config, - lib, - pkgs, - inputs, - ... -}: -let - cfg = config.server; -in -{ - options.server = { - enable = lib.mkEnableOption "basic server settings"; - }; - - imports = [ - ./github-mirror - ./host-user.nix - ./mixins - ]; - - config = lib.mkIf cfg.enable { - # all servers are most likely on stable, so we may want to pull some newer packages from time to time - _module.args.unstable = inputs.nixpkgs.legacyPackages.${pkgs.stdenv.hostPlatform.system}; - - boot.tmp.cleanOnBoot = lib.mkDefault true; - - # we don't need it here - documentation.enable = false; - - environment.defaultPackages = lib.mkForce [ ]; - - nix = { - gc = { - # ~every 2 days - dates = "Mon,Wed,Fri *-*-* 00:00:00"; - options = "-d --delete-older-than 2d"; - }; - - # hardening access to `nix` on servers as no other users - # *should* ever really touch it - settings.allowed-users = [ config.networking.hostName ]; - }; - }; -} diff --git a/modules/nixos/server/github-mirror/default.nix b/modules/nixos/server/github-mirror/default.nix deleted file mode 100644 index 9d0d870..0000000 --- a/modules/nixos/server/github-mirror/default.nix +++ /dev/null @@ -1,101 +0,0 @@ -{ - config, - lib, - pkgs, - ... -}: -let - cfg = config.services.github-mirror; - cgitInstance = config.services.cgit.${cfg.hostname}; - - update-mirror = - pkgs.runCommand "update-mirror" - { - nativeBuildInputs = [ pkgs.patsh ]; - - buildInputs = [ - config.programs.git.package - pkgs.curl - pkgs.jq - ]; - } - '' - patsh -s ${builtins.storeDir} ${./update-mirror.sh} $out - chmod 755 $out - patchShebangs $out - ''; -in -{ - options.services.github-mirror = { - enable = lib.mkEnableOption "the github-mirror service"; - - hostname = lib.mkOption { - type = lib.types.str; - description = "Hostname of the cgit service to create"; - example = lib.literalExpression "git.example.com"; - }; - - mirroredUsers = lib.mkOption { - type = lib.types.listOf lib.types.str; - description = "List of GitHub users to mirror repositories for"; - example = lib.literalExpression ''[ "edolstra" ]''; - }; - }; - - config = lib.mkIf cfg.enable { - assertions = [ - { - assertion = cfg.mirroredUsers != [ ]; - message = "`services.git-mirror.mirroredUsers` must have at least one user"; - } - ]; - - services.cgit.${cfg.hostname} = { - enable = true; - - scanPath = "/var/lib/cgit/${cfg.hostname}"; - settings = { - robots = "none"; # noindex, nofollow - }; - - user = "cgit"; - group = "cgit"; - }; - - systemd = { - services.github-mirror = { - description = "Mirror a GitHub repository"; - - after = [ "network-online.target" ]; - wants = [ "network-online.target" ]; - - script = toString ( - [ - "exec" - (toString update-mirror) - "--directory" - cgitInstance.scanPath - ] - ++ cfg.mirroredUsers - ); - - serviceConfig = { - Type = "oneshot"; - User = cgitInstance.user; - Group = cgitInstance.group; - }; - }; - - timers.github-mirror = { - description = "Hourly timer for %N"; - timerConfig.OnCalendar = "hourly"; - }; - - tmpfiles.settings."10-github-mirror" = { - ${cgitInstance.scanPath}.d = { - inherit (cgitInstance) user group; - }; - }; - }; - }; -} diff --git a/modules/nixos/server/github-mirror/update-mirror.sh b/modules/nixos/server/github-mirror/update-mirror.sh deleted file mode 100755 index c1e392d..0000000 --- a/modules/nixos/server/github-mirror/update-mirror.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -help() { - echo "Mirror a GitHub user's repositories - -Usage: $(basename "$0") [options] ... - -Options: - -h --help Show this screen - -d --directory DIRECTORY Where to clone repositories (defaults to ./git)" -} - -create_if_not_exists() { - if [ ! -d "$1" ]; then - mkdir -p "$1" - fi -} - -repo_endpoint() { - echo "https://api.github.com/users/$1/repos" -} - -users=() -output_directory="git" - -while [ "$#" -gt 0 ]; do - case $1 in - -h | --help) - help - exit 0 - ;; - -d | --directory) - output_directory="$2" - shift - shift - ;; - -*) - echo "error: unknown option $1" - help - exit 1 - ;; - *) - users+=("$1") - shift - ;; - esac -done - -if [ "${#users[@]}" -lt 1 ]; then - echo "error: at least one user must be specified" - help - exit 1 -fi - -create_if_not_exists "$output_directory" -cd "$output_directory" - -for user in "${users[@]}"; do - create_if_not_exists "$user" - - url="$(repo_endpoint "$user")" - curl --fail --location --show-error --silent "$url" | jq --raw-output '.[].name' | while read -r repo; do - repo_path="$user"/"$repo" - - if [ -d "$repo_path"/.git ]; then - pushd "$repo_path" &>/dev/null - echo "Pulling $repo_path..." - if ! git remote update --prune &>/dev/null; then - echo "Unable to pull $repo_path! Continuing..." - fi - popd &>/dev/null - else - echo "Cloning $repo_path..." - git clone --bare --mirror https://github.com/"$repo_path".git "$repo_path" &>/dev/null - fi - done -done diff --git a/modules/nixos/server/host-user.nix b/modules/nixos/server/host-user.nix deleted file mode 100644 index c60bfe3..0000000 --- a/modules/nixos/server/host-user.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ - config, - lib, - secretsDir, - ... -}: -let - cfg = config.server.hostUser; - inherit (config.networking) hostName; -in -{ - options.server.hostUser = { - enable = lib.mkEnableOption "a default interactive user" // { - default = config.server.enable; - defaultText = lib.literalExpression "config.server.enable"; - }; - - manageSecrets = lib.mkEnableOption "automatic management of secrets" // { - default = config.traits.secrets.enable; - defaultText = lib.literalExpression "config.traits.secrets.enable"; - }; - }; - - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - users.users.${hostName} = { - isNormalUser = true; - extraGroups = [ "wheel" ]; - }; - } - - (lib.mkIf cfg.manageSecrets { - age.secrets = { - userPassword.file = secretsDir + "/userPassword.age"; - }; - - users.users.${hostName} = { - hashedPasswordFile = config.age.secrets.userPassword.path; - }; - }) - ] - ); -} diff --git a/modules/nixos/server/mixins/acme.nix b/modules/nixos/server/mixins/acme.nix deleted file mode 100644 index 39166f2..0000000 --- a/modules/nixos/server/mixins/acme.nix +++ /dev/null @@ -1,52 +0,0 @@ -{ - config, - lib, - secretsDir, - ... -}: -let - cfg = config.server.mixins.acme; -in -{ - options.server.mixins.acme = { - enable = lib.mkEnableOption "ACME mixin"; - - manageSecrets = lib.mkEnableOption "automatic management of secrets" // { - default = config.traits.secrets.enable; - defaultText = lib.literalExpression "config.traits.secrets.enable"; - }; - - useDns = lib.mkEnableOption "the use of Cloudflare to obtain certs" // { - default = true; - }; - }; - - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - security.acme = { - acceptTerms = true; - defaults = { - email = "getchoo@tuta.io"; - }; - }; - } - - (lib.mkIf cfg.useDns { - security.acme.defaults = { - dnsProvider = "cloudflare"; - }; - }) - - (lib.mkIf cfg.manageSecrets { - age.secrets = { - cloudflareApiKey.file = secretsDir + "/cloudflareApiKey.age"; - }; - - security.acme.defaults = { - credentialsFile = config.age.secrets.cloudflareApiKey.path; - }; - }) - ] - ); -} diff --git a/modules/nixos/server/mixins/cloudflared.nix b/modules/nixos/server/mixins/cloudflared.nix deleted file mode 100644 index 9a56aaa..0000000 --- a/modules/nixos/server/mixins/cloudflared.nix +++ /dev/null @@ -1,60 +0,0 @@ -{ - config, - lib, - secretsDir, - ... -}: -let - cfg = config.server.mixins.cloudflared; - inherit (config.services) nginx; -in -{ - options.server.mixins.cloudflared = { - enable = lib.mkEnableOption "cloudflared mixin"; - tunnelName = lib.mkOption { - description = '' - Name of the default tunnel being created - ''; - type = lib.types.str; - default = "${config.networking.hostName}-nginx"; - defaultText = lib.literalExpression "\${config.networking.hostName}-nginx"; - example = "my-tunnel"; - }; - - manageSecrets = lib.mkEnableOption "automatic management of secrets" // { - default = config.traits.secrets.enable; - defaultText = lib.literalExpression "config.traits.secrets.enable"; - }; - }; - - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - services.cloudflared = { - enable = true; - tunnels.${cfg.tunnelName} = { - default = "http_status:404"; - - # map our virtualHosts from nginx to ingress rules - ingress = lib.mapAttrs (_: _: { - service = "http://localhost:${toString nginx.defaultHTTPListenPort}"; - }) nginx.virtualHosts; - }; - }; - } - - (lib.mkIf cfg.manageSecrets { - age.secrets.cloudflaredCreds = { - file = secretsDir + "/cloudflaredCreds.age"; - mode = "400"; - owner = "cloudflared"; - group = "cloudflared"; - }; - - services.cloudflared.tunnels.${cfg.tunnelName} = { - credentialsFile = config.age.secrets.cloudflaredCreds.path; - }; - }) - ] - ); -} diff --git a/modules/nixos/server/mixins/default.nix b/modules/nixos/server/mixins/default.nix deleted file mode 100644 index 461cd34..0000000 --- a/modules/nixos/server/mixins/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ - imports = [ - ./acme.nix - ./cloudflared.nix - ./hercules.nix - ./nginx.nix - ./promtail.nix - ]; -} diff --git a/modules/nixos/server/mixins/hercules.nix b/modules/nixos/server/mixins/hercules.nix deleted file mode 100644 index a04f9b1..0000000 --- a/modules/nixos/server/mixins/hercules.nix +++ /dev/null @@ -1,55 +0,0 @@ -{ - config, - lib, - unstable, - secretsDir, - ... -}: -let - cfg = config.server.mixins.hercules-ci; -in -{ - options.server.mixins.hercules-ci = { - enable = lib.mkEnableOption "Hercules CI mixin"; - manageSecrets = lib.mkEnableOption "automatic management of secrets" // { - default = config.traits.secrets.enable; - defaultText = lib.literalExpression "config.traits.secrets.enable"; - }; - }; - - config = lib.mkIf cfg.enable ( - lib.mkMerge [ - { - services.hercules-ci-agent = { - enable = true; - # we want newer features - package = unstable.hercules-ci-agent; - }; - } - - ( - let - secretNames = [ - "binaryCaches" - "clusterJoinToken" - "secretsJson" - ]; - in - lib.mkIf cfg.manageSecrets { - age.secrets = lib.genAttrs secretNames (file: { - file = "${secretsDir}/${file}.age"; - mode = "400"; - owner = "hercules-ci-agent"; - group = "hercules-ci-agent"; - }); - - services.hercules-ci-agent = { - settings = lib.mapAttrs' (name: lib.nameValuePair (name + "Path")) ( - lib.genAttrs secretNames (name: config.age.secrets.${name}.path) - ); - }; - } - ) - ] - ); -} diff --git a/modules/nixos/server/mixins/nginx.nix b/modules/nixos/server/mixins/nginx.nix deleted file mode 100644 index e3cc47a..0000000 --- a/modules/nixos/server/mixins/nginx.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.server.mixins.nginx; -in -{ - options.server.mixins.nginx = { - enable = lib.mkEnableOption "NGINX mixin"; - }; - - config = lib.mkIf cfg.enable { - services.nginx = { - enable = true; - - recommendedBrotliSettings = true; - recommendedGzipSettings = true; - recommendedOptimisation = true; - recommendedProxySettings = true; - recommendedTlsSettings = true; - recommendedZstdSettings = true; - }; - }; -} diff --git a/modules/nixos/server/mixins/promtail.nix b/modules/nixos/server/mixins/promtail.nix deleted file mode 100644 index 173a85b..0000000 --- a/modules/nixos/server/mixins/promtail.nix +++ /dev/null @@ -1,48 +0,0 @@ -{ config, lib, ... }: -let - cfg = config.server.mixins.promtail; - inherit (lib) types; -in -{ - options.server.mixins.promtail = { - enable = lib.mkEnableOption "Promtail mixin"; - - clients = lib.mkOption { - type = types.listOf types.attrs; - default = [ { } ]; - defaultText = lib.literalExpression "[ { } ]"; - description = "Clients for promtail"; - }; - }; - - config = lib.mkIf cfg.enable { - services.promtail = { - enable = true; - configuration = { - inherit (cfg) clients; - server.disable = true; - - scrape_configs = [ - { - job_name = "journal"; - - journal = { - max_age = "12h"; - labels = { - job = "systemd-journal"; - host = "${config.networking.hostName}"; - }; - }; - - relabel_configs = [ - { - source_labels = [ "__journal__systemd_unit" ]; - target_label = "unit"; - } - ]; - } - ]; - }; - }; - }; -} diff --git a/modules/nixos/services/default.nix b/modules/nixos/services/default.nix new file mode 100644 index 0000000..038c3a6 --- /dev/null +++ b/modules/nixos/services/default.nix @@ -0,0 +1,3 @@ +{ + imports = [ ./github-mirror ]; +} diff --git a/modules/nixos/services/github-mirror/default.nix b/modules/nixos/services/github-mirror/default.nix new file mode 100644 index 0000000..9d0d870 --- /dev/null +++ b/modules/nixos/services/github-mirror/default.nix @@ -0,0 +1,101 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.github-mirror; + cgitInstance = config.services.cgit.${cfg.hostname}; + + update-mirror = + pkgs.runCommand "update-mirror" + { + nativeBuildInputs = [ pkgs.patsh ]; + + buildInputs = [ + config.programs.git.package + pkgs.curl + pkgs.jq + ]; + } + '' + patsh -s ${builtins.storeDir} ${./update-mirror.sh} $out + chmod 755 $out + patchShebangs $out + ''; +in +{ + options.services.github-mirror = { + enable = lib.mkEnableOption "the github-mirror service"; + + hostname = lib.mkOption { + type = lib.types.str; + description = "Hostname of the cgit service to create"; + example = lib.literalExpression "git.example.com"; + }; + + mirroredUsers = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = "List of GitHub users to mirror repositories for"; + example = lib.literalExpression ''[ "edolstra" ]''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.mirroredUsers != [ ]; + message = "`services.git-mirror.mirroredUsers` must have at least one user"; + } + ]; + + services.cgit.${cfg.hostname} = { + enable = true; + + scanPath = "/var/lib/cgit/${cfg.hostname}"; + settings = { + robots = "none"; # noindex, nofollow + }; + + user = "cgit"; + group = "cgit"; + }; + + systemd = { + services.github-mirror = { + description = "Mirror a GitHub repository"; + + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + + script = toString ( + [ + "exec" + (toString update-mirror) + "--directory" + cgitInstance.scanPath + ] + ++ cfg.mirroredUsers + ); + + serviceConfig = { + Type = "oneshot"; + User = cgitInstance.user; + Group = cgitInstance.group; + }; + }; + + timers.github-mirror = { + description = "Hourly timer for %N"; + timerConfig.OnCalendar = "hourly"; + }; + + tmpfiles.settings."10-github-mirror" = { + ${cgitInstance.scanPath}.d = { + inherit (cgitInstance) user group; + }; + }; + }; + }; +} diff --git a/modules/nixos/services/github-mirror/update-mirror.sh b/modules/nixos/services/github-mirror/update-mirror.sh new file mode 100755 index 0000000..c1e392d --- /dev/null +++ b/modules/nixos/services/github-mirror/update-mirror.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -euo pipefail + +help() { + echo "Mirror a GitHub user's repositories + +Usage: $(basename "$0") [options] ... + +Options: + -h --help Show this screen + -d --directory DIRECTORY Where to clone repositories (defaults to ./git)" +} + +create_if_not_exists() { + if [ ! -d "$1" ]; then + mkdir -p "$1" + fi +} + +repo_endpoint() { + echo "https://api.github.com/users/$1/repos" +} + +users=() +output_directory="git" + +while [ "$#" -gt 0 ]; do + case $1 in + -h | --help) + help + exit 0 + ;; + -d | --directory) + output_directory="$2" + shift + shift + ;; + -*) + echo "error: unknown option $1" + help + exit 1 + ;; + *) + users+=("$1") + shift + ;; + esac +done + +if [ "${#users[@]}" -lt 1 ]; then + echo "error: at least one user must be specified" + help + exit 1 +fi + +create_if_not_exists "$output_directory" +cd "$output_directory" + +for user in "${users[@]}"; do + create_if_not_exists "$user" + + url="$(repo_endpoint "$user")" + curl --fail --location --show-error --silent "$url" | jq --raw-output '.[].name' | while read -r repo; do + repo_path="$user"/"$repo" + + if [ -d "$repo_path"/.git ]; then + pushd "$repo_path" &>/dev/null + echo "Pulling $repo_path..." + if ! git remote update --prune &>/dev/null; then + echo "Unable to pull $repo_path! Continuing..." + fi + popd &>/dev/null + else + echo "Cloning $repo_path..." + git clone --bare --mirror https://github.com/"$repo_path".git "$repo_path" &>/dev/null + fi + done +done diff --git a/modules/nixos/traits/default.nix b/modules/nixos/traits/default.nix index 88a0b8c..1bb92b2 100644 --- a/modules/nixos/traits/default.nix +++ b/modules/nixos/traits/default.nix @@ -6,7 +6,9 @@ ./containers.nix ./home-manager.nix ./locale.nix + ./nvd-diff.nix ./nvidia.nix + ./resolved.nix ./secrets.nix ./tailscale.nix ./users diff --git a/modules/nixos/traits/nvd-diff.nix b/modules/nixos/traits/nvd-diff.nix new file mode 100644 index 0000000..4c59287 --- /dev/null +++ b/modules/nixos/traits/nvd-diff.nix @@ -0,0 +1,27 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.traits.nvd-diff; +in +{ + options.traits.nvd-diff = { + enable = lib.mkEnableOption "showing configuration diffs with NVD on upgrade" // { + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + system.activationScripts."upgrade-diff" = { + supportsDryActivation = true; + text = '' + ${lib.getExe pkgs.nvd} \ + --nix-bin-dir=${config.nix.package}/bin \ + diff /run/current-system "$systemConfig" + ''; + }; + }; +} diff --git a/modules/nixos/traits/resolved.nix b/modules/nixos/traits/resolved.nix new file mode 100644 index 0000000..d6501c9 --- /dev/null +++ b/modules/nixos/traits/resolved.nix @@ -0,0 +1,41 @@ +{ + config, + lib, + ... +}: +let + cfg = config.traits.resolved; +in +{ + options.traits.resolved = { + enable = lib.mkEnableOption "systemd-resolved as the DNS resolver" // { + default = true; + }; + + networkManagerIntegration = lib.mkEnableOption "integration with network-manager" // { + default = config.networking.networkmanager.enable; + defaultText = "config.networking.networkmanager.enable"; + }; + }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + networking.nameservers = [ + "1.1.1.1#one.one.one.one" + "1.0.0.1#one.one.one.one" + ]; + + services.resolved = { + enable = true; + dnssec = "allow-downgrade"; + dnsovertls = "true"; + }; + } + + (lib.mkIf cfg.networkManagerIntegration { + networking.networkmanager.dns = "systemd-resolved"; + }) + ] + ); +} diff --git a/modules/nixos/traits/secrets.nix b/modules/nixos/traits/secrets.nix index 6624ef8..d7f4e60 100644 --- a/modules/nixos/traits/secrets.nix +++ b/modules/nixos/traits/secrets.nix @@ -2,6 +2,7 @@ config, lib, inputs, + secretsDir, ... }: let @@ -10,17 +11,50 @@ in { options.traits.secrets = { enable = lib.mkEnableOption "secrets management"; - }; - - imports = [ inputs.agenix.nixosModules.default ]; - config = lib.mkIf cfg.enable { - _module.args = { - secretsDir = inputs.self + "/secrets/${config.networking.hostName}"; + rootUser = lib.mkEnableOption "manage secrets for root user" // { + default = true; }; - age = { - identityPaths = [ "/etc/age/key" ]; + hostUser = lib.mkEnableOption "manager secrets for host user (see `profiles.server.hostUser`)" // { + default = config.profiles.server.hostUser; + defaultText = "config.profiles.server.hostUser"; }; }; + + imports = [ inputs.agenix.nixosModules.default ]; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + _module.args = { + secretsDir = inputs.self + "/secrets/${config.networking.hostName}"; + }; + + age = { + identityPaths = [ "/etc/age/key" ]; + }; + } + + (lib.mkIf cfg.rootUser { + age.secrets = { + rootPassword.file = secretsDir + "/rootPassword.age"; + }; + + users.users.root = { + hashedPasswordFile = config.age.secrets.rootPassword.path; + }; + }) + + (lib.mkIf (config.profiles.server.enable && cfg.hostUser) { + age.secrets = { + userPassword.file = secretsDir + "/userPassword.age"; + }; + + users.users.${config.networking.hostName} = { + hashedPasswordFile = config.age.secrets.userPassword.path; + }; + }) + ] + ); } -- cgit v1.2.3