diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..6931e02 --- /dev/null +++ b/flake.lock @@ -0,0 +1,93 @@ +{ + "nodes": { + "nix-index-database": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1703387252, + "narHash": "sha256-XKJqGj0BaEn/zyctEnkgVIh6Ba1rgTRc+UBi9EU8Y54=", + "owner": "Mic92", + "repo": "nix-index-database", + "rev": "f4340c1a42c38d79293ba69bfd839fbd6268a538", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "nix-index-database", + "type": "github" + } + }, + "nixos-modules": { + "inputs": { + "nixpkgs-lib": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1703426109, + "narHash": "sha256-/ujCgLJUq+iMgrvMVj58uvXan/nKvG0SeNVVrsvzJHk=", + "owner": "SuperSandro2000", + "repo": "nixos-modules", + "rev": "caa008d22e663c6190ffe12286566b2e87f357e4", + "type": "github" + }, + "original": { + "owner": "SuperSandro2000", + "repo": "nixos-modules", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1703255338, + "narHash": "sha256-Z6wfYJQKmDN9xciTwU3cOiOk+NElxdZwy/FiHctCzjU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "6df37dc6a77654682fe9f071c62b4242b5342e04", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nix-index-database": "nix-index-database", + "nixos-modules": "nixos-modules", + "nixpkgs": "nixpkgs", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1703387502, + "narHash": "sha256-JnWuQmyanPtF8c5yAEFXVWzaIlMxA3EAZCh8XNvnVqE=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "e523e89763ff45f0a6cf15bcb1092636b1da9ed3", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 58c1766..9a35f2b 100644 --- a/flake.nix +++ b/flake.nix @@ -4,9 +4,17 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + nixos-modules = { + url = "github:SuperSandro2000/nixos-modules"; + inputs.nixpkgs-lib.follows = "nixpkgs"; + }; + sops-nix = { url = "github:Mic92/sops-nix"; - inputs.nixpkgs.follows = "nixpkgs"; + inputs = { + nixpkgs.follows = "nixpkgs"; + nixpkgs-stable.follows = "nixpkgs"; + }; }; nix-index-database = { @@ -15,33 +23,36 @@ }; }; - outputs = { nixpkgs, nix-index-database, sops-nix, ... }: { - src = builtins.filterSource (path: type: type == "directory" || lib.hasSuffix ".nix" (baseNameOf path)) ./.; - ls = dir: lib.attrNames (builtins.readDir (src + "/${dir}")); - fileList = dir: map (file: ./. + "/${dir}/${file}") (ls dir); + outputs = { nixpkgs, nixos-modules, nix-index-database, sops-nix, ... }: + let + inherit (nixpkgs) lib; + in { nixosConfigurations = let constructSystem = { hostname, system ? "x86_64-linux", modules ? [], users ? [], - }: nixpkgs.lib.nixosSystem { - inherit system hostname; + }: lib.nixosSystem { + inherit system; + modules = [ + nixos-modules.nixosModule sops-nix.nixosModules.sops nix-index-database.nixosModules.nix-index - ./system/programs.nix - ./system/configuration.nix - ./system/${hostname}/configuration.nix - ] ++ fileList "modules" ++ modules ++ map (user: ./users/${user}/default.nix ) users; + ./systems/programs.nix + ./systems/configuration.nix + ./systems/${hostname}/configuration.nix + ] ++ modules ++ map(user: ./users/${user}) users; + }; in { photon = constructSystem { - hostname = "photon" + hostname = "photon"; }; palatine-hill = constructSystem { - hostname = "palatine-hill" + hostname = "palatine-hill"; }; }; }; diff --git a/lib/ldap.nix b/lib/ldap.nix deleted file mode 100644 index c954574..0000000 --- a/lib/ldap.nix +++ /dev/null @@ -1,9 +0,0 @@ -{ lib, ... }: - -{ - mkUserGroupOption = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - description = lib.mdDoc "Restrict logins to users in this group"; - }; -} diff --git a/lib/modules.nix b/lib/modules.nix deleted file mode 100644 index b74fbcc..0000000 --- a/lib/modules.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ config, lib, ... }: - -{ - mkOpinionatedOption = text: lib.mkOption { - type = lib.types.bool; - default = config.opinionatedDefaults; - description = lib.mdDoc "Whether to ${text}."; - }; - - mkRecursiveDefault = lib.mapAttrsRecursive (_: lib.mkDefault); -} diff --git a/lib/nix.nix b/lib/nix.nix deleted file mode 100644 index c7f3455..0000000 --- a/lib/nix.nix +++ /dev/null @@ -1,8 +0,0 @@ -{ lib, ... }: - -{ - # taken from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/misc/nix-daemon.nix#L828-L832 - # a builder can run code for `gcc.arch` and inferior architectures - gcc-system-features = arch: [ "gccarch-${arch}" ] - ++ map (x: "gccarch-${x}") lib.systems.architectures.inferiors.${arch}; -} diff --git a/lib/ssh.nix b/lib/ssh.nix deleted file mode 100644 index e13b5a2..0000000 --- a/lib/ssh.nix +++ /dev/null @@ -1,10 +0,0 @@ -_: - -{ - mkPubKey = name: type: publicKey: { - "${name}-${type}" = { - extraHostNames = [ name ]; - publicKey = "${type} ${publicKey}"; - }; - }; -} diff --git a/modules/acme.nix b/modules/acme.nix deleted file mode 100644 index 28cdbc2..0000000 --- a/modules/acme.nix +++ /dev/null @@ -1,21 +0,0 @@ -{ config, lib, ... }: - -let - cfg = config.security.acme; -in -{ - options.security.acme.staging = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc '' - If set to true, use Let's Encrypt's staging environment instead of the production one. - The staging environment has much higher rate limits but does not generate fully signed certificates. - This is great for testing when the normla rate limit is hit fast and impacts other people on the same IP. - See https://letsencrypt.org/docs/staging-environment for more detail. - ''; - }; - - config = lib.mkIf cfg.staging { - security.acme.server = "https://acme-staging-v02.api.letsencrypt.org/directory"; - }; -} diff --git a/modules/boot.nix b/modules/boot.nix deleted file mode 100644 index 0b3d873..0000000 --- a/modules/boot.nix +++ /dev/null @@ -1,41 +0,0 @@ -{ config, lib, ... }: - -let - cfg = config.boot; -in -{ - options = { - boot = { - default = lib.mkOpinionatedOption "enable the boot builder"; - }; - }; - - cfg = lib.mkIf cfg.default { - supportedFilesystems = [ "zfs" ]; - tmp.useTmpfs = true; - kernelPackages = config.boot.zfs.package.latestCompatibleLinuxPackages; - kernelParams = [ "kvm-amd" "nordrand" ]; - zfs = { - enableUnstable = true; - devNodes = "/dev/disk/by-id/"; - forceImportRoot = true; - }; - loader = { - efi = { - canTouchEfiVariables = false; - efiSysMountPoint = "/boot/efis/nvme-Samsung_SSD_980_PRO_1TB_S5GXNF0W178262L-part1"; - }; - generationsDir.copyKernels = true; - grub = { - enable = true; - copyKernels = true; - zfsSupport = true; - efiSupport = true; - efiInstallAsRemovable = true; - fsIdentifier = "uuid"; - device = "nodev"; - extraInstallCommands = "[ ! -e /boot/efis/nvme-Samsung_SSD_980_PRO_1TB_S5GXNF0W178262L-part1/EFI ] || cp -r /boot/efis/nvme-Samsung_SSD_980_PRO_1TB_S5GXNF0W178262L-part1/EFI/* /boot/efis/nvme-Samsung_SSD_980_PRO_1TB_S5GXNF0W178262L-part1"; - }; - }; - }; -} \ No newline at end of file diff --git a/modules/containers.nix b/modules/containers.nix deleted file mode 100644 index 7f0d5f4..0000000 --- a/modules/containers.nix +++ /dev/null @@ -1,56 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.virtualisation; - cfgd = cfg.docker; - cfgp = cfg.podman; -in -{ - options.virtualisation = { - docker = { - aggresiveAutoPrune = libS.mkOpinionatedOption "configure aggresive auto prune which removes everything unreferenced by running containers. This includes named volumes and mounts should be used instead"; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended and maintenance reducing default settings"; - }; - - podman.recommendedDefaults = libS.mkOpinionatedOption "set recommended and maintenance reducing default settings"; - }; - - config = { - virtualisation = { - containers.registries.search = lib.mkIf cfgp.recommendedDefaults [ - "docker.io" - "quay.io" - "ghcr.io" - "gcr.io" - ]; - - docker = { - daemon.settings = let - useIPTables = !config.networking.nftables.enable; - in lib.mkIf cfgd.recommendedDefaults { - fixed-cidr-v6 = "fd00::/80"; # TODO: is this a good idea for all networks? - iptables = useIPTables; - ip6tables = useIPTables; - ipv6 = true; - # userland proxy is slow, does not give back ports and if iptables/nftables is avaible just worsefgd.aggresiveAutoPrune - userland-proxy = false; - }; - autoPrune = lib.mkIf cfgd.aggresiveAutoPrune { - enable = true; - flags = [ - "--all" - "--external" - "--force" - "--volumes" - ]; - }; - }; - - podman = { - autoPrune.enable = lib.mkIf cfgp.recommendedDefaults true; - defaultNetwork.settings.dns_enabled = lib.mkIf cfgp.recommendedDefaults true; - }; - }; - }; -} diff --git a/modules/gitea.nix b/modules/gitea.nix deleted file mode 100644 index 1f3722c..0000000 --- a/modules/gitea.nix +++ /dev/null @@ -1,147 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.services.gitea; - cfgl = cfg.ldap; - inherit (config.security) ldap; -in -{ - options = { - services.gitea = { - # based on https://github.com/majewsky/nixos-modules/blob/master/gitea.nix - ldap = { - enable = lib.mkEnableOption (lib.mdDoc "login via ldap"); - - adminGroup = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - example = "gitea-admins"; - description = lib.mdDoc "Name of the ldap group that grants admin access in gitea."; - }; - - bindPasswordFile = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - example = "/var/lib/secrets/bind-password"; - description = lib.mdDoc "Path to a file containing the bind password."; - }; - - userGroup = libS.ldap.mkUserGroupOption; - - options = - let - mkOptStr = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - }; - in - { - id = lib.mkOption { - type = lib.types.ints.unsigned; - default = 1; - }; - name = mkOptStr; - security-protocol = mkOptStr; - host = mkOptStr; - port = lib.mkOption { - type = with lib.types; nullOr port; - default = null; - }; - bind-dn = mkOptStr; - bind-password = mkOptStr; - user-search-base = mkOptStr; - user-filter = mkOptStr; - admin-filter = mkOptStr; - username-attribute = mkOptStr; - firstname-attribute = mkOptStr; - surname-attribute = mkOptStr; - email-attribute = mkOptStr; - public-ssh-key-attribute = mkOptStr; - }; - }; - recommendedDefaults = libS.mkOpinionatedOption "set recommended, secure default settings"; - }; - }; - - config.services.gitea = lib.mkIf (cfg.enable && cfgl.enable) { - ldap.options = { - name = "ldap"; - security-protocol = "LDAPS"; - host = ldap.domainName; - inherit (ldap) port; - bind-dn = ldap.bindDN; - bind-password = "$(cat ${cfgl.bindPasswordFile})"; - user-search-base = ldap.userBaseDN; - user-filter = ldap.searchFilterWithGroupFilter cfgl.userGroup (ldap.userFilter "%[1]s"); - admin-filter = ldap.groupFilter cfgl.adminGroup; - username-attribute = ldap.userField; - firstname-attribute = ldap.givenNameField; - surname-attribute = ldap.surnameField; - email-attribute = ldap.mailField; - public-ssh-key-attribute = ldap.sshPublicKeyField; - }; - settings = lib.mkIf cfg.recommendedDefaults (libS.modules.mkRecursiveDefault { - cors = { - ALLOW_DOMAIN = cfg.settings.server.DOMAIN; - ENABLED = true; - SCHEME = "https"; - }; - cron.ENABLED = true; - "cron.resync_all_sshkeys".ENABLED = true; - "cron.resync_all_hooks".ENABLED = true; - other.SHOW_FOOTER_VERSION = false; - repository.ACCESS_CONTROL_ALLOW_ORIGIN = cfg.settings.server.DOMAIN; - "repository.signing".DEFAULT_TRUST_MODEL = "committer"; - security.DISABLE_GIT_HOOKS = true; - server = { - ENABLE_GZIP = true; - ROOT_URL = "https://${cfg.settings.server.DOMAIN}/"; - SSH_SERVER_CIPHERS = "chacha20-poly1305@openssh.com, aes256-gcm@openssh.com, aes128-gcm@openssh.com"; - SSH_SERVER_KEY_EXCHANGES = "curve25519-sha256@libssh.org, ecdh-sha2-nistp521, ecdh-sha2-nistp384, ecdh-sha2-nistp256, diffie-hellman-group14-sha1"; - SSH_SERVER_MACS = "hmac-sha2-256-etm@openssh.com, hmac-sha2-256, hmac-sha1"; - }; - session = { - COOKIE_SECURE = true; - PROVIDER = "db"; - SAME_SITE = "strict"; - SESSION_LIFE_TIME = 28 * 86400; # 28 days - }; - "ssh.minimum_key_sizes" = { - ECDSA = -1; - RSA = 4095; - }; - time.DEFAULT_UI_LOCATION = config.time.timeZone; - }); - }; - - config.systemd.services = lib.mkIf (cfg.enable && cfgl.enable) { - gitea.preStart = - let - exe = lib.getExe cfg.package; - # allow executing shell after the --bind-password argument to e.g. cat a password file - formatOption = key: value: "--${key} ${if key == "bind-password" then value else lib.escapeShellArg value}"; - ldapOptionsStr = opt: lib.concatStringsSep " " (lib.mapAttrsToList formatOption opt); - commonArgs = "--attributes-in-bind --synchronize-users"; - in - lib.mkAfter '' - if ${exe} admin auth list | grep -q ${cfgl.options.name}; then - ${exe} admin auth update-ldap ${commonArgs} ${ldapOptionsStr cfgl.options} - else - ${exe} admin auth add-ldap ${commonArgs} ${ldapOptionsStr (lib.filterAttrs (name: _: name != "id") cfgl.options)} - fi - ''; - }; - - config.services.portunus.seedSettings.groups = [ - (lib.mkIf (cfgl.adminGroup != null) { - long_name = "Gitea Administrators"; - name = cfgl.adminGroup; - permissions = { }; - }) - (lib.mkIf (cfgl.userGroup != null) { - long_name = "Gitea Users"; - name = cfgl.userGroup; - permissions = { }; - }) - ]; -} diff --git a/modules/grafana.nix b/modules/grafana.nix deleted file mode 100644 index 6a22126..0000000 --- a/modules/grafana.nix +++ /dev/null @@ -1,130 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.services.grafana; -in -{ - options = { - services.grafana = { - configureNginx = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc "Wether to configure Nginx."; - }; - - oauth = { - enable = lib.mkEnableOption (lib.mdDoc ''login only via OAuth2''); - enableViewerRole = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc "Wether to enable the fallback Viewer role when users do not have the user- or adminGroup."; - }; - adminGroup = libS.ldap.mkUserGroupOption; - userGroup = libS.ldap.mkUserGroupOption; - }; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended and secure default settings"; - }; - }; - - config = { - # the default values are hardcoded instead of using options. because I couldn't figure out how to extract them from the freeform type - assertions = lib.mkIf cfg.enable [ - { - assertion = cfg.oauth.enable -> cfg.settings."auth.generic_oauth".client_secret != null; - message = '' - Setting services.grafana.oauth.enable to true requires to set services.grafana.settings."auth.generic_oauth".client_secret. - Use this `$__file{/path/to/some/secret}` syntax to reference secrets securely. - ''; - } - { - assertion = cfg.settings.security.secret_key != "SW2YcwTIb9zpOOhoPsMm"; - message = "services.grafana.settings.security.secret_key must be changed from it's insecure, default value!"; - } - { - assertion = cfg.settings.security.admin_password != "admin"; - message = "services.grafana.settings.security.admin_password must be changed from it's insecure, default value!"; - } - ]; - - services.grafana.settings = lib.mkMerge [ - (lib.mkIf (cfg.enable && cfg.recommendedDefaults) (libS.modules.mkRecursiveDefault { - # no analytics, sorry, not sorry - analytics = { - # TODO: drop after https://github.com/NixOS/nixpkgs/pull/240323 is merged - check_for_updates = false; - feedback_links_enabled = false; - reporting_enabled = false; - }; - log.level = "warn"; - security = { - cookie_secure = true; - content_security_policy = true; - strict_transport_security = true; - }; - server = { - enable_gzip = true; - root_url = "https://${cfg.settings.server.domain}"; - }; - })) - - (lib.mkIf (cfg.enable && cfg.oauth.enable) { - "auth.generic_oauth" = let - inherit (config.services.dex.settings) issuer; - in { - enabled = true; - allow_assign_grafana_admin = true; # required for grafana-admins - allow_sign_up = true; # otherwise no new users can be created - api_url = "${issuer}/userinfo"; - auth_url = "${issuer}/auth"; - client_id = "grafana"; - disable_login_form = true; # only allow OAuth - icon = "signin"; - name = config.services.portunus.domain; - oauth_allow_insecure_email_lookup = true; # otherwise updating the mail in ldap will break login - oauth_auto_login = true; # redirect automatically to the only oauth provider - use_refresh_token = true; - role_attribute_path = "contains(groups[*], 'grafana-admins') && 'Admin' || contains(info.roles[*], 'grafana-user') && 'Editor'" - + lib.optionalString cfg.oauth.enableViewerRole "|| 'Viewer'"; - role_attribute_strict = true; - # https://dexidp.io/docs/custom-scopes-claims-clients/ - scopes = "openid email groups profile offline_access"; - token_url = "${issuer}/token"; - }; - server.protocol = "socket"; - }) - ]; - }; - - config.services.nginx = lib.mkIf (cfg.enable && cfg.configureNginx) { - upstreams.grafana.servers."unix:${cfg.settings.server.socket}" = {}; - virtualHosts = { - "${cfg.settings.server.domain}".locations = { - "/".proxyPass = "http://grafana"; - "/api/live/ws" = { - proxyPass = "http://grafana"; - proxyWebsockets = true; - }; - }; - }; - }; - - config.services.portunus = { - dex = lib.mkIf cfg.oauth.enable { - enable = true; - oidcClients = [{ - callbackURL = "https://${cfg.settings.server.domain}/login/generic_oauth"; - id = "grafana"; - }]; - }; - seedSettings.groups = lib.optional (cfg.oauth.adminGroup != null) { - long_name = "Grafana Administrators"; - name = cfg.oauth.adminGroup; - permissions = { }; - } ++ lib.optional (cfg.oauth.userGroup != null) { - long_name = "Grafana Users"; - name = cfg.oauth.userGroup; - permissions = { }; - }; - }; -} diff --git a/modules/hedgedoc.nix b/modules/hedgedoc.nix deleted file mode 100644 index 512d35b..0000000 --- a/modules/hedgedoc.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.services.hedgedoc.ldap; - inherit (config.security) ldap; -in -{ - options = { - services.hedgedoc.ldap = { - enable = lib.mkEnableOption (lib.mdDoc '' - login only via LDAP. - Use `service.hedgedoc.environmentFile` in format `bindCredentials=password` to set the credentials used by the search user - ''); - - userGroup = libS.ldap.mkUserGroupOption; - }; - }; - - config.services.hedgedoc.settings.ldap = lib.mkIf cfg.enable { - url = "ldaps://${ldap.domainName}:${toString ldap.port}"; - bindDn = ldap.bindDN; - bindCredentials = "$bindCredentials"; - searchBase = ldap.userBaseDN; - searchFilter = ldap.searchFilterWithGroupFilter cfg.userGroup (ldap.userFilter "{{username}}"); - tlsca = "/etc/ssl/certs/ca-certificates.crt"; - useridField = ldap.userField; - }; - - config.services.portunus.seedSettings.groups = lib.optional (cfg.userGroup != null) { - long_name = "Hedgedoc Users"; - name = cfg.userGroup; - permissions = {}; - }; -} diff --git a/modules/home-assistant.nix b/modules/home-assistant.nix deleted file mode 100644 index 7946d61..0000000 --- a/modules/home-assistant.nix +++ /dev/null @@ -1,103 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -let - cfg = config.services.home-assistant; - inherit (config.security) ldap; -in -{ - options = { - services.home-assistant = { - ldap = { - enable = lib.mkEnableOption (lib.mdDoc ''login only via LDAP - - ::: {.note} - Only enable this after completing the onboarding! - ::: - ''); - userGroup = libS.ldap.mkUserGroupOption; - }; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended default settings"; - }; - }; - - config.services.home-assistant = lib.mkMerge [ - (lib.mkIf (cfg.enable && cfg.recommendedDefaults) { - config = { - automation = "!include automations.yaml"; - default_config = { }; # yes, this is required... - homeassistant = { - auth_providers = lib.mkIf (!cfg.ldap.enable) [ - { type = "homeassistant"; } - ]; - temperature_unit = "C"; - time_zone = config.time.timeZone; - unit_system = "metric"; - }; - }; - }) - - (lib.mkIf (cfg.enable && cfg.ldap.enable) { - config.homeassistant.auth_providers = [{ - type = "command_line"; - # the script is not inheriting PATH from home-assistant - command = pkgs.resholve.mkDerivation { - pname = "ldap-auth-sh"; - version = "unstable-2019-02-23"; - - src = pkgs.fetchFromGitHub { - owner = "bob1de"; - repo = "ldap-auth-sh"; - rev = "819f9233116e68b5af5a5f45167bcbb4ed412ed4"; - hash = "sha256-+QjRP5SKUojaCv3lZX2Kv3wkaNvpWFd97phwsRlhroY="; - }; - - installPhase = '' - install -Dm755 ldap-auth.sh -t $out/bin - ''; - - solutions.default = { - fake.external = [ "on_auth_failure" "on_auth_success" ]; - inputs = with pkgs; [ coreutils curl gnugrep gnused openldap ]; - interpreter = "${pkgs.bash}/bin/bash"; - keep."source:$CONFIG_FILE" = true; - scripts = [ "bin/ldap-auth.sh" ]; - }; - }+ "/bin/ldap-auth.sh"; - args = [ - # https://github.com/bob1de/ldap-auth-sh/blob/master/examples/home-assistant.cfg - (pkgs.writeText "config.cfg" /* shell */ '' - ATTRS="${ldap.userField}" - CLIENT="ldapsearch" - DEBUG=0 - FILTER="${ldap.groupFilter "home-assistant-users"}" - NAME_ATTR="${ldap.userField}" - SCOPE="base" - SERVER="ldaps://${ldap.domainName}" - USERDN="uid=$(ldap_dn_escape "$username"),${ldap.userBaseDN}" - BASEDN="$USERDN" - - on_auth_success() { - # print the meta entries for use in HA - if [ ! -z "$NAME_ATTR" ]; then - name=$(echo "$output" | ${lib.getExe pkgs.gnused} -nr "s/^\s*$NAME_ATTR:\s*(.+)\s*\$/\1/Ip") - [ -z "$name" ] || echo "name=$name" - fi - } - '') - ]; - meta = true; - }]; - }) - ]; - - config.services.portunus.seedSettings.groups = lib.optional (cfg.ldap.userGroup != null) { - long_name = "Home-Assistant Users"; - name = cfg.ldap.userGroup; - permissions = { }; - }; - - config.systemd.tmpfiles.rules = lib.mkIf (cfg.enable && cfg.recommendedDefaults) [ - "f ${cfg.configDir}/automations.yaml 0444 hass hass" - ]; -} diff --git a/modules/hydra.nix b/modules/hydra.nix deleted file mode 100644 index 9e2ddb5..0000000 --- a/modules/hydra.nix +++ /dev/null @@ -1,91 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.services.hydra.ldap; - inherit (config.security) ldap; -in -{ - options = { - services.hydra.ldap = { - enable = lib.mkEnableOption (lib.mdDoc '' - login only via LDAP. - The bind user password must be placed at `/var/lib/hydra/ldap-password.conf` in the format `bindpw = "PASSWORD" - It is recommended to use a password without special characters because the perl config parser has weird escaping rule like that comment characters `#` must be escape with backslash - ''); - - roleMappings = lib.mkOption { - type = with lib.types; listOf (attrsOf str); - example = [{ hydra-admins = "admins"; }]; - default = [ ]; - description = lib.mdDoc "Map LDAP groups to hydra permissions. See upstream doc, especially role_mapping."; - }; - - userGroup = libS.ldap.mkUserGroupOption; - }; - }; - - config.services.hydra.extraConfig = lib.mkIf cfg.enable /* xml */ '' - # https://hydra.nixos.org/build/196107287/download/1/hydra/configuration.html#using-ldap-as-authentication-backend-optional - - - - class = Password - password_field = password - password_type = self_check - - - class = LDAP - ldap_server = "${ldap.domainName}" - - scheme = ldaps - timeout = 10 - - binddn = "${ldap.bindDN}" - include ldap-password.conf - start_tls = 0 - - ciphers = TLS_AES_256_GCM_SHA384 - sslversion = tlsv1_3 - - user_basedn = "${ldap.userBaseDN}" - user_filter = "${ldap.searchFilterWithGroupFilter cfg.userGroup (ldap.userFilter "%s")}" - user_scope = one - user_field = ${ldap.userField} - - deref = always - - # Important for role mappings to work: - use_roles = 1 - role_basedn = "${ldap.roleBaseDN}" - role_filter = "${ldap.roleFilter}" - role_scope = one - role_field = ${ldap.roleField} - role_value = ${ldap.roleValue} - - deref = always - - - - - # Make all users in the hydra-admin group Hydra admins - # hydra-admins = admin - # Allow all users in the dev group to restart jobs and cancel builds - # dev = restart-jobs - # dev = cancel-build - ${lib.concatStringsSep "\n" (lib.concatMap (lib.mapAttrsToList (name: value: "${name} = ${value}")) cfg.roleMappings)} - - - ''; - - config.services.portunus.seedSettings.groups = [ - (lib.mkIf (cfg.userGroup != null) { - long_name = "Hydra Users"; - name = cfg.userGroup; - permissions = { }; - }) - ] ++ lib.flatten (map lib.attrValues (map (lib.mapAttrs (ldapGroup: _: { - long_name = "Hydra Role ${ldapGroup}"; - name = ldapGroup; - permissions = { }; - })) cfg.roleMappings)); -} diff --git a/modules/intel.nix b/modules/intel.nix deleted file mode 100644 index f5c61a8..0000000 --- a/modules/intel.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - options.hardware = { - intelGPU = lib.mkEnableOption "" // { description = "Whether to add drivers for intel hardware acceleration."; }; - }; - - config = { - hardware.opengl = { - extraPackages = with pkgs; lib.mkIf config.hardware.intelGPU [ - intel-compute-runtime # OpenCL library for iGPU - # video encoding/decoding hardware acceleration - intel-media-driver # broadwell or newer - intel-vaapi-driver # older hardware like haswell - ]; - extraPackages32 = with pkgs.pkgsi686Linux; lib.mkIf config.hardware.intelGPU [ - # video encoding/decoding hardware acceleration - intel-media-driver # broadwell or newer - intel-vaapi-driver # older hardware like haswell - ]; - }; - }; -} diff --git a/modules/ldap.nix b/modules/ldap.nix deleted file mode 100644 index 117e776..0000000 --- a/modules/ldap.nix +++ /dev/null @@ -1,146 +0,0 @@ -{ config, lib, ... }: - -let - cfg = config.security.ldap; -in -{ - options.security.ldap = lib.mkOption { - type = lib.types.submodule { - options = { - bindDN = lib.mkOption { - type = lib.types.str; - example = "uid=search"; - default = "uid=${cfg.searchUID}"; - apply = s: s + "," + cfg.userBaseDN; - description = lib.mdDoc '' - The DN of the service user used by services. - The user base dn will be automatically appended. - ''; - }; - - domainComponent = lib.mkOption { - type = with lib.types; listOf str; - example = [ "example" "com" ]; - apply = dc: lib.removeSuffix "," (lib.concatMapStrings (x: "dc=${x},") dc); - description = lib.mdDoc '' - Domain component(s) (dc) represented as a list of strings. - - Each entry will be prefixed with `dc=` and all are concatinated with `,`, except the last one. - The example would be concatinated to `dc=example,dc=com` - ''; - }; - - domainName = lib.mkOption { - type = lib.types.str; - example = "auth.example.com"; - description = lib.mdDoc "The domain name to connect to the ldap server."; - }; - - givenNameField = lib.mkOption { - type = lib.types.str; - example = "givenName"; - description = lib.mdDoc "The attribute of the user object where to find its given name."; - }; - - groupFilter = lib.mkOption { - type = with lib.types; functionTo str; - example = lib.literalExpression ''group: "(&(objectclass=person)(isMemberOf=cn=''${group},''${config.security.ldap.roleBaseDN}"''; - description = lib.mdDoc "A function that returns a group filter that matches the first argument against the names of the groups the user is part of."; - }; - - mailField = lib.mkOption { - type = lib.types.str; - example = "mail"; - description = lib.mdDoc "The attribute of the user object where to find its email."; - }; - - port = lib.mkOption { - type = lib.types.port; - example = "636"; - description = lib.mdDoc "The port the ldap server listens on. Usually this is 389 for ldap and 636 for ldaps."; - }; - - roleBaseDN = lib.mkOption { - type = lib.types.str; - example = "ou=groups"; - apply = s: s + "," + cfg.domainComponent; - description = lib.mdDoc '' - The directory path where applications should search for users. - Domain component will be automatically appended. - ''; - }; - - roleField = lib.mkOption { - type = lib.types.str; - example = "cn"; - description = lib.mdDoc "The attribute where the user account is listed in a group."; - }; - - roleFilter = lib.mkOption { - type = lib.types.str; - example = "(&(objectclass=groupOfNames)(member=%s))"; - description = lib.mdDoc "Filter to get the groups of an user object."; - }; - - roleValue = lib.mkOption { - type = lib.types.str; - example = "dn"; - description = lib.mdDoc "The attribute of the user object where to find its distinguished name."; - }; - - searchUID = lib.mkOption { - type = lib.types.str; - example = "search"; - description = lib.mdDoc "The uid of the service user used by services, often referred as search user."; - }; - - searchFilterWithGroupFilter = lib.mkOption { - type = with lib.types; functionTo (functionTo str); - example = lib.literalExpression ''userFilterGroup: userFilter: if (userFilterGroup != null) then "(&''${config.security.ldap.groupFilter userFilterGroup})" else userFilter''; - description = lib.mdDoc '' - A function that returns a search filter that may include a group filter. - The first argument may be the group that is filtered upon or null. - If set to null no additional filtering is done. If set the supplied filter is combined with the user filter. - The second argument must be the user filter including the applications placeholders or ideally the userFilter option. - ''; - }; - - sshPublicKeyField = lib.mkOption { - type = lib.types.str; - example = "sshPublicKey"; - description = lib.mdDoc "The attribute of the user object where to find its ssh public key."; - }; - - surnameField = lib.mkOption { - type = lib.types.str; - example = "sn"; - description = lib.mdDoc "The attribute of the user object where to find its surname."; - }; - - userBaseDN = lib.mkOption { - type = lib.types.str; - example = "ou=users"; - apply = s: s + "," + cfg.domainComponent; - description = lib.mdDoc '' - The directory path where applications should search for users. - Domain component will be automatically appended. - ''; - }; - - userField = lib.mkOption { - type = lib.types.str; - example = "uid"; - description = lib.mdDoc "The attribute of the user object where to find its username."; - }; - - userFilter = lib.mkOption { - type = with lib.types; functionTo str; - example = ''param: "(&(objectclass=person)(|(uid=''${param})(mail=''${param})))"''; - description = lib.mdDoc "A function that returns a user search filter that uses the first argument as the placeholder."; - }; - }; - }; - default = { }; - description = "LDAP options used in other services."; - }; -} diff --git a/modules/mastodon.nix b/modules/mastodon.nix deleted file mode 100644 index 58496b6..0000000 --- a/modules/mastodon.nix +++ /dev/null @@ -1,75 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -let - cfg = config.services.mastodon; - cfgl = cfg.ldap; - inherit (config.security) ldap; -in -{ - options.services.mastodon = { - ldap = { - enable = lib.mkEnableOption (lib.mdDoc "login only via LDAP"); - - userGroup = libS.ldap.mkUserGroupOption; - }; - - enableBirdUITheme = lib.mkEnableOption (lib.mdDoc "Bird UI Theme"); - }; - - config.services.mastodon = { - package = lib.mkIf cfg.enableBirdUITheme (pkgs.mastodon.overrideAttrs (_: with pkgs; let - src = pkgs.applyPatches { - src = fetchFromGitHub { - owner = "mstdn"; - repo = "Bird-UI-Theme-Admins"; - rev = "2f9921db746593f393c13f9b79e5b4c2e19b03bd"; - hash = "sha256-+7FUm5GNXRWyS9Oiow6kwX+pWh11wO3stm5iOTY3sYY="; - }; - - patches = [ - # fix compose box background - (fetchpatch { - url = "https://github.com/mstdn/Bird-UI-Theme-Admins/commit/d5a07d653680fba0ad8dd941405e2d0272ff9cd1.patch"; - hash = "sha256-1gnQNCSSuTE/pkPCf49lJQbmeLAbaiPD9u/q8KiFvlU="; - }) - ]; - }; - in { - mastodonModules = mastodon.mastodonModules.overrideAttrs (oldAttrs: { - pname = "mastodon-birdui-theme"; - - nativeBuildInputs = oldAttrs.nativeBuildInputs ++ [ - rsync - xorg.lndir - ]; - - postPatch = '' - rsync -r ${src}/mastodon/ . - ''; - }); - - postBuild = '' - cp ${src}/mastodon/config/themes.yml config/themes.yml - ''; - })); - - extraConfig = lib.mkIf cfgl.enable { - LDAP_ENABLED = "true"; - LDAP_BASE = ldap.userBaseDN; - LDAP_BIND_DN = ldap.bindDN; - LDAP_HOST = ldap.domainName; - LDAP_METHOD = "simple_tls"; - LDAP_PORT = toString ldap.port; - LDAP_UID = ldap.userField; - # convert .,- (space) in LDAP usernames to underscore, otherwise those users cannot log in - LDAP_UID_CONVERSION_ENABLED = "true"; - LDAP_SEARCH_FILTER = ldap.searchFilterWithGroupFilter cfgl.userGroup "(|(%{uid}=%{email})(%{mail}=%{email}))"; - }; - }; - - config.services.portunus.seedSettings.groups = lib.optional (cfgl.userGroup != null) { - long_name = "Mastodon Users"; - name = cfgl.userGroup; - permissions = { }; - }; -} diff --git a/modules/matrix.nix b/modules/matrix.nix deleted file mode 100644 index d487888..0000000 --- a/modules/matrix.nix +++ /dev/null @@ -1,158 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -let - cfg = config.services.matrix-synapse; - cfge = cfg.element-web; - inherit (config.security) ldap; -in -{ - options = { - services.matrix-synapse = { - addAdditionalOembedProvider = libS.mkOpinionatedOption "add additional oembed providers from oembed.com"; - - element-web = { - enable = lib.mkEnableOption (lib.mdDoc "the element-web client"); - - domain = lib.mkOption { - type = lib.types.str; - example = "element.example.org"; - description = lib.mdDoc "The domain that element-web will use."; - }; - - package = lib.mkPackageOptionMD pkgs "Element-Web" { - default = [ "element-web" ]; - }; - - enableConfigFeatures = libS.mkOpinionatedOption "enable most features available via config.json"; - }; - - ldap = { - enable = lib.mkEnableOption (lib.mdDoc "login via ldap"); - - userGroup = libS.ldap.mkUserGroupOption; - - bindPasswordFile = lib.mkOption { - type = lib.types.str; - example = "/var/lib/secrets/bind-password"; - description = lib.mdDoc "Path to a file containing the bind password."; - }; - }; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended and secure default settings"; - }; - }; - - config.environment.etc = lib.mkIf cfg.enable { - "matrix-synapse/config.yaml".source = cfg.configFile; - }; - - config.services.nginx = lib.mkIf cfge.enable { - enable = true; - virtualHosts."${cfge.domain}" = { - forceSSL = true; - enableACME = lib.mkDefault true; - root = (cfge.package.override { - conf = with config.services.matrix-synapse.settings; { - default_server_config."m.homeserver" = { - "base_url" = public_baseurl; - "server_name" = server_name; - }; - default_theme = "dark"; - room_directory.servers = [ server_name ]; - } // lib.optionalAttrs cfge.enableConfigFeatures { - features = { - # https://github.com/matrix-org/matrix-react-sdk/blob/develop/src/settings/Settings.tsx - # https://github.com/vector-im/element-web/blob/develop/docs/labs.md - feature_ask_to_join = true; - feature_bridge_state = true; - feature_exploring_public_spaces = true; - feature_jump_to_date = true; - feature_mjolnir = true; - feature_pinning = true; - feature_presence_in_room_list = true; - feature_report_to_moderators = true; - feature_qr_signin_reciprocate_show = true; - }; - show_labs_settings = true; - }; - }).overrideAttrs ({ postInstall ? "", ... }: { - # prevent 404 spam in nginx log - postInstall = postInstall + '' - ln -rs $out/config.json $out/config.${cfge.domain}.json - ''; - }); - }; - }; - - config.services.matrix-synapse = lib.mkMerge [ - { - settings = lib.mkIf cfge.enable rec { - email.client_base_url = web_client_location; - web_client_location = "https://${cfge.domain}"; - }; - } - - (lib.mkIf cfg.ldap.enable { - plugins = with config.services.matrix-synapse.package.plugins; [ - matrix-synapse-ldap3 - ]; - - settings.modules = [{ - module = "ldap_auth_provider.LdapAuthProviderModule"; - config = { - enabled = true; - mode = "search"; - uri = "ldaps://${ldap.domainName}:${toString ldap.port}"; - base = ldap.userBaseDN; - attributes = { - uid = ldap.userField; - mail = ldap.mailField; - name = ldap.givenNameField; - }; - bind_dn = ldap.bindDN; - bind_password_file = cfg.ldap.bindPasswordFile; - tls_options.validate = true; - } // lib.optionalAttrs (cfg.ldap.userGroup != null) { - filter = ldap.groupFilter cfg.ldap.userGroup; - }; - }]; - }) - - { - settings.oembed.additional_providers = lib.mkIf cfg.addAdditionalOembedProvider [ - ( - let - providers = pkgs.fetchurl { - url = "https://oembed.com/providers.json?2023-03-23"; - sha256 = "sha256-OdgBgkLbtNMn84ixKuC1gGzpyr+X+ORiLl6TAK3lYuQ="; - }; - in - pkgs.runCommand "providers.json" - { - nativeBuildInputs = with pkgs; [ jq ]; - } '' - # filter out entries that do not contain a schemes entry - # Error in configuration at 'oembed.additional_providers...endpoints.': 'schemes' is a required property - # and have none http protocols: Unsupported oEmbed scheme (spotify) for pattern: spotify:* - jq '[ ..|objects| select(.endpoints[0]|has("schemes")) | .endpoints[0].schemes=([ .endpoints[0].schemes[]|select(.|contains("http")) ]) ]' ${providers} > $out - '' - ) - ]; - } - - (lib.mkIf cfg.recommendedDefaults { - settings = { - federation_client_minimum_tls_version = "1.2"; - suppress_key_server_warning = true; - user_directory.prefer_local_users = true; - }; - withJemalloc = true; - }) - ]; - - config.services.portunus.seedSettings.groups = lib.optional (cfg.ldap.userGroup != null) { - long_name = "Matrix Users"; - name = cfg.ldap.userGroup; - permissions = { }; - }; -} diff --git a/modules/nextcloud.nix b/modules/nextcloud.nix deleted file mode 100644 index 01a753c..0000000 --- a/modules/nextcloud.nix +++ /dev/null @@ -1,218 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -let - cfg = config.services.nextcloud; -in -{ - options = { - services.nextcloud = { - recommendedDefaults = libS.mkOpinionatedOption "set recommended default settings"; - - configureImaginary = libS.mkOpinionatedOption "configure and use Imaginary for preview generation"; - - configureMemories = libS.mkOpinionatedOption "configure dependencies for Memories App"; - - configureMemoriesVaapi = lib.mkOption { - type = lib.types.bool; - default = config.hardware.intelGPU; - defaultText = "config.hardware.intelGPU"; - description = lib.mdDoc '' - Wether to configure Memories App to use an Intel iGPU for hardware acceleration. - ''; - }; - - configurePreviewSettings = lib.mkOption { - type = lib.types.bool; - default = cfg.configureImaginary; - defaultText = "config.services.nextcloud.configureImaginary"; - description = lib.mdDoc '' - Wether to configure the preview settings to be more optimised for real world usage. - By default this is enabled, when Imaginary is configured. - ''; - }; - - configureRecognize = libS.mkOpinionatedOption "configure dependencies for Recognize App"; - }; - }; - - config = lib.mkIf cfg.enable { - services = { - imaginary = lib.mkIf cfg.configureImaginary { - enable = true; - address = "127.0.0.1"; - settings.return-size = true; - }; - - nextcloud = { - # otherwise the Logging App does not function - logType = lib.mkIf cfg.recommendedDefaults "file"; - - phpOptions = lib.mkIf cfg.recommendedDefaults { - # https://docs.nextcloud.com/server/latest/admin_manual/installation/server_tuning.html#:~:text=opcache.jit%20%3D%201255%20opcache.jit_buffer_size%20%3D%20128m - "opcache.jit" = 1255; - "opcache.jit_buffer_size" = "128M"; - }; - - extraOptions = lib.mkMerge [ - (lib.mkIf cfg.configureImaginary { - enabledPreviewProviders = [ - # default from https://github.com/nextcloud/server/blob/master/config/config.sample.php#L1295-L1304 - ''OC\Preview\BMP'' - ''OC\Preview\GIF'' - ''OC\Preview\JPEG'' - ''OC\Preview\Krita'' - ''OC\Preview\MarkDown'' - ''OC\Preview\MP3'' - ''OC\Preview\OpenDocument'' - ''OC\Preview\PNG'' - ''OC\Preview\TXT'' - ''OC\Preview\XBitmap'' - # https://docs.nextcloud.com/server/24/admin_manual/installation/server_tuning.html#previews - ''OC\Preview\Imaginary'' - ]; - }) - - (lib.mkIf cfg.configureMemories { - enabledPreviewProviders = [ - # https://github.com/pulsejet/memories/wiki/File-Type-Support - # TODO: not sure if this should be under configurePreviewSettings instead or both - ''OC\Preview\Image'' # alias for png,jpeg,gif,bmp - ''OC\Preview\HEIC'' - ''OC\Preview\TIFF'' - ''OC\Preview\Movie'' - ]; - - "memories.exiftool" = "${pkgs.exiftool}/bin/exiftool"; - "memories.vod.vaapi" = lib.mkIf cfg.configureMemoriesVaapi true; - "memories.vod.ffmpeg" = "${pkgs.ffmpeg-headless}/bin/ffmpeg"; - "memories.vod.ffprobe" = "${pkgs.ffmpeg-headless}/bin/ffprobe"; - }) - - (lib.mkIf cfg.configurePreviewSettings { - enabledPreviewProviders = [ - # https://github.com/nextcloud/server/tree/master/lib/private/Preview - ''OC\Preview\Font'' - ''OC\Preview\PDF'' - ''OC\Preview\SVG'' - ''OC\Preview\WebP'' - ]; - - jpeg_quality = 60; - preview_max_filesize_image = 128; # MB - preview_max_memory = 512; # MB - preview_max_x = 2048; # px - preview_max_y = 2048; # px - }) - ]; - }; - - phpfpm.pools = lib.mkIf cfg.configurePreviewSettings { - # add user packages to phpfpm process PATHs, required to find ffmpeg for preview generator - # beginning taken from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/web-apps/nextcloud.nix#L985 - nextcloud.phpEnv.PATH = lib.mkForce "/run/wrappers/bin:/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin:/etc/profiles/per-user/nextcloud/bin"; - }; - }; - - systemd = { - services = { - nextcloud-cron = lib.mkIf cfg.configureMemories { - # required for memories - # see https://github.com/pulsejet/memories/blob/master/docs/troubleshooting.md#issues-with-nixos - path = with pkgs; [ perl ]; - # fix memories app being unpacked without the x-bit on binaries - # could be done in nextcloud-update-plugins but then manually updates would be broken until the next auto update - preStart = "${pkgs.coreutils}/bin/chmod +x /var/lib/nextcloud/store-apps/memories/bin-ext/*"; - }; - - nextcloud-cron-preview-generator = lib.mkIf cfg.configurePreviewSettings { - environment.NEXTCLOUD_CONFIG_DIR = "${config.services.nextcloud.datadir}/config"; - serviceConfig = { - ExecStart = "/run/current-system/sw/bin/nextcloud-occ preview:pre-generate"; - Type = "oneshot"; - User = "nextcloud"; - }; - }; - - nextcloud-preview-generator-setup = lib.mkIf cfg.configurePreviewSettings { - wantedBy = [ "multi-user.target" ]; - requires = [ "phpfpm-nextcloud.service" ]; - after = [ "phpfpm-nextcloud.service" ]; - environment.NEXTCLOUD_CONFIG_DIR = "${config.services.nextcloud.datadir}/config"; - script = - let - occ = "/run/current-system/sw/bin/nextcloud-occ"; - in - /* bash */ '' - # check with: - # for size in squareSizes widthSizes heightSizes; do echo -n "$size: "; nextcloud-occ config:app:get previewgenerator $size; done - - # extra commands run for preview generator: - # 32 icon file list - # 64 icon file list android app, photos app - # 96 nextcloud client VFS windows file preview - # 256 file app grid view, many requests - # 512 photos app tags - ${occ} config:app:set --value="32 64 96 256 512" previewgenerator squareSizes - - # 341 hover in maps app - # 1920 files/photos app when viewing picture - ${occ} config:app:set --value="341 1920" previewgenerator widthSizes - - # 256 hover in maps app - # 1080 files/photos app when viewing picture - ${occ} config:app:set --value="256 1080" previewgenerator heightSizes - ''; - serviceConfig = { - Type = "oneshot"; - User = "nextcloud"; - }; - }; - - nextcloud-setup = lib.mkIf cfg.configureRecognize { - script = /* bash */ '' - export PATH=$PATH:/etc/profiles/per-user/nextcloud/bin:/run/current-system/sw/bin - - if [[ ! -e /var/lib/nextcloud/store-apps/recognize/node_modules/@tensorflow/tfjs-node/lib/napi-v8/tfjs_binding.node ]]; then - if [[ -d /var/lib/nextcloud/store-apps/recognize/node_modules/ ]]; then - cd /var/lib/nextcloud/store-apps/recognize/node_modules/ - npm rebuild @tensorflow/tfjs-node --build-addon-from-source - fi - fi - ''; - }; - - phpfpm-nextcloud.serviceConfig = lib.mkIf cfg.configureMemoriesVaapi { - DeviceAllow = [ "/dev/dri/renderD128 rwm" ]; - PrivateDevices = lib.mkForce false; - }; - }; - - timers.nextcloud-cron-preview-generator = lib.mkIf cfg.configurePreviewSettings { - timerConfig = { - OnUnitActiveSec = "5m"; - Unit = "nextcloud-cron-preview-generator.service"; - }; - wantedBy = [ "timers.target" ]; - }; - }; - - users.users.nextcloud = { - extraGroups = lib.mkIf cfg.configureMemoriesVaapi [ - "render" # access /dev/dri/renderD128 - ]; - packages = with pkgs; - # generate video thumbnails with preview generator - lib.optional cfg.configurePreviewSettings ffmpeg-headless - # required for memories, duplicated with nextcloud-cron to better debug - ++ lib.optional cfg.configureMemories perl - # required for recognize app - ++ lib.optionals cfg.configureRecognize [ - gnumake # installation requirement - nodejs_16 # runtime and installation requirement - nodejs_16.pkgs.node-pre-gyp # installation requirement - python3 # requirement for node-pre-gyp otherwise fails with exit code 236 - util-linux # runtime requirement for taskset - ]; - }; - }; -} diff --git a/modules/nginx.nix b/modules/nginx.nix deleted file mode 100644 index 49d8904..0000000 --- a/modules/nginx.nix +++ /dev/null @@ -1,176 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -let - cfg = config.services.nginx; -in -{ - options.services.nginx = { - allCompression = libS.mkOpinionatedOption "set all recommended compression options"; - - default404Server = { - enable = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc '' - Wether to add a default server which always responds with 404. - This is useful when using a wildcard cname with a wildcard certitificate to not return the first server entry in the config on unknown subdomains - or to do the same for an old and not fully removed domain. - ''; - }; - - acmeHost = lib.mkOption { - type = lib.types.str; - description = lib.mdDoc '' - The acme host to use for the default 404 server. - ''; - }; - }; - - generateDhparams = libS.mkOpinionatedOption "generate more secure, 2048 bits dhparams replacing the default 1024 bits"; - - openFirewall = libS.mkOpinionatedOption "open the firewall port for the http (80) and https (443) default ports"; - - quic = { - enable = lib.mkEnableOption (lib.mdDoc "quic support in nginx"); - - bpf = libS.mkOpinionatedOption "configure nginx' bpf support which routes quic packets from the same source to the same worker"; - }; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended performance options not grouped into other settings"; - - resolverAddrFromNameserver = libS.mkOpinionatedOption "set resolver address to environment.nameservers"; - - rotateLogsFaster = libS.mkOpinionatedOption "keep logs only for 7 days and rotate them daily"; - - setHSTSHeader = libS.mkOpinionatedOption "add the HSTS header to all virtual hosts"; - - tcpFastOpen = libS.mkOpinionatedOption "enable tcp fast open"; - }; - - config = lib.mkIf cfg.enable { - assertions = [ - { - assertion = cfg.quic.enable && cfg.quic.bpf -> !lib.versionOlder cfg.package.version "1.25.0"; - message = "Setting services.nginx.quic.bpf to true requires nginx version 1.25.0 or newer, but currently \"${cfg.package.version}\" is used!"; - } - ]; - - boot.kernel.sysctl = lib.mkIf cfg.tcpFastOpen { - # enable tcp fastopen for outgoing and incoming connections - "net.ipv4.tcp_fastopen" = 3; - }; - - networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ 80 443 ]; - - nixpkgs.overlays = lib.mkIf cfg.tcpFastOpen [ - (final: prev: - let - configureFlags = [ "-DTCP_FASTOPEN=23" ]; - in - { - nginx = prev.nginx.override { inherit configureFlags; }; - nginxQuic = prev.nginxQuic.override { inherit configureFlags; }; - nginxStable = prev.nginxStable.override { inherit configureFlags; }; - nginxMainline = prev.nginxMainline.override { inherit configureFlags; }; - }) - ]; - - services = { - logrotate.settings.nginx = lib.mkIf cfg.rotateLogsFaster { - frequency = "daily"; - rotate = 7; - }; - - # NOTE: do not use mkMerge here to prevent infinite recursions - nginx = { - appendConfig = lib.optionalString (cfg.quic.enable && cfg.quic.bpf) /* nginx */ '' - quic_bpf on; - '' + lib.optionalString cfg.recommendedDefaults /* nginx */ '' - worker_processes auto; - worker_cpu_affinity auto; - ''; - - commonHttpConfig = lib.optionalString cfg.recommendedDefaults /* nginx */ '' - error_log syslog:server=unix:/dev/log; - '' + lib.optionalString cfg.quic.enable /* nginx */'' - quic_retry on; - '' + lib.optionalString cfg.recommendedZstdSettings /* nginx */ '' - # TODO: upstream this? - zstd_types application/x-nix-archive; - ''; - - commonServerConfig = lib.mkIf cfg.setHSTSHeader /* nginx */ '' - more_set_headers "Strict-Transport-Security: max-age=63072000; includeSubDomains; preload"; - ''; - - package = lib.mkIf cfg.quic.enable pkgs.nginxQuic; # based on pkgs.nginxMainline - - recommendedBrotliSettings = lib.mkIf cfg.allCompression true; - recommendedGzipSettings = lib.mkIf cfg.allCompression true; - recommendedOptimisation = lib.mkIf cfg.allCompression true; - recommendedProxySettings = lib.mkIf cfg.allCompression true; - recommendedTlsSettings = lib.mkIf cfg.allCompression true; - recommendedZstdSettings = lib.mkIf cfg.allCompression true; - - resolver.addresses = - let - isIPv6 = addr: builtins.match ".*:.*:.*" addr != null; - escapeIPv6 = addr: - if isIPv6 addr then - "[${addr}]" - else - addr; - in - lib.optionals (cfg.resolverAddrFromNameserver && config.networking.nameservers != [ ]) (map escapeIPv6 config.networking.nameservers); - sslDhparam = lib.mkIf cfg.generateDhparams config.security.dhparams.params.nginx.path; - - # NOTE: do not use mkMerge here to prevent infinite recursions - virtualHosts = - let - extraParameters = [ - # net.core.somaxconn is set to 4096 - # see https://www.nginx.com/blog/tuning-nginx/#:~:text=to%20a%20value-,greater%20than%20512,-%2C%20change%20the%20backlog - "backlog=1024" - - "deferred" - "fastopen=256" # requires nginx to be compiled with -DTCP_FASTOPEN=23 - ]; - in - lib.mkIf (cfg.recommendedDefaults || cfg.default404Server.enable || cfg.quic.enable) { - "_" = { - kTLS = lib.mkIf cfg.recommendedDefaults true; - reuseport = lib.mkIf (cfg.recommendedDefaults || cfg.quic.enable) true; - - default = lib.mkIf cfg.default404Server.enable true; - forceSSL = lib.mkIf cfg.default404Server.enable true; - useACMEHost = lib.mkIf cfg.default404Server.enable cfg.default404Server.acmeHost; - extraConfig = lib.mkIf cfg.default404Server.enable /* nginx */ '' - return 404; - ''; - - listen = lib.mkIf cfg.tcpFastOpen (lib.mkDefault [ - { addr = "0.0.0.0"; port = 80; inherit extraParameters; } - { addr = "0.0.0.0"; port = 443; ssl = true; inherit extraParameters; } - { addr = "[::]"; port = 80; inherit extraParameters; } - { addr = "[::]"; port = 443; ssl = true; inherit extraParameters; } - ]); - - quic = lib.mkIf cfg.quic.enable true; - }; - }; - }; - }; - - security.dhparams = lib.mkIf cfg.generateDhparams { - enable = cfg.generateDhparams; - params.nginx = { }; - }; - - systemd.services.nginx.serviceConfig = lib.mkIf (cfg.quic.enable && cfg.quic.bpf) { - # NOTE: CAP_BPF is included in CAP_SYS_ADMIN but it is not enough alone - AmbientCapabilities = [ "CAP_BPF" "CAP_NET_ADMIN" "CAP_SYS_ADMIN" ]; - CapabilityBoundingSet = [ "CAP_BPF" "CAP_NET_ADMIN" "CAP_SYS_ADMIN" ]; - SystemCallFilter = [ "bpf" ]; - }; - }; -} diff --git a/modules/nix.nix b/modules/nix.nix deleted file mode 100644 index 9c7fc71..0000000 --- a/modules/nix.nix +++ /dev/null @@ -1,91 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -let - cfg = config.nix; -in -{ - options.nix = { - deleteChannels = lib.mkEnableOption "" // { description = "Whether to delete all channels on a system switch."; }; - - deleteUserProfiles = lib.mkEnableOption "" // { description = "Whether to delete all user profiles on a system switch."; }; - - diffSystem = libS.mkOpinionatedOption "system closure diffing on updates"; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended default settings"; - - remoteBuilder = { - enable = lib.mkEnableOption "restricted nix remote builder"; - - sshPublicKeys = lib.mkOption { - description = "SSH public keys accepted by the remote build user."; - type = lib.types.listOf lib.types.str; - }; - - name = lib.mkOption { - description = "Name of the user used for remote building."; - type = lib.types.str; - readOnly = true; - default = "nix-remote-builder"; - }; - }; - }; - - config = { - # based on https://github.com/numtide/srvos/blob/main/nixos/roles/nix-remote-builder.nix - # and https://discourse.nixos.org/t/wrapper-to-restrict-builder-access-through-ssh-worth-upstreaming/25834 - nix.settings = { - builders-use-substitutes = lib.mkIf cfg.recommendedDefaults true; - connect-timeout = lib.mkIf cfg.recommendedDefaults 20; - experimental-features = lib.mkIf cfg.recommendedDefaults [ "nix-command" "flakes" ]; - trusted-users = lib.mkIf cfg.remoteBuilder.enable [ cfg.remoteBuilder.name ]; - }; - - users.users.${cfg.remoteBuilder.name} = lib.mkIf cfg.remoteBuilder.enable { - group = "nogroup"; - isNormalUser = true; - openssh.authorizedKeys.keys = map - (key: - let - wrapper-dispatch-ssh-nix = pkgs.writeShellScriptBin "wrapper-dispatch-ssh-nix" /* bash */ '' - case $SSH_ORIGINAL_COMMAND in - "nix-daemon --stdio") - exec ${config.nix.package}/bin/nix-daemon --stdio - ;; - "nix-store --serve --write") - exec ${config.nix.package}/bin/nix-store --serve --write - ;; - *) - echo "Access is only allowed for the nix remote builder" 1>&2 - exit 1 - esac - ''; - - in - "restrict,pty,command=\"${wrapper-dispatch-ssh-nix}/bin/wrapper-dispatch-ssh-nix\" ${key}" - ) - config.nix.remoteBuilder.sshPublicKeys; - }; - - system.activationScripts = { - deleteChannels = lib.mkIf cfg.deleteChannels '' - echo "Deleting all channels..." - rm -rf /root/.nix-channels /home/*/.nix-channels /nix/var/nix/profiles/per-user/*/channels* || true - ''; - - deleteUserProfiles = lib.mkIf cfg.deleteUserProfiles '' - echo "Deleting all user profiles..." - rm -rf /root/.nix-profile /home/*/.nix-profile /nix/var/nix/profiles/per-user/*/profile* || true - ''; - - diff-system = lib.mkIf cfg.diffSystem { - supportsDryActivation = true; - text = '' - if [[ -e /run/current-system && -e $systemConfig ]]; then - echo System package diff: - ${lib.getExe config.nix.package} --extra-experimental-features nix-command store diff-closures /run/current-system $systemConfig || true - fi - ''; - }; - }; - }; -} diff --git a/modules/openvpn.nix b/modules/openvpn.nix deleted file mode 100644 index 4f77041..0000000 --- a/modules/openvpn.nix +++ /dev/null @@ -1,9 +0,0 @@ - -{ config, lib, ... }: - -let - cfg = config.services.openvpn; -in -{ - # TODO: OpenVPN -} diff --git a/modules/portunus-remove-add-group.diff b/modules/portunus-remove-add-group.diff deleted file mode 100644 index e3c210a..0000000 --- a/modules/portunus-remove-add-group.diff +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/internal/frontend/core.go b/internal/frontend/core.go -index 5976377..7c67991 100644 ---- a/internal/frontend/core.go -+++ b/internal/frontend/core.go -@@ -43,8 +43,6 @@ func HTTPHandler(nexus core.Nexus, isBehindTLSProxy bool) http.Handler { - r.Methods("POST").Path(`/users/{uid}/delete`).Handler(postUserDeleteHandler(nexus)) - - r.Methods("GET").Path(`/groups`).Handler(getGroupsHandler(nexus)) -- r.Methods("GET").Path(`/groups/new`).Handler(getGroupsNewHandler(nexus)) -- r.Methods("POST").Path(`/groups/new`).Handler(postGroupsNewHandler(nexus)) - r.Methods("GET").Path(`/groups/{name}/edit`).Handler(getGroupEditHandler(nexus)) - r.Methods("POST").Path(`/groups/{name}/edit`).Handler(postGroupEditHandler(nexus)) - r.Methods("GET").Path(`/groups/{name}/delete`).Handler(getGroupDeleteHandler(nexus)) -diff --git a/internal/frontend/groups.go b/internal/frontend/groups.go -index 5ac6a75..ac59f4f 100644 ---- a/internal/frontend/groups.go -+++ b/internal/frontend/groups.go -@@ -38,7 +38,6 @@ func getGroupsHandler(n core.Nexus) http.Handler { - Members - Permissions granted - -- New group - - - diff --git a/modules/portunus.nix b/modules/portunus.nix deleted file mode 100644 index dca6c5a..0000000 --- a/modules/portunus.nix +++ /dev/null @@ -1,183 +0,0 @@ -{ config, lib, pkgs, ... }: - -let - cfg = config.services.portunus; - inherit (config.security) ldap; -in -{ - options.services.portunus = { - # TODO: how to automatically set this? - # maybe based on $service.ldap.enable && services.portunus.enable? - addToHosts = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc "Whether to add a hosts entry for the portunus domain pointing to externalIp"; - }; - - configureOAuth2Proxy = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc '' - Wether to configure OAuth2 Proxy with Portunus' Dex. - - Use `services.oauth2_proxy.nginx.virtualHosts` to configure the nginx virtual hosts that should require authentication. - ''; - }; - - internalIp4 = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - description = lib.mdDoc "Internal IPv4 of portunus instance. This is used in the addToHosts option."; - }; - - internalIp6 = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - description = lib.mdDoc "Internal IPv6 of portunus instance. This is used in the addToHosts option."; - }; - - ldapPreset = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc "Whether to set config.security.ldap to portunus specific settings."; - }; - - removeAddGroup = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc "When enabled, remove the function to add new Groups via the web ui, to enforce seeding usage."; - }; - - seedGroups = lib.mkOption { - type = lib.types.bool; - default = false; - description = lib.mdDoc "Wether to seed groups configured in services as not member managed groups."; - }; - - # TODO: upstream to nixos - seedSettings = lib.mkOption { - type = with lib.types; nullOr (attrsOf (listOf (attrsOf anything))); - default = null; - description = lib.mdDoc '' - Seed settings for users and grousp. - See upstream for format - ''; - }; - }; - - config = { - assertions = [ - { - assertion = cfg.configureOAuth2Proxy -> config.services.oauth2_proxy.keyFile != null; - message = '' - Setting services.portunus.configureOAuth2Proxy to true requires to set service.oauth2_proxy.keyFile - to a file that contains `OAUTH2_PROXY_CLIENT_SECRET` and `OAUTH2_PROXY_COOKIE_SECRET`. - ''; - } - ]; - - networking.hosts = lib.mkIf cfg.addToHosts { - ${cfg.internalIp4} = [ cfg.domain ]; - ${cfg.internalIp6} = [ cfg.domain ]; - }; - - nixpkgs.overlays = lib.mkIf cfg.enable [ - (final: prev: with final; { - dex-oidc = prev.dex-oidc.override { - buildGoModule = args: buildGoModule (args // { - patches = args.patches or [ ] ++ [ - # remember session - (fetchpatch { - url = "https://github.com/SuperSandro2000/dex/commit/d2fb6cdf8188e6973721ddac657a7c5d3daf6955.patch"; - hash = "sha256-PKC7jsNyFN28qFZ7SLYgnd0s09G2cb+vBeFvRzyyLGQ="; - }) - # Complain if the env set in SecretEnv cannot be found - (fetchpatch { - url = "https://github.com/dexidp/dex/commit/f25f72053c9282cfe22521cd508698a07dc5190f.patch"; - hash = "sha256-dyo+UPpceHxL3gcBQaGaDAHJqmysDJw051gMG1aeh5o="; - }) - ]; - - vendorHash = "sha256-YIi67pPIcVndIjWk94ckv6X4WLELUe/J/03e+XWIdHE="; - }); - }; - - portunus = (prev.portunus.override { buildGoModule = buildGo121Module; }).overrideAttrs ({ patches ? [ ], buildInputs ? [ ], ... }: let - version = "2.0.0-beta.2"; - in { - inherit version; - - # TODO: upstream - src = fetchFromGitHub { - owner = "majewsky"; - repo = "portunus"; - rev = "v${version}"; - hash = "sha256-1OU3bepvqriGCW1qDszPnUDJ6eqBzNTiBZ2J4KF4ynw="; - }; - - patches = patches - ++ lib.optional cfg.removeAddGroup ./portunus-remove-add-group.diff; - - # TODO: upstream - buildInputs = buildInputs ++ [ - libxcrypt-legacy - ]; - }); - }) - ]; - - services = let - callbackURL = "https://${cfg.domain}/oauth2/callback"; - clientID = "oauth2_proxy"; # - is not allowed in environment variables - in { - dex = { - enable = lib.mkIf cfg.configureOAuth2Proxy true; - # the user has no other option to accept this and all clients are internal anyway - settings.oauth2.skipApprovalScreen = true; - }; - - oauth2_proxy = lib.mkIf cfg.configureOAuth2Proxy { - enable = true; - inherit clientID; - nginx = { - inherit (config.services.portunus) domain; - }; - provider = "oidc"; - redirectURL = callbackURL; - reverseProxy = true; - upstream = "http://127.0.0.1:4181"; - extraConfig = { - oidc-issuer-url = config.services.dex.settings.issuer; - provider-display-name = "Portunus"; - }; - }; - - portunus = { - dex.oidcClients = lib.mkIf cfg.configureOAuth2Proxy [{ - inherit callbackURL; - id = clientID; - }]; - seedPath = pkgs.writeText "seed.json" (builtins.toJSON cfg.seedSettings); - }; - }; - - security.ldap = lib.mkIf cfg.ldapPreset { - domainName = cfg.domain; - givenNameField = "givenName"; - groupFilter = group: "(&(objectclass=person)(isMemberOf=cn=${group},${ldap.roleBaseDN}))"; - mailField = "mail"; - port = 636; - roleBaseDN = "ou=groups"; - roleField = "cn"; - roleFilter = "(&(objectclass=groupOfNames)(member=%s))"; - roleValue = "dn"; - searchFilterWithGroupFilter = userFilterGroup: userFilter: if (userFilterGroup != null) then "(&${ldap.groupFilter userFilterGroup}${userFilter})" else userFilter; - sshPublicKeyField = "sshPublicKey"; - searchUID = "search"; - surnameField = "sn"; - userField = "uid"; - userFilter = replaceStr: "(&(objectclass=person)(|(uid=${replaceStr})(mail=${replaceStr})))"; - userBaseDN = "ou=users"; - }; - }; -} diff --git a/modules/postgres.nix b/modules/postgres.nix deleted file mode 100644 index 17d860c..0000000 --- a/modules/postgres.nix +++ /dev/null @@ -1,96 +0,0 @@ -{ config, lib, libS, pkgs, ... }: - -# NOTE: requires https://github.com/NixOS/nixpkgs/pull/257503 because of new usage of extraPlugins - -let - cfg = config.services.postgresql; - cfgu = config.services.postgresql.upgrade; -in -{ - options.services.postgresql = { - upgrade = { - enable = libS.mkOpinionatedOption "install the upgrade-pg-cluster script to update postgres."; - - extraArgs = lib.mkOption { - type = with lib.types; listOf str; - default = [ "--link" "--jobs=$(nproc)" ]; - description = lib.mdDoc "Extra arguments to pass to pg_upgrade. See https://www.postgresql.org/docs/current/pgupgrade.html for doc."; - }; - - newPackage = (lib.mkPackageOptionMD pkgs "postgresql" { - default = [ "postgresql_16" ]; - }) // { - description = lib.mdDoc '' - The postgres package to which should be updated. - After running upgrade-pg-cluster this must be set to services.postgresql.package to complete the update. - ''; - }; - - stopServices = lib.mkOption { - type = with lib.types; listOf str; - default = [ ]; - example = [ "hedgedoc" "hydra" "nginx" ]; - description = lib.mdDoc "Systemd services to stop when upgrade is started."; - }; - }; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended default settings"; - }; - - config = lib.mkIf cfg.enable { - environment.systemPackages = lib.optional cfgu.enable ( - let - # conditions copied from nixos/modules/services/databases/postgresql.nix - newPackage = if cfg.enableJIT && !cfgu.newPackage.jitSupport then cfgu.newPackage.withJIT else cfg.newPackage; - newData = "/var/lib/postgresql/${cfgu.newPackage.psqlSchema}"; - newBin = "${if cfg.extraPlugins == [] then cfgu.newPackage else cfgu.newPackage.withPackages cfg.extraPlugins}/bin"; - - oldPackage = if cfg.enableJIT && !cfg.package.jitSupport then cfg.package.withJIT else cfg.package; - oldData = config.services.postgresql.dataDir; - oldBin = "${if cfg.extraPlugins == [] then oldPackage else oldPackage.withPackages cfg.extraPlugins}/bin"; - in - pkgs.writeScriptBin "upgrade-pg-cluster" /* bash */ '' - set -eu - - echo "Current version: ${cfg.package.version}" - echo "Update version: ${cfgu.newPackage.version}" - - if [[ ${cfgu.newPackage.version} == ${cfg.package.version} ]]; then - echo "There is no major postgres update available." - exit 2 - fi - - systemctl stop postgresql ${lib.concatStringsSep " " cfgu.stopServices} - - install -d -m 0700 -o postgres -g postgres "${newData}" - cd "${newData}" - sudo -u postgres "${newBin}/initdb" -D "${newData}" - - sudo -u postgres "${newBin}/pg_upgrade" \ - --old-datadir "${oldData}" --new-datadir "${newData}" \ - --old-bindir ${oldBin} --new-bindir ${newBin} \ - ${lib.concatStringsSep " " cfgu.extraArgs} \ - "$@" - - echo " - - - Run the following commands after setting: - services.postgresql.package = pkgs.postgresql_${lib.versions.major cfgu.newPackage.version} - sudo -u postgres vacuumdb --all --analyze-in-stages - ${newData}/delete_old_cluster.sh - " - '' - ); - - services = { - postgresql.enableJIT = lib.mkIf cfg.recommendedDefaults true; - - postgresqlBackup = lib.mkIf cfg.recommendedDefaults { - compression = "zstd"; - compressionLevel = 9; - pgdumpOptions = "--create --clean"; - }; - }; - }; -} diff --git a/modules/simd.nix b/modules/simd.nix deleted file mode 100644 index cd81630..0000000 --- a/modules/simd.nix +++ /dev/null @@ -1,27 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.simd; -in -{ - options.simd = { - enable = lib.mkEnableOption "optimized builds with simd instructions"; - arch = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - description = '' - Microarchitecture string for nixpkgs.hostPlatform.gcc.march and to generate system-features. - Can be determined with: ``nix shell nixpkgs#gcc -c gcc -march=native -Q --help=target | grep march`` - ''; - }; - }; - - config = { - nix.settings.system-features = lib.mkIf (cfg.arch != null) (libS.nix.gcc-system-features config.simd.arch); - - nixpkgs.hostPlatform = lib.mkIf cfg.enable { - gcc.arch = config.simd.arch; - inherit (config.nixpkgs) system; - }; - }; -} diff --git a/modules/slim.nix b/modules/slim.nix deleted file mode 100644 index c16f949..0000000 --- a/modules/slim.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.slim; -in -{ - options.slim = { - enable = libS.mkOpinionatedOption "disable some usual rarely used things to slim down the system"; - }; - - config = lib.mkIf cfg.enable { - documentation = { - # html docs and info are not required, man pages are enough - doc.enable = false; - info.enable = false; - }; - - environment.defaultPackages = lib.mkForce [ ]; - - # durring testing only 550K-650K of the tmpfs where used - security.wrapperDirSize = "10M"; - }; -} diff --git a/modules/ssh.nix b/modules/ssh.nix deleted file mode 100644 index 501eeeb..0000000 --- a/modules/ssh.nix +++ /dev/null @@ -1,66 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfgP = config.programs.ssh; - cfgS = config.services.openssh; -in -{ - options = { - programs.ssh = { - addPopularKnownHosts = libS.mkOpinionatedOption "add ssh public keys of popular websites to known_hosts"; - recommendedDefaults = libS.mkOpinionatedOption "set recommend and secure default settings"; - }; - - services.openssh = { - fixPermissions = libS.mkOpinionatedOption "fix host key permissions to prevent lock outs"; - }; - }; - - config = lib.mkIf cfgP.addPopularKnownHosts { - programs.ssh = { - extraConfig = lib.mkIf cfgP.recommendedDefaults '' - # hard complain about wrong knownHosts - StrictHostKeyChecking accept-new - # make automated host key rotation possible - UpdateHostKeys yes - # fetch host keys via DNS and trust them - VerifyHostKeyDNS yes - ''; - knownHosts = lib.mkMerge [ - (libS.mkPubKey "github.com" "ssh-rsa" "AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=") - (libS.mkPubKey "github.com" "ecdsa-sha2-nistp256" "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=") - (libS.mkPubKey "github.com" "ssh-ed25519" "AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl") - (libS.mkPubKey "gitlab.com" "ssh-rsa" "AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9") - (libS.mkPubKey "gitlab.com" "ecdsa-sha2-nistp256" "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBFSMqzJeV9rUzU4kWitGjeR4PWSa29SPqJ1fVkhtj3Hw9xjLVXVYrU9QlYWrOLXBpQ6KWjbjTDTdDkoohFzgbEY=") - (libS.mkPubKey "gitlab.com" "ssh-ed25519" "AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjquxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf") - (libS.mkPubKey "git.openwrt.org" "ssh-rsa" "AAAAB3NzaC1yc2EAAAABIwAAAQEAtnM1w/A1uRZqZuYHhw4ASOe9mr3J2qKAa9K9zR8jG+B+NQVtYlIBSkmCFyP6OuydCmoRZ5Gs1I9pl/hEyi7ieEi6g9yww/JbV322cw04Tli46enIYDG1bnSxF6Qt4aXqvPhcObI3z/1Z3XR6weS1fiLDzLvzq+w1gNM77xExD4Mh27LTPkdwOWjkGa5joNx3EQUC3rzwxUqE4fhOT2Ii93h8FSAUXY9C32jkJj9x7vfaJEsCacs6YTiUKKxyzEB+TvFZdUtGtoRThX7UVICUCD2th/r3UeSp8ItWPg/KqzSg2pRfWeYszlVoD59JZ6YCupSjjRqZddghQc94Hev7oQ==") - (libS.mkPubKey "git.openwrt.org" "ecdsa-sha2-nistp256" "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBASOHg+tghASiZF0ClxYb/HEhUcqnD43I86YatRZSUsXNWLEd8yOzjOJExDHHaKtmZtQ/jfEMmoYbCjdEDOYm5g=") - (libS.mkPubKey "git.openwrt.org" "ssh-ed25519" "AAAAC3NzaC1lZDI1NTE5AAAAIJZFpKQMaLM8bG9lAPfEpTBExrzuiTKMni7PgktmDbJe") - (libS.mkPubKey "git.sr.ht" "ssh-rsa" "AAAAB3NzaC1yc2EAAAADAQABAAABAQDZ+l/lvYmaeOAPeijHL8d4794Am0MOvmXPyvHTtrqvgmvCJB8pen/qkQX2S1fgl9VkMGSNxbp7NF7HmKgs5ajTGV9mB5A5zq+161lcp5+f1qmn3Dp1MWKp/AzejWXKW+dwPBd3kkudDBA1fa3uK6g1gK5nLw3qcuv/V4emX9zv3P2ZNlq9XRvBxGY2KzaCyCXVkL48RVTTJJnYbVdRuq8/jQkDRA8lHvGvKI+jqnljmZi2aIrK9OGT2gkCtfyTw2GvNDV6aZ0bEza7nDLU/I+xmByAOO79R1Uk4EYCvSc1WXDZqhiuO2sZRmVxa0pQSBDn1DB3rpvqPYW+UvKB3SOz") - (libS.mkPubKey "git.sr.ht" "ecdsa-sha2-nistp256" "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCj6y+cJlqK3BHZRLZuM+KP2zGPrh4H66DacfliU1E2DHAd1GGwF4g1jwu3L8gOZUTIvUptqWTkmglpYhFp4Iy4=") - (libS.mkPubKey "git.sr.ht" "ssh-ed25519" "AAAAC3NzaC1lZDI1NTE5AAAAIMZvRd4EtM7R+IHVMWmDkVU3VLQTSwQDSAvW0t2Tkj60") - ]; - }; - - systemd.tmpfiles.rules = lib.mkIf cfgS.fixPermissions [ - "d /etc 0755 root root -" - "d /etc/ssh 0755 root root -" - "f /etc/ssh/ssh_host_ed25519_key 0700 root root -" - "f /etc/ssh/ssh_host_ed25519_key.pub 0744 root root -" - "f /etc/ssh/ssh_host_rsa_key 0700 root root -" - "f /etc/ssh/ssh_host_rsa_key.pub 0744 root root -" - ]; - - services.openssh.banner = '' - Welcome to another - ░██╗░░░░░░░██╗░█████╗░██╗░░░██╗███████╗██╗░░░░░███████╗███╗░░██╗░██████╗ - ░██║░░██╗░░██║██╔══██╗██║░░░██║██╔════╝██║░░░░░██╔════╝████╗░██║██╔════╝ - ░╚██╗████╗██╔╝███████║╚██╗░██╔╝█████╗░░██║░░░░░█████╗░░██╔██╗██║╚█████╗░ - ░░████╔═████║░██╔══██║░╚████╔╝░██╔══╝░░██║░░░░░██╔══╝░░██║╚████║░╚═══██╗ - ░░╚██╔╝░╚██╔╝░██║░░██║░░╚██╔╝░░███████╗███████╗███████╗██║░╚███║██████╔╝ - ░░░╚═╝░░░╚═╝░░╚═╝░░╚═╝░░░╚═╝░░░╚══════╝╚══════╝╚══════╝╚═╝░░╚══╝╚═════╝░ - Server :o - - ''; - }; -} diff --git a/modules/tmux.nix b/modules/tmux.nix deleted file mode 100644 index 4f5c9c1..0000000 --- a/modules/tmux.nix +++ /dev/null @@ -1,31 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.programs.tmux; -in -{ - options = { - programs.tmux.recommendedDefaults = libS.mkOpinionatedOption "set recommended default settings"; - }; - - config = lib.mkIf cfg.recommendedDefaults { - programs.tmux = { - keyMode = "vi"; - shortcut = "Space"; - aggressiveResize = true; - baseIndex = 1; - clock24 = true; - escapeTime = 100; - terminal = "xterm-256color"; - extraConfig = '' - # focus events enabled for terminals that support them - set -g focus-events on - - # open new tab in PWD - bind '"' split-window -c "#{pane_current_path}" - bind % split-window -h -c "#{pane_current_path}" - bind c new-window -c "#{pane_current_path}" - ''; - }; - }; -} diff --git a/modules/vaultwarden.nix b/modules/vaultwarden.nix deleted file mode 100644 index 899f604..0000000 --- a/modules/vaultwarden.nix +++ /dev/null @@ -1,97 +0,0 @@ -{ config, lib, libS, ... }: - -let - cfg = config.services.vaultwarden; - usingPostgres = cfg.dbBackend == "postgresql"; -in -{ - options = { - services.vaultwarden = { - configureNginx = libS.mkOpinionatedOption "configure nginx for the configured domain"; - - domain = lib.mkOption { - type = with lib.types; nullOr str; - default = null; - description = lib.mdDoc '' - The domain under which vaultwarden will be reachable. - ''; - }; - - recommendedDefaults = libS.mkOpinionatedOption "set recommended default settings"; - }; - }; - - config = lib.mkIf cfg.enable { - assertions = [ { - assertion = cfg.configureNginx -> cfg.domain != null; - message = '' - Setting services.vaultwarden.configureNginx to true requires configuring services.vaultwarden.domain! - ''; - } ]; - - nixpkgs.overlays = lib.mkIf cfg.recommendedDefaults [ - (final: prev: { - vaultwarden = prev.vaultwarden.overrideAttrs ({ patches ? [], ... }: { - patches = patches ++ [ - # add eu region push support - (final.fetchpatch { - url = "https://github.com/dani-garcia/vaultwarden/pull/3752.diff"; - hash = "sha256-QWbuUotNss1TkIIW6c54Y7U7u2yLg2xHopEngtNawcc="; - }) - ]; - }); - }) - ]; - - services = { - nginx = lib.mkIf cfg.configureNginx { - upstreams.vaultwarden.servers."127.0.0.1:${toString config.services.vaultwarden.config.ROCKET_PORT}" = { }; - virtualHosts.${cfg.domain}.locations = { - "/".proxyPass = "http://vaultwarden"; - "/notifications/hub" = { - proxyPass = "http://vaultwarden"; - proxyWebsockets = true; - }; - }; - }; - - postgresql = lib.mkIf usingPostgres { - enable = true; - ensureDatabases = [ "vaultwarden" ]; - ensureUsers = [{ - name = "vaultwarden"; - ensureDBOwnership = true; - }]; - }; - - vaultwarden.config = lib.mkMerge [ - { - DATABASE_URL = lib.mkIf usingPostgres "postgresql:///vaultwarden?host=/run/postgresql"; - DOMAIN = lib.mkIf (cfg.domain != null) "https://${cfg.domain}"; - } - (lib.mkIf cfg.recommendedDefaults { - DATA_FOLDER = "/var/lib/vaultwarden"; # changes data directory - # TODO: change with 1.31.0 update - # ENABLE_WEBSOCKET = true; - LOG_LEVEL = "warn"; - PASSWORD_ITERATIONS = 600000; - ROCKET_ADDRESS = "127.0.0.1"; - ROCKET_PORT = lib.mkDefault 8222; - SIGNUPS_VERIFY = true; - TRASH_AUTO_DELETE_DAYS = 30; - WEBSOCKET_ADDRESS = "127.0.0.1"; - WEBSOCKET_ENABLED = true; - WEBSOCKET_PORT = lib.mkDefault 8223; - }) - ]; - }; - - systemd.services.vaultwarden = { - after = lib.mkIf usingPostgres [ "postgresql.service" ]; - requires = lib.mkIf usingPostgres [ "postgresql.service" ]; - serviceConfig = lib.mkIf cfg.recommendedDefaults { - StateDirectory = lib.mkForce "vaultwarden"; # modules defaults to bitwarden_rs - }; - }; - }; -} diff --git a/modules/zfs.nix b/modules/zfs.nix deleted file mode 100644 index 457913d..0000000 --- a/modules/zfs.nix +++ /dev/null @@ -1,34 +0,0 @@ -{ config, lib, libS, options, pkgs, ... }: - -let - cfg = config.boot.zfs; -in -{ - options = { - boot.zfs = { - recommendedDefaults = libS.mkOpinionatedOption "enable recommended ZFS settings"; - latestCompatibleKernel = libS.mkOpinionatedOption "use the latest ZFS compatible kernel"; - }; - }; - - config = lib.mkIf cfg.enabled { - boot.kernelPackages = - let - ver = config.boot.zfs.package.latestCompatibleLinuxPackages.kernel.version; - in - # 6.0 has a bug in the bind syscall and does not error correct when the port is already in use - # https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/7VPNMC77YC3SI5LFYKUA4B5MTFPLTLVB/ - # https://lore.kernel.org/stable/CAFsF8vL4CGFzWMb38_XviiEgxoKX0GYup=JiUFXUOmagdk9CRg@mail.gmail.com/ - lib.mkIf (cfg.latestCompatibleKernel && lib.versions.majorMinor ver != "6.0") (lib.mkDefault config.boot.zfs.package.latestCompatibleLinuxPackages); - - services.zfs = lib.mkIf cfg.recommendedDefaults { - autoScrub.enable = true; - trim.enable = true; - }; - - virtualisation.containers.storage.settings = lib.mkIf cfg.recommendedDefaults (lib.recursiveUpdate options.virtualisation.containers.storage.settings.default { - # fixes: Error: 'overlay' is not supported over zfs, a mount_program is required: backing file system is unsupported for this graph driver - storage.options.mount_program = "${pkgs.fuse-overlayfs}/bin/fuse-overlayfs"; - }); - }; -} diff --git a/systems/configuration.nix b/systems/configuration.nix index c7b750b..d1ce548 100644 --- a/systems/configuration.nix +++ b/systems/configuration.nix @@ -1,7 +1,5 @@ -{ pkgs, lib, config, ... }: -let -in { - +{ pkgs, ... }: +{ i18n = { defaultLocale = "en_US.utf8"; supportedLocales = [ @@ -10,7 +8,6 @@ in { ]; }; - networking.firewall.allowedTCPPorts = [ 22 ]; services = { @@ -26,13 +23,6 @@ in { }; }; - users.users.brain = { - isNormalUser = true; - description = "Administrator"; - extraGroups = [ "networkmanager" "wheel" ]; - shell = pkgs.zsh; - }; - nixpkgs.config.allowUnfree = true; programs = { @@ -180,7 +170,7 @@ in { options = "--delete-oder-than 14d"; }; - diff-system = true; + diffSystem = true; }; system = { diff --git a/systems/palatine-hill/configuration.nix b/systems/palatine-hill/configuration.nix index e47646d..c6e4baf 100644 --- a/systems/palatine-hill/configuration.nix +++ b/systems/palatine-hill/configuration.nix @@ -1,6 +1,5 @@ -{ pkgs, lib, config, ... }: -let -in { +{ pkgs, ... }: +{ time.timeZone = "America/New_York"; console.keyMap = "us"; diff --git a/users/alice/default.nix b/users/alice/default.nix index 2125303..b74829f 100644 --- a/users/alice/default.nix +++ b/users/alice/default.nix @@ -1,27 +1,8 @@ -{ - pkgs, - lib, - config, -}: let - pubKeys = import ./keys/default.nix; -in { - isNormalUser = true; - description = "AmethystAndroid"; - uid = 1000; - extraGroups = [ - "wheel" - "media" - (lib.mkIf config.networking.networkmanager.enable "networkmanager") - (lib.mkIf config.programs.adb.enable "adbusers") - (lib.mkIf config.programs.wireshark.enable "wireshark") - (lib.mkIf config.programs.virtualisation.docker.enable "docker") - "libvirtd" - "dialout" - "plugdev" - "uaccess" - ]; - shell = pkgs.fish; - openssh.authorizedKeys.keys = [ - (lib.mkIf (pubKeys ? ${config.networking.hostName}) pubKeys.${config.networking.hostName}) - ]; +{ pkgs, lib, config }: +import ../default.nix { + inherit pkgs lib config; + userName = "AmethystAndroid"; + pubKeys = { + palatine-hill = "ed25516-AAAAAAA"; + }; } \ No newline at end of file diff --git a/users/alice/keys/default.nix b/users/alice/keys/default.nix deleted file mode 100644 index 6de9970..0000000 --- a/users/alice/keys/default.nix +++ /dev/null @@ -1,3 +0,0 @@ -{ - palatine-hill = "ed25516-AAAAAAA"; -} \ No newline at end of file diff --git a/users/default.nix b/users/default.nix new file mode 100644 index 0000000..d25005c --- /dev/null +++ b/users/default.nix @@ -0,0 +1,21 @@ +{ lib, config, pkgs, userName, pubKeys }: +{ + isNormalUser = true; + uid = 1000; + extraGroups = [ + "wheel" + "media" + (lib.mkIf config.networking.networkmanager.enable "networkmanager") + (lib.mkIf config.programs.adb.enable "adbusers") + (lib.mkIf config.programs.wireshark.enable "wireshark") + (lib.mkIf config.programs.virtualisation.docker.enable "docker") + "libvirtd" + "dialout" + "plugdev" + "uaccess" + ]; + shell = pkgs.zsh; + openssh.authorizedKeys.keys = [ + (lib.mkIf (pubKeys ? ${config.networking.hostName}) pubKeys.${config.networking.hostName}) + ]; +} \ No newline at end of file diff --git a/users/user.nix b/users/user.nix deleted file mode 100644 index e69de29..0000000