feat(a1d1): init

Co-Authored-By: Samuel Shuert <coded@clicks.codes>
Change-Id: Iaf1499b8cde6d3f6bdb024374f6830d582006aeb
Reviewed-on: https://git.clicks.codes/c/Infra/NixFiles/+/720
Tested-by: Samuel Shuert <coded@clicks.codes>
Reviewed-by: Samuel Shuert <coded@clicks.codes>
diff --git a/modules/nixos/clicks/nix/default.nix b/modules/nixos/clicks/nix/default.nix
new file mode 100644
index 0000000..742980d
--- /dev/null
+++ b/modules/nixos/clicks/nix/default.nix
@@ -0,0 +1,103 @@
+# SPDX-FileCopyrightText: 2024 Auxolotl Infrastructure Contributors
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{
+  options,
+  config,
+  pkgs,
+  lib,
+  inputs,
+  ...
+}:
+let
+  cfg = config.clicks.nix;
+
+  substituters-submodule = lib.types.submodule (
+    { name, ... }:
+    {
+      options = {
+        key = lib.mkOption {
+          type = lib.types.nullOr lib.types.str;
+          default = null;
+          description = "The trusted public key for this substituter.";
+        };
+      };
+    }
+  );
+in
+{
+  options.clicks.nix = {
+    enable = lib.mkEnableOption "Nix configuration";
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.nix;
+      defaultText = "pkgs.nix";
+      description = "Which Nix package to use.";
+    };
+
+    default-substituter = {
+      url = lib.mkOption {
+        type = lib.types.str;
+        default = "https://cache.nixos.org";
+        description = "The url for the substituter.";
+      };
+      key = lib.mkOption {
+        type = lib.types.str;
+        default = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=";
+        description = "The trusted public key for the substituter.";
+      };
+    };
+
+    extra-substituters = lib.mkOption {
+      type = lib.types.attrsOf substituters-submodule;
+      default = { };
+      description = "Extra substituters to configure.";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    assertions = lib.mapAttrsToList (name: value: {
+      assertion = value.key != null;
+      message = "auxolotl.nix.extra-substituters.${name}.key must be set";
+    }) cfg.extra-substituters;
+
+    nix =
+      let
+        users = [ "root" ];
+      in
+      {
+        package = cfg.package;
+
+        settings = {
+          experimental-features = "nix-command flakes";
+          http-connections = 50;
+          log-lines = 50;
+          auto-optimise-store = true;
+
+          trusted-users = users;
+          allowed-users = users;
+
+          substituters = [
+            cfg.default-substituter.url
+          ] ++ (lib.mapAttrsToList (name: value: name) cfg.extra-substituters);
+
+          trusted-public-keys = [
+            cfg.default-substituter.key
+          ] ++ (lib.mapAttrsToList (name: value: value.key) cfg.extra-substituters);
+        };
+
+        gc = {
+          automatic = true;
+          dates = "weekly";
+          options = "--delete-older-than 30d";
+        };
+
+        # flake-utils-plus
+        generateRegistryFromInputs = true;
+        generateNixPathFromInputs = true;
+        linkInputs = true;
+      };
+  };
+}
diff --git a/modules/nixos/clicks/security/acme/default.nix b/modules/nixos/clicks/security/acme/default.nix
new file mode 100644
index 0000000..655e39f
--- /dev/null
+++ b/modules/nixos/clicks/security/acme/default.nix
@@ -0,0 +1,42 @@
+# SPDX-FileCopyrightText: 2024 Auxolotl Infrastructure Contributors
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{ lib, config, ... }:
+let
+  cfg = config.clicks.security.acme;
+in
+{
+  options.clicks.security.acme = {
+    enable = lib.mkEnableOption "Acme defaults";
+
+    email = lib.mkOption {
+      type = lib.types.str;
+      default = "";
+      description = "Email address to use for Let's Encrypt registration.";
+    };
+
+    staging = lib.mkOption {
+      type = lib.types.bool;
+      default = false;
+      description = "Use the Let's Encrypt staging server.";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    security.acme = {
+      acceptTerms = true;
+
+      defaults = {
+        inherit (cfg) email;
+
+        group = lib.mkIf config.services.nginx.enable "nginx";
+        server = lib.mkIf cfg.staging "https://acme-staging-v02.api.letsencrypt.org/directory";
+
+        # Reload nginx when certs change.
+        reloadServices = lib.optional config.services.nginx.enable "nginx.service";
+      };
+    };
+  };
+}
diff --git a/modules/nixos/clicks/security/doas/default.nix b/modules/nixos/clicks/security/doas/default.nix
new file mode 100644
index 0000000..424d9d7
--- /dev/null
+++ b/modules/nixos/clicks/security/doas/default.nix
@@ -0,0 +1,38 @@
+# SPDX-FileCopyrightText: 2024 Auxolotl Infrastructure Contributors
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{
+  lib,
+  pkgs,
+  config,
+  ...
+}:
+let
+  cfg = config.clicks.security.doas;
+in
+{
+  options.clicks.security.doas = {
+    enable = lib.mkEnableOption "doas";
+  };
+
+  config = lib.mkIf cfg.enable {
+    security.sudo.enable = false;
+
+    security.doas = {
+      enable = true;
+      extraRules = [
+        {
+          users = config.clicks.users.deployers;
+          noPass = true;
+          keepEnv = true;
+        }
+      ];
+    };
+
+    environment.shellAliases = {
+      sudo = "${config.security.wrapperDir}/${config.security.wrappers.doas.program}";
+    };
+  };
+}
diff --git a/modules/nixos/clicks/services/ssh/default.nix b/modules/nixos/clicks/services/ssh/default.nix
new file mode 100644
index 0000000..eedfe6c
--- /dev/null
+++ b/modules/nixos/clicks/services/ssh/default.nix
@@ -0,0 +1,20 @@
+# SPDX-FileCopyrightText: 2024 Auxolotl Infrastructure Contributors
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{ lib, config, ... }:
+let
+  cfg = config.clicks.services.ssh;
+in
+{
+  options.clicks.services.ssh = {
+    enable = lib.mkEnableOption "SSH";
+  };
+
+  config = lib.mkIf cfg.enable {
+    services.openssh = {
+      enable = true;
+    };
+  };
+}
diff --git a/modules/nixos/clicks/users/default.nix b/modules/nixos/clicks/users/default.nix
new file mode 100644
index 0000000..4e169ce
--- /dev/null
+++ b/modules/nixos/clicks/users/default.nix
@@ -0,0 +1,19 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{
+  config,
+  lib,
+  pkgs,
+  ...
+}:
+{
+  options = {
+    clicks.users.deployers = lib.mkOption {
+      type = lib.types.listOf lib.types.str;
+      default = [ ];
+      description = "Users who should be allowed to deploy to this server. They will be given passwordless access to run commands as root";
+    };
+  };
+}
diff --git a/modules/nixos/clicks/users/minion/default.nix b/modules/nixos/clicks/users/minion/default.nix
new file mode 100644
index 0000000..7b3c2ee
--- /dev/null
+++ b/modules/nixos/clicks/users/minion/default.nix
@@ -0,0 +1,31 @@
+# SPDX-FileCopyrightText: 2024 Clicks Codes
+#
+# SPDX-License-Identifier: GPL-3.0-only
+
+{ lib, config, ... }:
+{
+  options = {
+    clicks.users.minion.enable = lib.mkOption {
+      type = lib.types.bool;
+      default = true;
+    };
+  };
+
+  config = lib.mkIf config.clicks.users.minion.enable {
+    nix.settings.trusted-users = [ "minion" ];
+    clicks.users.deployers = [ "minion" ];
+
+    users.users.minion = {
+      isNormalUser = true;
+      group = "minion";
+
+      openssh.authorizedKeys.keys = [
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIIteIdlZv52nUDxW2SUsoJ2NZi/w9j1NZwuHanQ/o/DuAAAAHnNzaDpjb2xsYWJvcmFfeXViaWtleV9yZXNpZGVudA== collabora_yubikey_resident"
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIJRzQbQjXFpHKtt8lpNKmoNx57+EJ/z3wnKOn3/LjM6cAAAAFXNzaDppeXViaWtleV9yZXNpZGVudA== iyubikey_resident"
+        "sk-ssh-ed25519@openssh.com AAAAGnNrLXNzaC1lZDI1NTE5QG9wZW5zc2guY29tAAAAIOhzJ0p9bFRSURUjV05rrt5jCbxPXke7juNbEC9ZJXS/AAAAGXNzaDp0aW55X3l1YmlrZXlfcmVzaWRlbnQ= tiny_yubikey_resident"
+      ];
+    };
+
+    users.groups.minion = { };
+  };
+}