diff options
Diffstat (limited to 'infra/libkookie/nixpkgs/nixos/modules/services')
147 files changed, 3329 insertions, 1312 deletions
diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/master.nix b/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/master.nix index c6b1b0cc0bd8..a3069c81c19a 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/master.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/master.nix @@ -45,7 +45,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = with pkgs; [ - utillinux # for dmesg + util-linux # for dmesg ]; serviceConfig = { ExecStart = "${pkgs.salt}/bin/salt-master"; @@ -59,5 +59,5 @@ in }; }; - meta.maintainers = with lib.maintainers; [ aneeshusa ]; + meta.maintainers = with lib.maintainers; [ Flakebi ]; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/minion.nix b/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/minion.nix index c8fa9461a209..ac124c570d8d 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/minion.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/admin/salt/minion.nix @@ -50,7 +50,7 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; path = with pkgs; [ - utillinux + util-linux ]; serviceConfig = { ExecStart = "${pkgs.salt}/bin/salt-minion"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/audio/jack.nix b/infra/libkookie/nixpkgs/nixos/modules/services/audio/jack.nix index ceff366d0bbb..bee97dbfc6b3 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/audio/jack.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/audio/jack.nix @@ -246,6 +246,9 @@ in { description = "JACK Audio Connection Kit"; serviceConfig = { User = "jackaudio"; + SupplementaryGroups = lib.optional + (config.hardware.pulseaudio.enable + && !config.hardware.pulseaudio.systemWide) "users"; ExecStart = "${cfg.jackd.package}/bin/jackd ${lib.escapeShellArgs cfg.jackd.extraOptions}"; LimitRTPRIO = 99; LimitMEMLOCK = "infinity"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/backup/syncoid.nix b/infra/libkookie/nixpkgs/nixos/modules/services/backup/syncoid.nix index fff119c2cf00..e72e3fa59cf9 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/backup/syncoid.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/backup/syncoid.nix @@ -4,6 +4,15 @@ with lib; let cfg = config.services.syncoid; + + # Extract pool names of local datasets (ones that don't contain "@") that + # have the specified type (either "source" or "target") + getPools = type: unique (map (d: head (builtins.match "([^/]+).*" d)) ( + # Filter local datasets + filter (d: !hasInfix "@" d) + # Get datasets of the specified type + (catAttrs type (attrValues cfg.commands)) + )); in { # Interface @@ -26,14 +35,25 @@ in { user = mkOption { type = types.str; - default = "root"; + default = "syncoid"; example = "backup"; description = '' - The user for the service. Sudo or ZFS privilege delegation must be - configured to use a user other than root. + The user for the service. ZFS privilege delegation will be + automatically configured for any local pools used by syncoid if this + option is set to a user other than root. The user will be given the + "hold" and "send" privileges on any pool that has datasets being sent + and the "create", "mount", "receive", and "rollback" privileges on + any pool that has datasets being received. ''; }; + group = mkOption { + type = types.str; + default = "syncoid"; + example = "backup"; + description = "The group for the service."; + }; + sshKey = mkOption { type = types.nullOr types.path; # Prevent key from being copied to store @@ -150,6 +170,18 @@ in { # Implementation config = mkIf cfg.enable { + users = { + users = mkIf (cfg.user == "syncoid") { + syncoid = { + group = cfg.group; + isSystemUser = true; + }; + }; + groups = mkIf (cfg.group == "syncoid") { + syncoid = {}; + }; + }; + systemd.services.syncoid = { description = "Syncoid ZFS synchronization service"; script = concatMapStringsSep "\n" (c: lib.escapeShellArgs @@ -160,10 +192,22 @@ in { ++ c.extraArgs ++ [ "--sendoptions" c.sendOptions "--recvoptions" c.recvOptions + "--no-privilege-elevation" c.source c.target ])) (attrValues cfg.commands); after = [ "zfs.target" ]; - serviceConfig.User = cfg.user; + serviceConfig = { + ExecStartPre = (map (pool: lib.escapeShellArgs [ + "+/run/booted-system/sw/bin/zfs" "allow" + cfg.user "hold,send" pool + ]) (getPools "source")) ++ + (map (pool: lib.escapeShellArgs [ + "+/run/booted-system/sw/bin/zfs" "allow" + cfg.user "create,mount,receive,rollback" pool + ]) (getPools "target")); + User = cfg.user; + Group = cfg.group; + }; startAt = cfg.interval; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/backup/tarsnap.nix b/infra/libkookie/nixpkgs/nixos/modules/services/backup/tarsnap.nix index 6d99a1efb613..e1200731c2ca 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/backup/tarsnap.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/backup/tarsnap.nix @@ -308,7 +308,7 @@ in requires = [ "network-online.target" ]; after = [ "network-online.target" ]; - path = with pkgs; [ iputils tarsnap utillinux ]; + path = with pkgs; [ iputils tarsnap util-linux ]; # In order for the persistent tarsnap timer to work reliably, we have to # make sure that the tarsnap server is reachable after systemd starts up @@ -355,7 +355,7 @@ in description = "Tarsnap restore '${name}'"; requires = [ "network-online.target" ]; - path = with pkgs; [ iputils tarsnap utillinux ]; + path = with pkgs; [ iputils tarsnap util-linux ]; script = let tarsnap = ''tarsnap --configfile "/etc/tarsnap/${name}.conf"''; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/cluster/k3s/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/cluster/k3s/default.nix index 2e8bf20a68fc..f0317fdbd160 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/cluster/k3s/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/cluster/k3s/default.nix @@ -76,6 +76,10 @@ in enable = mkDefault true; }; + # TODO: disable this once k3s supports cgroupsv2, either by docker + # supporting it, or their bundled containerd + systemd.enableUnifiedCgroupHierarchy = false; + systemd.services.k3s = { description = "k3s service"; after = mkIf cfg.docker [ "docker.service" ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix b/infra/libkookie/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix index c3d67552cc8c..2b6e45ba1b90 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/cluster/kubernetes/kubelet.nix @@ -241,7 +241,7 @@ in description = "Kubernetes Kubelet Service"; wantedBy = [ "kubernetes.target" ]; after = [ "network.target" "docker.service" "kube-apiserver.service" ]; - path = with pkgs; [ gitMinimal openssh docker utillinux iproute ethtool thin-provisioning-tools iptables socat ] ++ top.path; + path = with pkgs; [ gitMinimal openssh docker util-linux iproute ethtool thin-provisioning-tools iptables socat ] ++ top.path; preStart = '' ${concatMapStrings (img: '' echo "Seeding docker image: ${img}" diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/mom.nix b/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/mom.nix index 0c5f43cf3e6a..6747bd4b0d5a 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/mom.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/mom.nix @@ -32,7 +32,7 @@ in environment.systemPackages = [ pkgs.torque ]; systemd.services.torque-mom-init = { - path = with pkgs; [ torque utillinux procps inetutils ]; + path = with pkgs; [ torque util-linux procps inetutils ]; script = '' pbs_mkdirs -v aux diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/server.nix b/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/server.nix index 21c5a4f46724..8d923fc04d46 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/server.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/computing/torque/server.nix @@ -21,7 +21,7 @@ in environment.systemPackages = [ pkgs.torque ]; systemd.services.torque-server-init = { - path = with pkgs; [ torque utillinux procps inetutils ]; + path = with pkgs; [ torque util-linux procps inetutils ]; script = '' tmpsetup=$(mktemp -t torque-XXXX) diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix index 431555309cc9..c358a5db77c2 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/gitlab-runner.nix @@ -541,7 +541,7 @@ in jq moreutils remarshal - utillinux + util-linux cfg.package ] ++ cfg.extraPackages; reloadIfChanged = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix index d2e7e8e18f94..79d1ce580545 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hercules-ci-agent/default.nix @@ -25,19 +25,18 @@ in ]; config = mkIf cfg.enable { - systemd.services.hercules-ci-agent = { wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; path = [ config.nix.package ]; + startLimitBurst = 30 * 1000000; # practically infinite serviceConfig = { User = "hercules-ci-agent"; ExecStart = command; ExecStartPre = testCommand; Restart = "on-failure"; RestartSec = 120; - StartLimitBurst = 30 * 1000000; # practically infinite }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix index 502a5898a5de..252ca17006da 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/hydra/default.nix @@ -37,8 +37,6 @@ let haveLocalDB = cfg.dbi == localDB; - inherit (config.system) stateVersion; - hydra-package = let makeWrapperArgs = concatStringsSep " " (mapAttrsToList (key: value: "--set \"${key}\" \"${value}\"") hydraEnv); @@ -96,7 +94,8 @@ in package = mkOption { type = types.package; - defaultText = "pkgs.hydra"; + default = pkgs.hydra-unstable; + defaultText = "pkgs.hydra-unstable"; description = "The Hydra package."; }; @@ -225,34 +224,6 @@ in config = mkIf cfg.enable { - warnings = optional (cfg.package.migration or false) '' - You're currently deploying an older version of Hydra which is needed to - make some required database changes[1]. As soon as this is done, it's recommended - to run `hydra-backfill-ids` and set `services.hydra.package` to `pkgs.hydra-unstable` - after that. - - [1] https://github.com/NixOS/hydra/pull/711 - ''; - - services.hydra.package = with pkgs; - mkDefault ( - if pkgs ? hydra - then throw '' - The Hydra package doesn't exist anymore in `nixpkgs`! It probably exists - due to an overlay. To upgrade Hydra, you need to take two steps as some - bigger changes in the database schema were implemented recently[1]. You first - need to deploy `pkgs.hydra-migration`, run `hydra-backfill-ids` on the server - and then deploy `pkgs.hydra-unstable`. - - If you want to use `pkgs.hydra` from your overlay, please set `services.hydra.package` - explicitly to `pkgs.hydra` and make sure you know what you're doing. - - [1] https://github.com/NixOS/hydra/pull/711 - '' - else if versionOlder stateVersion "20.03" then hydra-migration - else hydra-unstable - ); - users.groups.hydra = { gid = config.ids.gids.hydra; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix index 1477c471f8ab..cdc3b4b5c58f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/continuous-integration/jenkins/default.nix @@ -86,8 +86,8 @@ in { }; packages = mkOption { - default = [ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ]; - defaultText = "[ pkgs.stdenv pkgs.git pkgs.jdk config.programs.ssh.package pkgs.nix ]"; + default = [ pkgs.stdenv pkgs.git pkgs.jdk11 config.programs.ssh.package pkgs.nix ]; + defaultText = "[ pkgs.stdenv pkgs.git pkgs.jdk11 config.programs.ssh.package pkgs.nix ]"; type = types.listOf types.package; description = '' Packages to add to PATH for the jenkins process. @@ -207,7 +207,7 @@ in { # For reference: https://wiki.jenkins.io/display/JENKINS/JenkinsLinuxStartupScript script = '' - ${pkgs.jdk}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \ + ${pkgs.jdk11}/bin/java ${concatStringsSep " " cfg.extraJavaOptions} -jar ${cfg.package}/webapps/jenkins.war --httpListenAddress=${cfg.listenAddress} \ --httpPort=${toString cfg.port} \ --prefix=${cfg.prefix} \ -Djava.awt.headless=true \ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/foundationdb.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/foundationdb.nix index 18727acc7c75..e22127403e91 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/foundationdb.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/databases/foundationdb.nix @@ -233,7 +233,7 @@ in type = types.str; default = "Check.Valid=1,Check.Unexpired=1"; description = '' - "Peer verification string". This may be used to adjust which TLS + "Peer verification string". This may be used to adjust which TLS client certificates a server will accept, as a form of user authorization; for example, it may only accept TLS clients who offer a certificate abiding by some locality or organization name. diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/openldap.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/openldap.nix index 7472538b887e..94a5c573768b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/openldap.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/databases/openldap.nix @@ -1,43 +1,121 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.openldap; + legacyOptions = [ "rootpwFile" "suffix" "dataDir" "rootdn" "rootpw" ]; openldap = cfg.package; - - dataFile = pkgs.writeText "ldap-contents.ldif" cfg.declarativeContents; - configFile = pkgs.writeText "slapd.conf" ((optionalString cfg.defaultSchemas '' - include ${openldap.out}/etc/schema/core.schema - include ${openldap.out}/etc/schema/cosine.schema - include ${openldap.out}/etc/schema/inetorgperson.schema - include ${openldap.out}/etc/schema/nis.schema - '') + '' - ${cfg.extraConfig} - database ${cfg.database} - suffix ${cfg.suffix} - rootdn ${cfg.rootdn} - ${if (cfg.rootpw != null) then '' - rootpw ${cfg.rootpw} - '' else '' - include ${cfg.rootpwFile} - ''} - directory ${cfg.dataDir} - ${cfg.extraDatabaseConfig} - ''); - configOpts = if cfg.configDir == null then "-f ${configFile}" - else "-F ${cfg.configDir}"; -in - -{ - - ###### interface - + configDir = if cfg.configDir != null then cfg.configDir else "/etc/openldap/slapd.d"; + + ldapValueType = let + # Can't do types.either with multiple non-overlapping submodules, so define our own + singleLdapValueType = lib.mkOptionType rec { + name = "LDAP"; + description = "LDAP value"; + check = x: lib.isString x || (lib.isAttrs x && (x ? path || x ? base64)); + merge = lib.mergeEqualOption; + }; + # We don't coerce to lists of single values, as some values must be unique + in types.either singleLdapValueType (types.listOf singleLdapValueType); + + ldapAttrsType = + let + options = { + attrs = mkOption { + type = types.attrsOf ldapValueType; + default = {}; + description = "Attributes of the parent entry."; + }; + children = mkOption { + # Hide the child attributes, to avoid infinite recursion in e.g. documentation + # Actual Nix evaluation is lazy, so this is not an issue there + type = let + hiddenOptions = lib.mapAttrs (name: attr: attr // { visible = false; }) options; + in types.attrsOf (types.submodule { options = hiddenOptions; }); + default = {}; + description = "Child entries of the current entry, with recursively the same structure."; + example = lib.literalExample '' + { + "cn=schema" = { + # The attribute used in the DN must be defined + attrs = { cn = "schema"; }; + children = { + # This entry's DN is expanded to "cn=foo,cn=schema" + "cn=foo" = { ... }; + }; + # These includes are inserted after "cn=schema", but before "cn=foo,cn=schema" + includes = [ ... ]; + }; + } + ''; + }; + includes = mkOption { + type = types.listOf types.path; + default = []; + description = '' + LDIF files to include after the parent's attributes but before its children. + ''; + }; + }; + in types.submodule { inherit options; }; + + valueToLdif = attr: values: let + listValues = if lib.isList values then values else lib.singleton values; + in map (value: + if lib.isAttrs value then + if lib.hasAttr "path" value + then "${attr}:< file://${value.path}" + else "${attr}:: ${value.base64}" + else "${attr}: ${lib.replaceStrings [ "\n" ] [ "\n " ] value}" + ) listValues; + + attrsToLdif = dn: { attrs, children, includes, ... }: ['' + dn: ${dn} + ${lib.concatStringsSep "\n" (lib.flatten (lib.mapAttrsToList valueToLdif attrs))} + ''] ++ (map (path: "include: file://${path}\n") includes) ++ ( + lib.flatten (lib.mapAttrsToList (name: value: attrsToLdif "${name},${dn}" value) children) + ); +in { + imports = let + deprecationNote = "This option is removed due to the deprecation of `slapd.conf` upstream. Please migrate to `services.openldap.settings`, see the release notes for advice with this process."; + mkDatabaseOption = old: new: + lib.mkChangedOptionModule [ "services" "openldap" old ] [ "services" "openldap" "settings" "children" ] + (config: let + database = lib.getAttrFromPath [ "services" "openldap" "database" ] config; + value = lib.getAttrFromPath [ "services" "openldap" old ] config; + in lib.setAttrByPath ([ "olcDatabase={1}${database}" "attrs" ] ++ new) value); + in [ + (lib.mkRemovedOptionModule [ "services" "openldap" "extraConfig" ] deprecationNote) + (lib.mkRemovedOptionModule [ "services" "openldap" "extraDatabaseConfig" ] deprecationNote) + + (lib.mkChangedOptionModule [ "services" "openldap" "logLevel" ] [ "services" "openldap" "settings" "attrs" "olcLogLevel" ] + (config: lib.splitString " " (lib.getAttrFromPath [ "services" "openldap" "logLevel" ] config))) + (lib.mkChangedOptionModule [ "services" "openldap" "defaultSchemas" ] [ "services" "openldap" "settings" "children" "cn=schema" "includes"] + (config: lib.optionals (lib.getAttrFromPath [ "services" "openldap" "defaultSchemas" ] config) ( + map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ]))) + + (lib.mkChangedOptionModule [ "services" "openldap" "database" ] [ "services" "openldap" "settings" "children" ] + (config: let + database = lib.getAttrFromPath [ "services" "openldap" "database" ] config; + in { + "olcDatabase={1}${database}".attrs = { + # objectClass is case-insensitive, so don't need to capitalize ${database} + objectClass = [ "olcdatabaseconfig" "olc${database}config" ]; + olcDatabase = "{1}${database}"; + olcDbDirectory = lib.mkDefault "/var/db/openldap"; + }; + "cn=schema".includes = lib.mkDefault ( + map (schema: "${openldap}/etc/schema/${schema}.ldif") [ "core" "cosine" "inetorgperson" "nis" ] + ); + })) + (mkDatabaseOption "rootpwFile" [ "olcRootPW" "path" ]) + (mkDatabaseOption "suffix" [ "olcSuffix" ]) + (mkDatabaseOption "dataDir" [ "olcDbDirectory" ]) + (mkDatabaseOption "rootdn" [ "olcRootDN" ]) + (mkDatabaseOption "rootpw" [ "olcRootPW" ]) + ]; options = { - services.openldap = { - enable = mkOption { type = types.bool; default = false; @@ -77,224 +155,170 @@ in example = [ "ldaps:///" ]; }; - dataDir = mkOption { - type = types.path; - default = "/var/db/openldap"; - description = "The database directory."; - }; - - defaultSchemas = mkOption { - type = types.bool; - default = true; - description = '' - Include the default schemas core, cosine, inetorgperson and nis. - This setting will be ignored if configDir is set. - ''; - }; - - database = mkOption { - type = types.str; - default = "mdb"; - description = '' - Database type to use for the LDAP. - This setting will be ignored if configDir is set. - ''; - }; - - suffix = mkOption { - type = types.str; - example = "dc=example,dc=org"; - description = '' - Specify the DN suffix of queries that will be passed to this backend - database. - This setting will be ignored if configDir is set. - ''; - }; - - rootdn = mkOption { - type = types.str; - example = "cn=admin,dc=example,dc=org"; - description = '' - Specify the distinguished name that is not subject to access control - or administrative limit restrictions for operations on this database. - This setting will be ignored if configDir is set. - ''; - }; - - rootpw = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Password for the root user. - This setting will be ignored if configDir is set. - Using this option will store the root password in plain text in the - world-readable nix store. To avoid this the <literal>rootpwFile</literal> can be used. + settings = mkOption { + type = ldapAttrsType; + description = "Configuration for OpenLDAP, in OLC format"; + example = lib.literalExample '' + { + attrs.olcLogLevel = [ "stats" ]; + children = { + "cn=schema".includes = [ + "\${pkgs.openldap}/etc/schema/core.ldif" + "\${pkgs.openldap}/etc/schema/cosine.ldif" + "\${pkgs.openldap}/etc/schema/inetorgperson.ldif" + ]; + "olcDatabase={-1}frontend" = { + attrs = { + objectClass = "olcDatabaseConfig"; + olcDatabase = "{-1}frontend"; + olcAccess = [ "{0}to * by dn.exact=uidNumber=0+gidNumber=0,cn=peercred,cn=external,cn=auth manage stop by * none stop" ]; + }; + }; + "olcDatabase={0}config" = { + attrs = { + objectClass = "olcDatabaseConfig"; + olcDatabase = "{0}config"; + olcAccess = [ "{0}to * by * none break" ]; + }; + }; + "olcDatabase={1}mdb" = { + attrs = { + objectClass = [ "olcDatabaseConfig" "olcMdbConfig" ]; + olcDatabase = "{1}mdb"; + olcDbDirectory = "/var/db/ldap"; + olcDbIndex = [ + "objectClass eq" + "cn pres,eq" + "uid pres,eq" + "sn pres,eq,subany" + ]; + olcSuffix = "dc=example,dc=com"; + olcAccess = [ "{0}to * by * read break" ]; + }; + }; + }; + }; ''; }; - rootpwFile = mkOption { - type = types.nullOr types.str; - default = null; - description = '' - Password file for the root user. - The file should contain the string <literal>rootpw</literal> followed by the password. - e.g.: <literal>rootpw mysecurepassword</literal> - ''; - }; - - logLevel = mkOption { - type = types.str; - default = "0"; - example = "acl trace"; - description = "The log level selector of slapd."; - }; - + # This option overrides settings configDir = mkOption { type = types.nullOr types.path; default = null; - description = "Use this optional config directory instead of using slapd.conf"; + description = '' + Use this config directory instead of generating one from the + <literal>settings</literal> option. Overrides all NixOS settings. If + you use this option,ensure `olcPidFile` is set to `/run/slapd/slapd.conf`. + ''; example = "/var/db/slapd.d"; }; - extraConfig = mkOption { - type = types.lines; - default = ""; - description = " - slapd.conf configuration - "; - example = literalExample '' - ''' - include ${openldap.out}/etc/schema/core.schema - include ${openldap.out}/etc/schema/cosine.schema - include ${openldap.out}/etc/schema/inetorgperson.schema - include ${openldap.out}/etc/schema/nis.schema - - database bdb - suffix dc=example,dc=org - rootdn cn=admin,dc=example,dc=org - # NOTE: change after first start - rootpw secret - directory /var/db/openldap - ''' - ''; - }; - declarativeContents = mkOption { - type = with types; nullOr lines; - default = null; + type = with types; attrsOf lines; + default = {}; description = '' - Declarative contents for the LDAP database, in LDIF format. + Declarative contents for the LDAP database, in LDIF format by suffix. - Note a few facts when using it. First, the database - <emphasis>must</emphasis> be stored in the directory defined by - <code>dataDir</code>. Second, all <code>dataDir</code> will be erased - when starting the LDAP server. Third, modifications to the database - are not prevented, they are just dropped on the next reboot of the - server. Finally, performance-wise the database and indexes are rebuilt - on each server startup, so this will slow down server startup, + All data will be erased when starting the LDAP server. Modifications + to the database are not prevented, they are just dropped on the next + reboot of the server. Performance-wise the database and indexes are + rebuilt on each server startup, so this will slow down server startup, especially with large databases. ''; - example = '' - dn: dc=example,dc=org - objectClass: domain - dc: example - - dn: ou=users,dc=example,dc=org - objectClass = organizationalUnit - ou: users - - # ... + example = lib.literalExample '' + { + "dc=example,dc=org" = ''' + dn= dn: dc=example,dc=org + objectClass: domain + dc: example + + dn: ou=users,dc=example,dc=org + objectClass = organizationalUnit + ou: users + + # ... + '''; + } ''; }; - - extraDatabaseConfig = mkOption { - type = types.lines; - default = ""; - description = '' - slapd.conf configuration after the database option. - This setting will be ignored if configDir is set. - ''; - example = '' - # Indices to maintain for this directory - # unique id so equality match only - index uid eq - # allows general searching on commonname, givenname and email - index cn,gn,mail eq,sub - # allows multiple variants on surname searching - index sn eq,sub - # sub above includes subintial,subany,subfinal - # optimise department searches - index ou eq - # if searches will include objectClass uncomment following - # index objectClass eq - # shows use of default index parameter - index default eq,sub - # indices missing - uses default eq,sub - index telephonenumber - - # other database parameters - # read more in slapd.conf reference section - cachesize 10000 - checkpoint 128 15 - ''; - }; - }; - - }; - - meta = { - maintainers = [ lib.maintainers.mic92 ]; }; - - ###### implementation + meta.maintainers = with lib.maintainters; [ mic92 kwohlfahrt ]; config = mkIf cfg.enable { - assertions = [ - { - assertion = cfg.configDir != null || cfg.rootpwFile != null || cfg.rootpw != null; - message = "services.openldap: Unless configDir is set, either rootpw or rootpwFile must be set"; - } - ]; - + assertions = map (opt: { + assertion = ((getAttr opt cfg) != "_mkMergedOptionModule") -> (cfg.database != "_mkMergedOptionModule"); + message = "Legacy OpenLDAP option `services.openldap.${opt}` requires `services.openldap.database` (use value \"mdb\" if unsure)"; + }) legacyOptions; environment.systemPackages = [ openldap ]; + # Literal attributes must always be set + services.openldap.settings = { + attrs = { + objectClass = "olcGlobal"; + cn = "config"; + olcPidFile = "/run/slapd/slapd.pid"; + }; + children."cn=schema".attrs = { + cn = "schema"; + objectClass = "olcSchemaConfig"; + }; + }; + systemd.services.openldap = { description = "LDAP server"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - preStart = '' + preStart = let + settingsFile = pkgs.writeText "config.ldif" (lib.concatStringsSep "\n" (attrsToLdif "cn=config" cfg.settings)); + + dbSettings = lib.filterAttrs (name: value: lib.hasPrefix "olcDatabase=" name) cfg.settings.children; + dataDirs = lib.mapAttrs' (name: value: lib.nameValuePair value.attrs.olcSuffix value.attrs.olcDbDirectory) + (lib.filterAttrs (_: value: value.attrs ? olcDbDirectory) dbSettings); + dataFiles = lib.mapAttrs (dn: contents: pkgs.writeText "${dn}.ldif" contents) cfg.declarativeContents; + mkLoadScript = dn: let + dataDir = lib.escapeShellArg (getAttr dn dataDirs); + in '' + rm -rf ${dataDir}/* + ${openldap}/bin/slapadd -F ${lib.escapeShellArg configDir} -b ${dn} -l ${getAttr dn dataFiles} + chown -R "${cfg.user}:${cfg.group}" ${dataDir} + ''; + in '' mkdir -p /run/slapd chown -R "${cfg.user}:${cfg.group}" /run/slapd - ${optionalString (cfg.declarativeContents != null) '' - rm -Rf "${cfg.dataDir}" - ''} - mkdir -p "${cfg.dataDir}" - ${optionalString (cfg.declarativeContents != null) '' - ${openldap.out}/bin/slapadd ${configOpts} -l ${dataFile} - ''} - chown -R "${cfg.user}:${cfg.group}" "${cfg.dataDir}" - ${openldap}/bin/slaptest ${configOpts} + mkdir -p ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)} + chown "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} ${lib.escapeShellArgs (lib.attrValues dataDirs)} + + ${lib.optionalString (cfg.configDir == null) ('' + rm -Rf ${configDir}/* + ${openldap}/bin/slapadd -F ${configDir} -bcn=config -l ${settingsFile} + '')} + chown -R "${cfg.user}:${cfg.group}" ${lib.escapeShellArg configDir} + + ${lib.concatStrings (map mkLoadScript (lib.attrNames cfg.declarativeContents))} + ${openldap}/bin/slaptest -u -F ${lib.escapeShellArg configDir} ''; - serviceConfig.ExecStart = - "${openldap.out}/libexec/slapd -d '${cfg.logLevel}' " + - "-u '${cfg.user}' -g '${cfg.group}' " + - "-h '${concatStringsSep " " cfg.urlList}' " + - "${configOpts}"; + serviceConfig = { + ExecStart = lib.escapeShellArgs ([ + "${openldap}/libexec/slapd" "-u" cfg.user "-g" cfg.group "-F" configDir + "-h" (lib.concatStringsSep " " cfg.urlList) + ]); + Type = "forking"; + PIDFile = cfg.settings.attrs.olcPidFile; + }; }; - users.users.openldap = - { name = cfg.user; + users.users = lib.optionalAttrs (cfg.user == "openldap") { + openldap = { group = cfg.group; - uid = config.ids.uids.openldap; - }; - - users.groups.openldap = - { name = cfg.group; - gid = config.ids.gids.openldap; + isSystemUser = true; }; + }; + users.groups = lib.optionalAttrs (cfg.group == "openldap") { + openldap = {}; + }; }; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/postgresql.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/postgresql.nix index 5056d50153f6..f582b0592774 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/postgresql.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/databases/postgresql.nix @@ -69,11 +69,16 @@ in type = types.lines; default = ""; description = '' - Defines how users authenticate themselves to the server. By - default, "trust" access to local users will always be granted - along with any other custom options. If you do not want this, - set this option using "lib.mkForce" to override this - behaviour. + Defines how users authenticate themselves to the server. See the + <link xlink:href="https://www.postgresql.org/docs/current/auth-pg-hba-conf.html"> + PostgreSQL documentation for pg_hba.conf</link> + for details on the expected format of this option. By default, + peer based authentication will be used for users connecting + via the Unix socket, and md5 password authentication will be + used for users connecting via TCP. Any added rules will be + inserted above the default rules. If you'd like to replace the + default rules entirely, you can use <function>lib.mkForce</function> in your + module. ''; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/redis.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/redis.nix index f1777854e141..6b8853ae390b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/redis.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/databases/redis.nix @@ -87,9 +87,12 @@ in bind = mkOption { type = with types; nullOr str; - default = null; # All interfaces - description = "The IP interface to bind to."; - example = "127.0.0.1"; + default = "127.0.0.1"; + description = '' + The IP interface to bind to. + <literal>null</literal> means "all interfaces". + ''; + example = "192.0.2.1"; }; unixSocket = mkOption { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak-cs.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak-cs.nix deleted file mode 100644 index fa6ac8863318..000000000000 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak-cs.nix +++ /dev/null @@ -1,202 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.riak-cs; - -in - -{ - - ###### interface - - options = { - - services.riak-cs = { - - enable = mkEnableOption "riak-cs"; - - package = mkOption { - type = types.package; - default = pkgs.riak-cs; - defaultText = "pkgs.riak-cs"; - example = literalExample "pkgs.riak-cs"; - description = '' - Riak package to use. - ''; - }; - - nodeName = mkOption { - type = types.str; - default = "riak-cs@127.0.0.1"; - description = '' - Name of the Erlang node. - ''; - }; - - anonymousUserCreation = mkOption { - type = types.bool; - default = false; - description = '' - Anonymous user creation. - ''; - }; - - riakHost = mkOption { - type = types.str; - default = "127.0.0.1:8087"; - description = '' - Name of riak hosting service. - ''; - }; - - listener = mkOption { - type = types.str; - default = "127.0.0.1:8080"; - description = '' - Name of Riak CS listening service. - ''; - }; - - stanchionHost = mkOption { - type = types.str; - default = "127.0.0.1:8085"; - description = '' - Name of stanchion hosting service. - ''; - }; - - stanchionSsl = mkOption { - type = types.bool; - default = true; - description = '' - Tell stanchion to use SSL. - ''; - }; - - distributedCookie = mkOption { - type = types.str; - default = "riak"; - description = '' - Cookie for distributed node communication. All nodes in the - same cluster should use the same cookie or they will not be able to - communicate. - ''; - }; - - dataDir = mkOption { - type = types.path; - default = "/var/db/riak-cs"; - description = '' - Data directory for Riak CS. - ''; - }; - - logDir = mkOption { - type = types.path; - default = "/var/log/riak-cs"; - description = '' - Log directory for Riak CS. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be appended to <filename>riak-cs.conf</filename>. - ''; - }; - - extraAdvancedConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be appended to <filename>advanced.config</filename>. - ''; - }; - }; - - }; - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ cfg.package ]; - environment.etc."riak-cs/riak-cs.conf".text = '' - nodename = ${cfg.nodeName} - distributed_cookie = ${cfg.distributedCookie} - - platform_log_dir = ${cfg.logDir} - - riak_host = ${cfg.riakHost} - listener = ${cfg.listener} - stanchion_host = ${cfg.stanchionHost} - - anonymous_user_creation = ${if cfg.anonymousUserCreation then "on" else "off"} - - ${cfg.extraConfig} - ''; - - environment.etc."riak-cs/advanced.config".text = '' - ${cfg.extraAdvancedConfig} - ''; - - users.users.riak-cs = { - name = "riak-cs"; - uid = config.ids.uids.riak-cs; - group = "riak"; - description = "Riak CS server user"; - }; - - systemd.services.riak-cs = { - description = "Riak CS Server"; - - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - path = [ - pkgs.utillinux # for `logger` - pkgs.bash - ]; - - environment.HOME = "${cfg.dataDir}"; - environment.RIAK_CS_DATA_DIR = "${cfg.dataDir}"; - environment.RIAK_CS_LOG_DIR = "${cfg.logDir}"; - environment.RIAK_CS_ETC_DIR = "/etc/riak"; - - preStart = '' - if ! test -e ${cfg.logDir}; then - mkdir -m 0755 -p ${cfg.logDir} - chown -R riak-cs ${cfg.logDir} - fi - - if ! test -e ${cfg.dataDir}; then - mkdir -m 0700 -p ${cfg.dataDir} - chown -R riak-cs ${cfg.dataDir} - fi - ''; - - serviceConfig = { - ExecStart = "${cfg.package}/bin/riak-cs console"; - ExecStop = "${cfg.package}/bin/riak-cs stop"; - StandardInput = "tty"; - User = "riak-cs"; - Group = "riak-cs"; - PermissionsStartOnly = true; - # Give Riak a decent amount of time to clean up. - TimeoutStopSec = 120; - LimitNOFILE = 65536; - }; - - unitConfig.RequiresMountsFor = [ - "${cfg.dataDir}" - "${cfg.logDir}" - "/etc/riak" - ]; - }; - }; -} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak.nix index 885215209bdf..657eeea87bf4 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/databases/riak.nix @@ -118,7 +118,7 @@ in after = [ "network.target" ]; path = [ - pkgs.utillinux # for `logger` + pkgs.util-linux # for `logger` pkgs.bash ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/stanchion.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/stanchion.nix deleted file mode 100644 index 97e55bc70c47..000000000000 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/stanchion.nix +++ /dev/null @@ -1,194 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - cfg = config.services.stanchion; - -in - -{ - - ###### interface - - options = { - - services.stanchion = { - - enable = mkEnableOption "stanchion"; - - package = mkOption { - type = types.package; - default = pkgs.stanchion; - defaultText = "pkgs.stanchion"; - example = literalExample "pkgs.stanchion"; - description = '' - Stanchion package to use. - ''; - }; - - nodeName = mkOption { - type = types.str; - default = "stanchion@127.0.0.1"; - description = '' - Name of the Erlang node. - ''; - }; - - adminKey = mkOption { - type = types.str; - default = ""; - description = '' - Name of admin user. - ''; - }; - - adminSecret = mkOption { - type = types.str; - default = ""; - description = '' - Name of admin secret - ''; - }; - - riakHost = mkOption { - type = types.str; - default = "127.0.0.1:8087"; - description = '' - Name of riak hosting service. - ''; - }; - - listener = mkOption { - type = types.str; - default = "127.0.0.1:8085"; - description = '' - Name of Riak CS listening service. - ''; - }; - - stanchionHost = mkOption { - type = types.str; - default = "127.0.0.1:8085"; - description = '' - Name of stanchion hosting service. - ''; - }; - - distributedCookie = mkOption { - type = types.str; - default = "riak"; - description = '' - Cookie for distributed node communication. All nodes in the - same cluster should use the same cookie or they will not be able to - communicate. - ''; - }; - - dataDir = mkOption { - type = types.path; - default = "/var/db/stanchion"; - description = '' - Data directory for Stanchion. - ''; - }; - - logDir = mkOption { - type = types.path; - default = "/var/log/stanchion"; - description = '' - Log directory for Stanchion. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional text to be appended to <filename>stanchion.conf</filename>. - ''; - }; - }; - }; - - ###### implementation - - config = mkIf cfg.enable { - - environment.systemPackages = [ cfg.package ]; - - environment.etc."stanchion/advanced.config".text = '' - [{stanchion, []}]. - ''; - - environment.etc."stanchion/stanchion.conf".text = '' - listener = ${cfg.listener} - - riak_host = ${cfg.riakHost} - - ${optionalString (cfg.adminKey == "") "#"} admin.key=${optionalString (cfg.adminKey != "") cfg.adminKey} - ${optionalString (cfg.adminSecret == "") "#"} admin.secret=${optionalString (cfg.adminSecret != "") cfg.adminSecret} - - platform_bin_dir = ${pkgs.stanchion}/bin - platform_data_dir = ${cfg.dataDir} - platform_etc_dir = /etc/stanchion - platform_lib_dir = ${pkgs.stanchion}/lib - platform_log_dir = ${cfg.logDir} - - nodename = ${cfg.nodeName} - - distributed_cookie = ${cfg.distributedCookie} - - ${cfg.extraConfig} - ''; - - users.users.stanchion = { - name = "stanchion"; - uid = config.ids.uids.stanchion; - group = "stanchion"; - description = "Stanchion server user"; - }; - - users.groups.stanchion.gid = config.ids.gids.stanchion; - - systemd.tmpfiles.rules = [ - "d '${cfg.logDir}' - stanchion stanchion --" - "d '${cfg.dataDir}' 0700 stanchion stanchion --" - ]; - - systemd.services.stanchion = { - description = "Stanchion Server"; - - wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; - - path = [ - pkgs.utillinux # for `logger` - pkgs.bash - ]; - - environment.HOME = "${cfg.dataDir}"; - environment.STANCHION_DATA_DIR = "${cfg.dataDir}"; - environment.STANCHION_LOG_DIR = "${cfg.logDir}"; - environment.STANCHION_ETC_DIR = "/etc/stanchion"; - - serviceConfig = { - ExecStart = "${cfg.package}/bin/stanchion console"; - ExecStop = "${cfg.package}/bin/stanchion stop"; - StandardInput = "tty"; - User = "stanchion"; - Group = "stanchion"; - # Give Stanchion a decent amount of time to clean up. - TimeoutStopSec = 120; - LimitNOFILE = 65536; - }; - - unitConfig.RequiresMountsFor = [ - "${cfg.dataDir}" - "${cfg.logDir}" - "/etc/stanchion" - ]; - }; - }; -} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/databases/victoriametrics.nix b/infra/libkookie/nixpkgs/nixos/modules/services/databases/victoriametrics.nix index 0af5d2adf372..5b09115bb2fb 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/databases/victoriametrics.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/databases/victoriametrics.nix @@ -40,10 +40,10 @@ let cfg = config.services.victoriametrics; in systemd.services.victoriametrics = { description = "VictoriaMetrics time series database"; after = [ "network.target" ]; + startLimitBurst = 5; serviceConfig = { Restart = "on-failure"; RestartSec = 1; - StartLimitBurst = 5; StateDirectory = "victoriametrics"; DynamicUser = true; ExecStart = '' diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/flatpak.nix b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/flatpak.nix index 7da92cc9f264..d0f6b66328a4 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/flatpak.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/flatpak.nix @@ -15,6 +15,18 @@ in { options = { services.flatpak = { enable = mkEnableOption "flatpak"; + + guiPackages = mkOption { + internal = true; + type = types.listOf types.package; + default = []; + example = literalExample "[ pkgs.gnome3.gnome-software ]"; + description = '' + Packages that provide an interface for flatpak + (like gnome-software) that will be automatically available + to all users when flatpak is enabled. + ''; + }; }; }; @@ -28,7 +40,7 @@ in { } ]; - environment.systemPackages = [ pkgs.flatpak ]; + environment.systemPackages = [ pkgs.flatpak ] ++ cfg.guiPackages; services.dbus.packages = [ pkgs.flatpak ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/pipewire.nix b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/pipewire.nix index 5aee59cfdcce..0ef988d9e69f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/pipewire.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/pipewire.nix @@ -5,8 +5,18 @@ with lib; let cfg = config.services.pipewire; - packages = with pkgs; [ pipewire ]; + enable32BitAlsaPlugins = cfg.alsa.support32Bit + && pkgs.stdenv.isx86_64 + && pkgs.pkgsi686Linux.pipewire != null; + # The package doesn't output to $out/lib/pipewire directly so that the + # overlays can use the outputs to replace the originals in FHS environments. + # + # This doesn't work in general because of missing development information. + jack-libs = pkgs.runCommand "jack-libs" {} '' + mkdir -p "$out/lib" + ln -s "${cfg.package.jack}/lib" "$out/lib/pipewire" + ''; in { meta = { @@ -18,6 +28,16 @@ in { services.pipewire = { enable = mkEnableOption "pipewire service"; + package = mkOption { + type = types.package; + default = pkgs.pipewire; + defaultText = "pkgs.pipewire"; + example = literalExample "pkgs.pipewire"; + description = '' + The pipewire derivation to use. + ''; + }; + socketActivation = mkOption { default = true; type = types.bool; @@ -25,17 +45,139 @@ in { Automatically run pipewire when connections are made to the pipewire socket. ''; }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Literal string to append to /etc/pipewire/pipewire.conf. + ''; + }; + + sessionManager = mkOption { + type = types.nullOr types.string; + default = null; + example = literalExample ''"''${pipewire}/bin/pipewire-media-session"''; + description = '' + Path to the pipewire session manager executable. + ''; + }; + + sessionManagerArguments = mkOption { + type = types.listOf types.string; + default = []; + example = literalExample ''[ "-p" "bluez5.msbc-support=true" ]''; + description = '' + Arguments passed to the pipewire session manager. + ''; + }; + + alsa = { + enable = mkEnableOption "ALSA support"; + support32Bit = mkEnableOption "32-bit ALSA support on 64-bit systems"; + }; + + jack = { + enable = mkEnableOption "JACK audio emulation"; + }; + + pulse = { + enable = mkEnableOption "PulseAudio server emulation"; + }; }; }; ###### implementation config = mkIf cfg.enable { - environment.systemPackages = packages; + assertions = [ + { + assertion = cfg.pulse.enable -> !config.hardware.pulseaudio.enable; + message = "PipeWire based PulseAudio server emulation replaces PulseAudio"; + } + { + assertion = cfg.jack.enable -> !config.services.jack.jackd.enable; + message = "PipeWire based JACK emulation doesn't use the JACK service"; + } + ]; + + services.pipewire.sessionManager = mkDefault "${cfg.package}/bin/pipewire-media-session"; + + environment.systemPackages = [ cfg.package ] + ++ lib.optional cfg.jack.enable jack-libs; - systemd.packages = packages; + systemd.packages = [ cfg.package ] + ++ lib.optional cfg.pulse.enable cfg.package.pulse; + # PipeWire depends on DBUS but doesn't list it. Without this booting + # into a terminal results in the service crashing with an error. systemd.user.sockets.pipewire.wantedBy = lib.mkIf cfg.socketActivation [ "sockets.target" ]; - }; + systemd.user.sockets.pipewire-pulse.wantedBy = lib.mkIf (cfg.socketActivation && cfg.pulse.enable) ["sockets.target"]; + systemd.user.services.pipewire.bindsTo = [ "dbus.service" ]; + services.udev.packages = [ cfg.package ]; + + # If any paths are updated here they must also be updated in the package test. + environment.etc."alsa/conf.d/49-pipewire-modules.conf" = mkIf cfg.alsa.enable { + text = '' + pcm_type.pipewire { + libs.native = ${cfg.package.lib}/lib/alsa-lib/libasound_module_pcm_pipewire.so ; + ${optionalString enable32BitAlsaPlugins + "libs.32Bit = ${pkgs.pkgsi686Linux.pipewire.lib}/lib/alsa-lib/libasound_module_pcm_pipewire.so ;"} + } + ctl_type.pipewire { + libs.native = ${cfg.package.lib}/lib/alsa-lib/libasound_module_ctl_pipewire.so ; + ${optionalString enable32BitAlsaPlugins + "libs.32Bit = ${pkgs.pkgsi686Linux.pipewire.lib}/lib/alsa-lib/libasound_module_ctl_pipewire.so ;"} + } + ''; + }; + environment.etc."alsa/conf.d/50-pipewire.conf" = mkIf cfg.alsa.enable { + source = "${cfg.package}/share/alsa/alsa.conf.d/50-pipewire.conf"; + }; + environment.etc."alsa/conf.d/99-pipewire-default.conf" = mkIf cfg.alsa.enable { + source = "${cfg.package}/share/alsa/alsa.conf.d/99-pipewire-default.conf"; + }; + environment.sessionVariables.LD_LIBRARY_PATH = + lib.optional cfg.jack.enable "/run/current-system/sw/lib/pipewire"; + + environment.etc."pipewire/pipewire.conf" = { + # Adapted from src/daemon/pipewire.conf.in + text = '' + set-prop link.max-buffers 16 # version < 3 clients can't handle more + + add-spa-lib audio.convert* audioconvert/libspa-audioconvert + add-spa-lib api.alsa.* alsa/libspa-alsa + add-spa-lib api.v4l2.* v4l2/libspa-v4l2 + add-spa-lib api.libcamera.* libcamera/libspa-libcamera + add-spa-lib api.bluez5.* bluez5/libspa-bluez5 + add-spa-lib api.vulkan.* vulkan/libspa-vulkan + add-spa-lib api.jack.* jack/libspa-jack + add-spa-lib support.* support/libspa-support + + load-module libpipewire-module-rtkit # rt.prio=20 rt.time.soft=200000 rt.time.hard=200000 + load-module libpipewire-module-protocol-native + load-module libpipewire-module-profiler + load-module libpipewire-module-metadata + load-module libpipewire-module-spa-device-factory + load-module libpipewire-module-spa-node-factory + load-module libpipewire-module-client-node + load-module libpipewire-module-client-device + load-module libpipewire-module-portal + load-module libpipewire-module-access + load-module libpipewire-module-adapter + load-module libpipewire-module-link-factory + load-module libpipewire-module-session-manager + + create-object spa-node-factory factory.name=support.node.driver node.name=Dummy priority.driver=8000 + exec ${cfg.sessionManager} ${lib.concatStringsSep " " cfg.sessionManagerArguments} + + ${cfg.extraConfig} + ''; + }; + + environment.etc."pipewire/media-session.d/with-alsa" = mkIf cfg.alsa.enable { text = ""; }; + environment.etc."pipewire/media-session.d/with-pulseaudio" = mkIf cfg.pulse.enable { text = ""; }; + environment.etc."pipewire/media-session.d/with-jack" = mkIf cfg.jack.enable { text = ""; }; + }; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix index a8ac22ac1276..6206295272fc 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/profile-sync-daemon.nix @@ -36,7 +36,7 @@ in { description = "Profile Sync daemon"; wants = [ "psd-resync.service" ]; wantedBy = [ "default.target" ]; - path = with pkgs; [ rsync kmod gawk nettools utillinux profile-sync-daemon ]; + path = with pkgs; [ rsync kmod gawk nettools util-linux profile-sync-daemon ]; unitConfig = { RequiresMountsFor = [ "/home/" ]; }; @@ -55,7 +55,7 @@ in { wants = [ "psd-resync.timer" ]; partOf = [ "psd.service" ]; wantedBy = [ "default.target" ]; - path = with pkgs; [ rsync kmod gawk nettools utillinux profile-sync-daemon ]; + path = with pkgs; [ rsync kmod gawk nettools util-linux profile-sync-daemon ]; serviceConfig = { Type = "oneshot"; ExecStart = "${pkgs.profile-sync-daemon}/bin/profile-sync-daemon resync"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/telepathy.nix b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/telepathy.nix index 34596bf78184..8c50d860e5bb 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/desktops/telepathy.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/desktops/telepathy.nix @@ -38,6 +38,11 @@ with lib; services.dbus.packages = [ pkgs.telepathy-mission-control ]; + # Enable runtime optional telepathy in gnome-shell + services.xserver.desktopManager.gnome3.sessionPath = with pkgs; [ + telepathy-glib + telepathy-logger + ]; }; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/development/hoogle.nix b/infra/libkookie/nixpkgs/nixos/modules/services/development/hoogle.nix index 1a98f005602a..cbf13f027de2 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/development/hoogle.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/development/hoogle.nix @@ -61,10 +61,8 @@ in { Restart = "always"; ExecStart = ''${hoogleEnv}/bin/hoogle server --local --port ${toString cfg.port} --home ${cfg.home}''; - User = "nobody"; - Group = "nogroup"; + DynamicUser = true; - PrivateTmp = true; ProtectHome = true; RuntimeDirectory = "hoogle"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/games/factorio.nix b/infra/libkookie/nixpkgs/nixos/modules/services/games/factorio.nix index 4b2e1a3c07f0..73099ae33634 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/games/factorio.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/games/factorio.nix @@ -49,8 +49,13 @@ in default = 34197; description = '' The port to which the service should bind. - - This option will also open up the UDP port in the firewall configuration. + ''; + }; + openFirewall = mkOption { + type = types.bool; + default = false; + description = '' + Whether to automatically open the specified UDP port in the firewall. ''; }; saveName = mkOption { @@ -237,6 +242,6 @@ in }; }; - networking.firewall.allowedUDPPorts = [ cfg.port ]; + networking.firewall.allowedUDPPorts = if cfg.openFirewall then [ cfg.port ] else []; }; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/bluetooth.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/bluetooth.nix index dfa39e7f6024..6f5a6d3bf288 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/bluetooth.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/bluetooth.nix @@ -15,6 +15,8 @@ in { hardware.bluetooth = { enable = mkEnableOption "support for Bluetooth"; + hsphfpd.enable = mkEnableOption "support for hsphfpd[-prototype] implementation"; + powerOnBoot = mkOption { type = types.bool; default = true; @@ -72,7 +74,8 @@ in { }; }; - environment.systemPackages = [ bluez-bluetooth ]; + environment.systemPackages = [ bluez-bluetooth ] + ++ optionals cfg.hsphfpd.enable [ pkgs.hsphfpd ]; environment.etc."bluetooth/main.conf"= { source = pkgs.writeText "main.conf" @@ -80,19 +83,42 @@ in { }; services.udev.packages = [ bluez-bluetooth ]; - services.dbus.packages = [ bluez-bluetooth ]; + services.dbus.packages = [ bluez-bluetooth ] + ++ optionals cfg.hsphfpd.enable [ pkgs.hsphfpd ]; systemd.packages = [ bluez-bluetooth ]; systemd.services = { bluetooth = { wantedBy = [ "bluetooth.target" ]; aliases = [ "dbus-org.bluez.service" ]; + # restarting can leave people without a mouse/keyboard + unitConfig.X-RestartIfChanged = false; }; - }; + } + // (optionalAttrs cfg.hsphfpd.enable { + hsphfpd = { + after = [ "bluetooth.service" ]; + requires = [ "bluetooth.service" ]; + wantedBy = [ "multi-user.target" ]; + + description = "A prototype implementation used for connecting HSP/HFP Bluetooth devices"; + serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/hsphfpd.pl"; + }; + }) + ; systemd.user.services = { obex.aliases = [ "dbus-org.bluez.obex.service" ]; - }; + } + // (optionalAttrs cfg.hsphfpd.enable { + telephony_client = { + wantedBy = [ "default.target"]; + + description = "telephony_client for hsphfpd"; + serviceConfig.ExecStart = "${pkgs.hsphfpd}/bin/telephony_client.pl"; + }; + }) + ; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/fwupd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/fwupd.nix index 222ac8e487eb..51eca19dca32 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/fwupd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/fwupd.nix @@ -11,8 +11,8 @@ let "fwupd/daemon.conf" = { source = pkgs.writeText "daemon.conf" '' [fwupd] - BlacklistDevices=${lib.concatStringsSep ";" cfg.blacklistDevices} - BlacklistPlugins=${lib.concatStringsSep ";" cfg.blacklistPlugins} + DisabledDevices=${lib.concatStringsSep ";" cfg.disabledDevices} + DisabledPlugins=${lib.concatStringsSep ";" cfg.disabledPlugins} ''; }; "fwupd/uefi.conf" = { @@ -59,21 +59,21 @@ in { ''; }; - blacklistDevices = mkOption { + disabledDevices = mkOption { type = types.listOf types.str; default = []; example = [ "2082b5e0-7a64-478a-b1b2-e3404fab6dad" ]; description = '' - Allow blacklisting specific devices by their GUID + Allow disabling specific devices by their GUID ''; }; - blacklistPlugins = mkOption { + disabledPlugins = mkOption { type = types.listOf types.str; default = []; example = [ "udev" ]; description = '' - Allow blacklisting specific plugins + Allow disabling specific plugins ''; }; @@ -105,11 +105,15 @@ in { }; }; + imports = [ + (mkRenamedOptionModule [ "services" "fwupd" "blacklistDevices"] [ "services" "fwupd" "disabledDevices" ]) + (mkRenamedOptionModule [ "services" "fwupd" "blacklistPlugins"] [ "services" "fwupd" "disabledPlugins" ]) + ]; ###### implementation config = mkIf cfg.enable { # Disable test related plug-ins implicitly so that users do not have to care about them. - services.fwupd.blacklistPlugins = cfg.package.defaultBlacklistedPlugins; + services.fwupd.disabledPlugins = cfg.package.defaultDisabledPlugins; environment.systemPackages = [ cfg.package ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/lcd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/lcd.nix index d78d742cd318..dc8595ea60cd 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/lcd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/lcd.nix @@ -151,14 +151,13 @@ in with lib; { description = "LCDproc - client"; after = [ "lcdd.service" ]; wantedBy = [ "lcd.target" ]; + # Allow restarting for eternity + startLimitIntervalSec = lib.mkIf cfg.client.restartForever 0; serviceConfig = serviceCfg // { ExecStart = "${pkg}/bin/lcdproc -f -c ${clientCfg}"; # If the server is being restarted at the same time, the client will # fail as it cannot connect, so space it out a bit. RestartSec = "5"; - # Allow restarting for eternity - StartLimitIntervalSec = lib.mkIf cfg.client.restartForever "0"; - StartLimitBurst = lib.mkIf cfg.client.restartForever "0"; }; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/sane.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/sane.nix index b344dfc20610..03070a8f9e7c 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/sane.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/sane.nix @@ -148,7 +148,7 @@ in # saned needs to distinguish between IPv4 and IPv6 to open matching data sockets. BindIPv6Only = "ipv6-only"; Accept = true; - MaxConnections = 1; + MaxConnections = 64; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/thermald.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/thermald.nix index b7be0e89d0c6..241490c5aae7 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/thermald.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/thermald.nix @@ -23,15 +23,6 @@ in { default = null; description = "the thermald manual configuration file."; }; - - adaptive = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable adaptive mode, only working on kernel versions greater than 5.8. - Thermald will detect this itself, safe to enable on kernel versions below 5.8. - ''; - }; }; }; @@ -48,8 +39,8 @@ in { --no-daemon \ ${optionalString cfg.debug "--loglevel=debug"} \ ${optionalString (cfg.configFile != null) "--config-file ${cfg.configFile}"} \ - ${optionalString cfg.adaptive "--adaptive"} \ --dbus-enable + --adaptive ''; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/tlp.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/tlp.nix index 4230f2edd279..eb53f565a67f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/tlp.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/tlp.nix @@ -39,7 +39,7 @@ in default = ""; description = '' Verbatim additional configuration variables for TLP. - DEPRECATED: use services.tlp.config instead. + DEPRECATED: use services.tlp.settings instead. ''; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/udev.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/udev.nix index 587b9b0234aa..a212adb7342d 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/udev.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/udev.nix @@ -57,8 +57,8 @@ let substituteInPlace $i \ --replace \"/sbin/modprobe \"${pkgs.kmod}/bin/modprobe \ --replace \"/sbin/mdadm \"${pkgs.mdadm}/sbin/mdadm \ - --replace \"/sbin/blkid \"${pkgs.utillinux}/sbin/blkid \ - --replace \"/bin/mount \"${pkgs.utillinux}/bin/mount \ + --replace \"/sbin/blkid \"${pkgs.util-linux}/sbin/blkid \ + --replace \"/bin/mount \"${pkgs.util-linux}/bin/mount \ --replace /usr/bin/readlink ${pkgs.coreutils}/bin/readlink \ --replace /usr/bin/basename ${pkgs.coreutils}/bin/basename done @@ -280,7 +280,7 @@ in services.udev.packages = [ extraUdevRules extraHwdbFile ]; - services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.utillinux udev ]; + services.udev.path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep pkgs.util-linux udev ]; boot.kernelParams = mkIf (!config.networking.usePredictableInterfaceNames) [ "net.ifnames=0" ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/undervolt.nix b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/undervolt.nix index 054ffa35050a..9c2f78a755dd 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/hardware/undervolt.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/hardware/undervolt.nix @@ -3,7 +3,12 @@ with lib; let cfg = config.services.undervolt; - cliArgs = lib.cli.toGNUCommandLineShell {} { + + mkPLimit = limit: window: + if (isNull limit && isNull window) then null + else assert asserts.assertMsg (!isNull limit && !isNull window) "Both power limit and window must be set"; + "${toString limit} ${toString window}"; + cliArgs = lib.cli.toGNUCommandLine {} { inherit (cfg) verbose temp @@ -21,6 +26,9 @@ let temp-bat = cfg.tempBat; temp-ac = cfg.tempAc; + + power-limit-long = mkPLimit cfg.p1.limit cfg.p1.window; + power-limit-short = mkPLimit cfg.p2.limit cfg.p2.window; }; in { @@ -104,6 +112,40 @@ in ''; }; + p1.limit = mkOption { + type = with types; nullOr int; + default = null; + description = '' + The P1 Power Limit in Watts. + Both limit and window must be set. + ''; + }; + p1.window = mkOption { + type = with types; nullOr (oneOf [ float int ]); + default = null; + description = '' + The P1 Time Window in seconds. + Both limit and window must be set. + ''; + }; + + p2.limit = mkOption { + type = with types; nullOr int; + default = null; + description = '' + The P2 Power Limit in Watts. + Both limit and window must be set. + ''; + }; + p2.window = mkOption { + type = with types; nullOr (oneOf [ float int ]); + default = null; + description = '' + The P2 Time Window in seconds. + Both limit and window must be set. + ''; + }; + useTimer = mkOption { type = types.bool; default = false; @@ -133,7 +175,7 @@ in serviceConfig = { Type = "oneshot"; Restart = "no"; - ExecStart = "${pkgs.undervolt}/bin/undervolt ${cliArgs}"; + ExecStart = "${pkgs.undervolt}/bin/undervolt ${toString cliArgs}"; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/logging/promtail.nix b/infra/libkookie/nixpkgs/nixos/modules/services/logging/promtail.nix new file mode 100644 index 000000000000..19b12daa4152 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/logging/promtail.nix @@ -0,0 +1,86 @@ +{ config, lib, pkgs, ... }: with lib; +let + cfg = config.services.promtail; + + prettyJSON = conf: pkgs.runCommandLocal "promtail-config.json" {} '' + echo '${builtins.toJSON conf}' | ${pkgs.buildPackages.jq}/bin/jq 'del(._module)' > $out + ''; + + allowSystemdJournal = cfg.configuration ? scrape_configs && lib.any (v: v ? journal) cfg.configuration.scrape_configs; +in { + options.services.promtail = with types; { + enable = mkEnableOption "the Promtail ingresser"; + + + configuration = mkOption { + type = (pkgs.formats.json {}).type; + description = '' + Specify the configuration for Promtail in Nix. + ''; + }; + + extraFlags = mkOption { + type = listOf str; + default = []; + example = [ "--server.http-listen-port=3101" ]; + description = '' + Specify a list of additional command line flags, + which get escaped and are then passed to Loki. + ''; + }; + }; + + config = mkIf cfg.enable { + services.promtail.configuration.positions.filename = mkDefault "/var/cache/promtail/positions.yaml"; + + systemd.services.promtail = { + description = "Promtail log ingress"; + wantedBy = [ "multi-user.target" ]; + stopIfChanged = false; + + serviceConfig = { + Restart = "on-failure"; + + ExecStart = "${pkgs.grafana-loki}/bin/promtail -config.file=${prettyJSON cfg.configuration} ${escapeShellArgs cfg.extraFlags}"; + + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + RestrictSUIDSGID = true; + PrivateMounts = true; + CacheDirectory = "promtail"; + + User = "promtail"; + Group = "promtail"; + + CapabilityBoundingSet = ""; + NoNewPrivileges = true; + + ProtectKernelModules = true; + SystemCallArchitectures = "native"; + ProtectKernelLogs = true; + ProtectClock = true; + + LockPersonality = true; + ProtectHostname = true; + RestrictRealtime = true; + MemoryDenyWriteExecute = true; + PrivateUsers = true; + + SupplementaryGroups = lib.optional (allowSystemdJournal) "systemd-journal"; + } // (optionalAttrs (!pkgs.stdenv.isAarch64) { # FIXME: figure out why this breaks on aarch64 + SystemCallFilter = "@system-service"; + }); + }; + + users.groups.promtail = {}; + users.users.promtail = { + description = "Promtail service user"; + isSystemUser = true; + group = "promtail"; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/logging/vector.nix b/infra/libkookie/nixpkgs/nixos/modules/services/logging/vector.nix new file mode 100644 index 000000000000..a7c54ad75fde --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/logging/vector.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: + +with lib; +let cfg = config.services.vector; + +in { + options.services.vector = { + enable = mkEnableOption "Vector"; + + journaldAccess = mkOption { + type = types.bool; + default = false; + description = '' + Enable Vector to access journald. + ''; + }; + + settings = mkOption { + type = (pkgs.formats.json { }).type; + default = { }; + description = '' + Specify the configuration for Vector in Nix. + ''; + }; + }; + + config = mkIf cfg.enable { + + users.groups.vector = { }; + users.users.vector = { + description = "Vector service user"; + group = "vector"; + isSystemUser = true; + }; + systemd.services.vector = { + description = "Vector event and log aggregator"; + wantedBy = [ "multi-user.target" ]; + after = [ "network-online.target" ]; + requires = [ "network-online.target" ]; + serviceConfig = let + format = pkgs.formats.toml { }; + conf = format.generate "vector.toml" cfg.settings; + validateConfig = file: + pkgs.runCommand "validate-vector-conf" { } '' + ${pkgs.vector}/bin/vector validate --no-topology --no-environment "${file}" + ln -s "${file}" "$out" + ''; + in { + ExecStart = "${pkgs.vector}/bin/vector --config ${validateConfig conf}"; + User = "vector"; + Group = "vector"; + Restart = "no"; + StateDirectory = "vector"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + # This group is required for accessing journald. + SupplementaryGroups = mkIf cfg.journaldAccess "systemd-journal"; + }; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/mail/dovecot.nix b/infra/libkookie/nixpkgs/nixos/modules/services/mail/dovecot.nix index f5c5f795dc1b..03e7e40e388e 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/mail/dovecot.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/mail/dovecot.nix @@ -427,12 +427,12 @@ in wantedBy = [ "multi-user.target" ]; restartTriggers = [ cfg.configFile modulesDir ]; + startLimitIntervalSec = 60; # 1 min serviceConfig = { ExecStart = "${dovecotPkg}/sbin/dovecot -F"; ExecReload = "${dovecotPkg}/sbin/doveadm reload"; Restart = "on-failure"; RestartSec = "1s"; - StartLimitInterval = "1min"; RuntimeDirectory = [ "dovecot2" ]; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/mail/freepops.nix b/infra/libkookie/nixpkgs/nixos/modules/services/mail/freepops.nix deleted file mode 100644 index 5b729ca50a5e..000000000000 --- a/infra/libkookie/nixpkgs/nixos/modules/services/mail/freepops.nix +++ /dev/null @@ -1,89 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.mail.freepopsd; -in - -{ - options = { - services.mail.freepopsd = { - enable = mkOption { - default = false; - type = with types; bool; - description = '' - Enables Freepops, a POP3 webmail wrapper. - ''; - }; - - port = mkOption { - default = 2000; - type = with types; uniq int; - description = '' - Port on which the pop server will listen. - ''; - }; - - threads = mkOption { - default = 5; - type = with types; uniq int; - description = '' - Max simultaneous connections. - ''; - }; - - bind = mkOption { - default = "0.0.0.0"; - type = types.str; - description = '' - Bind over an IPv4 address instead of any. - ''; - }; - - logFile = mkOption { - default = "/var/log/freepopsd"; - example = "syslog"; - type = types.str; - description = '' - Filename of the log file or syslog to rely on the logging daemon. - ''; - }; - - suid = { - user = mkOption { - default = "nobody"; - type = types.str; - description = '' - User name under which freepopsd will be after binding the port. - ''; - }; - - group = mkOption { - default = "nogroup"; - type = types.str; - description = '' - Group under which freepopsd will be after binding the port. - ''; - }; - }; - - }; - }; - - config = mkIf cfg.enable { - systemd.services.freepopsd = { - description = "Freepopsd (webmail over POP3)"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - script = '' - ${pkgs.freepops}/bin/freepopsd \ - -p ${toString cfg.port} \ - -t ${toString cfg.threads} \ - -b ${cfg.bind} \ - -vv -l ${cfg.logFile} \ - -s ${cfg.suid.user}.${cfg.suid.group} - ''; - }; - }; -} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/mail/postfix.nix b/infra/libkookie/nixpkgs/nixos/modules/services/mail/postfix.nix index fd4d16cdc37b..319b3b638444 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/mail/postfix.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/mail/postfix.nix @@ -834,12 +834,6 @@ in }; services.postfix.masterConfig = { - smtp_inet = { - name = "smtp"; - type = "inet"; - private = false; - command = "smtpd"; - }; pickup = { private = false; wakeup = 60; @@ -921,6 +915,12 @@ in in concatLists (mapAttrsToList mkKeyVal cfg.submissionOptions); }; } // optionalAttrs cfg.enableSmtp { + smtp_inet = { + name = "smtp"; + type = "inet"; + private = false; + command = "smtpd"; + }; smtp = {}; relay = { command = "smtp"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/mail/roundcube.nix b/infra/libkookie/nixpkgs/nixos/modules/services/mail/roundcube.nix index a0bbab64985b..ee7aa7e22fb9 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/mail/roundcube.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/mail/roundcube.nix @@ -204,6 +204,11 @@ in }; systemd.services.phpfpm-roundcube.after = [ "roundcube-setup.service" ]; + # Restart on config changes. + systemd.services.phpfpm-roundcube.restartTriggers = [ + config.environment.etc."roundcube/config.inc.php".source + ]; + systemd.services.roundcube-setup = mkMerge [ (mkIf (cfg.database.host == "localhost") { requires = [ "postgresql.service" ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/mail/rspamd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/mail/rspamd.nix index aacdbe2aeed2..2f9d28195bd8 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/mail/rspamd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/mail/rspamd.nix @@ -153,7 +153,7 @@ let ${concatStringsSep "\n" (mapAttrsToList (name: value: let includeName = if name == "rspamd_proxy" then "proxy" else name; - tryOverride = if value.extraConfig == "" then "true" else "false"; + tryOverride = boolToString (value.extraConfig == ""); in '' worker "${value.type}" { type = "${value.type}"; @@ -371,6 +371,9 @@ in }; services.postfix.config = mkIf cfg.postfix.enable cfg.postfix.config; + systemd.services.postfix.serviceConfig.SupplementaryGroups = + mkIf cfg.postfix.enable [ postfixCfg.group ]; + # Allow users to run 'rspamc' and 'rspamadm'. environment.systemPackages = [ pkgs.rspamd ]; @@ -394,21 +397,50 @@ in restartTriggers = [ rspamdDir ]; serviceConfig = { - ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} --user=${cfg.user} --group=${cfg.group} --pid=/run/rspamd.pid -c /etc/rspamd/rspamd.conf -f"; + ExecStart = "${pkgs.rspamd}/bin/rspamd ${optionalString cfg.debug "-d"} -c /etc/rspamd/rspamd.conf -f"; Restart = "always"; + + User = "${cfg.user}"; + Group = "${cfg.group}"; + SupplementaryGroups = mkIf cfg.postfix.enable [ postfixCfg.group ]; + RuntimeDirectory = "rspamd"; + RuntimeDirectoryMode = "0755"; + StateDirectory = "rspamd"; + StateDirectoryMode = "0700"; + + AmbientCapabilities = []; + CapabilityBoundingSet = []; + DevicePolicy = "closed"; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; PrivateTmp = true; + # we need to chown socket to rspamd-milter + PrivateUsers = !cfg.postfix.enable; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectSystem = "strict"; + RemoveIPC = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = "@system-service"; + UMask = "0077"; }; - - preStart = '' - ${pkgs.coreutils}/bin/mkdir -p /var/lib/rspamd - ${pkgs.coreutils}/bin/chown ${cfg.user}:${cfg.group} /var/lib/rspamd - ''; }; }; imports = [ (mkRemovedOptionModule [ "services" "rspamd" "socketActivation" ] - "Socket activation never worked correctly and could at this time not be fixed and so was removed") + "Socket activation never worked correctly and could at this time not be fixed and so was removed") (mkRenamedOptionModule [ "services" "rspamd" "bindSocket" ] [ "services" "rspamd" "workers" "normal" "bindSockets" ]) (mkRenamedOptionModule [ "services" "rspamd" "bindUISocket" ] [ "services" "rspamd" "workers" "controller" "bindSockets" ]) (mkRemovedOptionModule [ "services" "rmilter" ] "Use services.rspamd.* instead to set up milter service") diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/autorandr.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/autorandr.nix index cf7fb5f78d3d..dfb418af6ede 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/autorandr.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/autorandr.nix @@ -37,9 +37,9 @@ in { description = "Autorandr execution hook"; after = [ "sleep.target" ]; + startLimitIntervalSec = 5; + startLimitBurst = 1; serviceConfig = { - StartLimitInterval = 5; - StartLimitBurst = 1; ExecStart = "${pkgs.autorandr}/bin/autorandr --batch --change --default ${cfg.defaultTarget}"; Type = "oneshot"; RemainAfterExit = false; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/cfdyndns.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/cfdyndns.nix index dcf416022734..15af1f50da1d 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/cfdyndns.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/cfdyndns.nix @@ -6,6 +6,12 @@ let cfg = config.services.cfdyndns; in { + imports = [ + (mkRemovedOptionModule + [ "services" "cfdyndns" "apikey" ] + "Use services.cfdyndns.apikeyFile instead.") + ]; + options = { services.cfdyndns = { enable = mkEnableOption "Cloudflare Dynamic DNS Client"; @@ -17,10 +23,12 @@ in ''; }; - apikey = mkOption { - type = types.str; + apikeyFile = mkOption { + default = null; + type = types.nullOr types.str; description = '' - The API Key to use to authenticate to CloudFlare. + The path to a file containing the API Key + used to authenticate with CloudFlare. ''; }; @@ -45,13 +53,17 @@ in Type = "simple"; User = config.ids.uids.cfdyndns; Group = config.ids.gids.cfdyndns; - ExecStart = "/bin/sh -c '${pkgs.cfdyndns}/bin/cfdyndns'"; }; environment = { CLOUDFLARE_EMAIL="${cfg.email}"; - CLOUDFLARE_APIKEY="${cfg.apikey}"; CLOUDFLARE_RECORDS="${concatStringsSep "," cfg.records}"; }; + script = '' + ${optionalString (cfg.apikeyFile != null) '' + export CLOUDFLARE_APIKEY="$(cat ${escapeShellArg cfg.apikeyFile})" + ''} + ${pkgs.cfdyndns}/bin/cfdyndns + ''; }; users.users = { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/cgminer.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/cgminer.nix index 7635c2a0f4e9..fa9c8c54509e 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/cgminer.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/cgminer.nix @@ -126,12 +126,12 @@ in GPU_USE_SYNC_OBJECTS = "1"; }; + startLimitIntervalSec = 60; # 1 min serviceConfig = { ExecStart = "${pkgs.cgminer}/bin/cgminer --syslog --text-only --config ${cgminerConfig}"; User = cfg.user; RestartSec = "30s"; Restart = "always"; - StartLimitInterval = "1m"; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/disnix.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/disnix.nix index 69386cdbb381..41483d80a2dd 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/disnix.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/disnix.nix @@ -34,6 +34,14 @@ in defaultText = "pkgs.disnix"; }; + enableProfilePath = mkEnableOption "exposing the Disnix profiles in the system's PATH"; + + profiles = mkOption { + type = types.listOf types.string; + default = [ "default" ]; + example = [ "default" ]; + description = "Names of the Disnix profiles to expose in the system's PATH"; + }; }; }; @@ -44,6 +52,7 @@ in dysnomia.enable = true; environment.systemPackages = [ pkgs.disnix ] ++ optional cfg.useWebServiceInterface pkgs.DisnixWebService; + environment.variables.PATH = lib.optionals cfg.enableProfilePath (map (profileName: "/nix/var/nix/profiles/disnix/${profileName}/bin" ) cfg.profiles); services.dbus.enable = true; services.dbus.packages = [ pkgs.disnix ]; @@ -68,7 +77,8 @@ in ++ optional config.services.postgresql.enable "postgresql.service" ++ optional config.services.tomcat.enable "tomcat.service" ++ optional config.services.svnserve.enable "svnserve.service" - ++ optional config.services.mongodb.enable "mongodb.service"; + ++ optional config.services.mongodb.enable "mongodb.service" + ++ optional config.services.influxdb.enable "influxdb.service"; restartIfChanged = false; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/dysnomia.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/dysnomia.nix index 4b52963500d1..eb94791fbbff 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/dysnomia.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/dysnomia.nix @@ -66,6 +66,19 @@ let ) (builtins.attrNames cfg.components)} ''; }; + + dysnomiaFlags = { + enableApacheWebApplication = config.services.httpd.enable; + enableAxis2WebService = config.services.tomcat.axis2.enable; + enableDockerContainer = config.virtualisation.docker.enable; + enableEjabberdDump = config.services.ejabberd.enable; + enableMySQLDatabase = config.services.mysql.enable; + enablePostgreSQLDatabase = config.services.postgresql.enable; + enableTomcatWebApplication = config.services.tomcat.enable; + enableMongoDatabase = config.services.mongodb.enable; + enableSubversionRepository = config.services.svnserve.enable; + enableInfluxDatabase = config.services.influxdb.enable; + }; in { options = { @@ -117,6 +130,12 @@ in description = "A list of paths containing additional modules that are added to the search folders"; default = []; }; + + enableLegacyModules = mkOption { + type = types.bool; + default = true; + description = "Whether to enable Dysnomia legacy process and wrapper modules"; + }; }; }; @@ -142,34 +161,48 @@ in environment.systemPackages = [ cfg.package ]; - dysnomia.package = pkgs.dysnomia.override (origArgs: { - enableApacheWebApplication = config.services.httpd.enable; - enableAxis2WebService = config.services.tomcat.axis2.enable; - enableEjabberdDump = config.services.ejabberd.enable; - enableMySQLDatabase = config.services.mysql.enable; - enablePostgreSQLDatabase = config.services.postgresql.enable; - enableSubversionRepository = config.services.svnserve.enable; - enableTomcatWebApplication = config.services.tomcat.enable; - enableMongoDatabase = config.services.mongodb.enable; - enableInfluxDatabase = config.services.influxdb.enable; + dysnomia.package = pkgs.dysnomia.override (origArgs: dysnomiaFlags // lib.optionalAttrs (cfg.enableLegacyModules) { + enableLegacy = builtins.trace '' + WARNING: Dysnomia has been configured to use the legacy 'process' and 'wrapper' + modules for compatibility reasons! If you rely on these modules, consider + migrating to better alternatives. + + More information: https://raw.githubusercontent.com/svanderburg/dysnomia/f65a9a84827bcc4024d6b16527098b33b02e4054/README-legacy.md + + If you have migrated already or don't rely on these Dysnomia modules, you can + disable legacy mode with the following NixOS configuration option: + + dysnomia.enableLegacyModules = false; + + In a future version of Dysnomia (and NixOS) the legacy option will go away! + '' true; }); dysnomia.properties = { hostname = config.networking.hostName; inherit (config.nixpkgs.localSystem) system; - supportedTypes = (import "${pkgs.stdenv.mkDerivation { - name = "supportedtypes"; - buildCommand = '' - ( echo -n "[ " - cd ${cfg.package}/libexec/dysnomia - for i in * - do - echo -n "\"$i\" " - done - echo -n " ]") > $out - ''; - }}"); + supportedTypes = [ + "echo" + "fileset" + "process" + "wrapper" + + # These are not base modules, but they are still enabled because they work with technology that are always enabled in NixOS + "systemd-unit" + "sysvinit-script" + "nixos-configuration" + ] + ++ optional (dysnomiaFlags.enableApacheWebApplication) "apache-webapplication" + ++ optional (dysnomiaFlags.enableAxis2WebService) "axis2-webservice" + ++ optional (dysnomiaFlags.enableDockerContainer) "docker-container" + ++ optional (dysnomiaFlags.enableEjabberdDump) "ejabberd-dump" + ++ optional (dysnomiaFlags.enableInfluxDatabase) "influx-database" + ++ optional (dysnomiaFlags.enableMySQLDatabase) "mysql-database" + ++ optional (dysnomiaFlags.enablePostgreSQLDatabase) "postgresql-database" + ++ optional (dysnomiaFlags.enableTomcatWebApplication) "tomcat-webapplication" + ++ optional (dysnomiaFlags.enableMongoDatabase) "mongo-database" + ++ optional (dysnomiaFlags.enableSubversionRepository) "subversion-repository"; }; dysnomia.containers = lib.recursiveUpdate ({ @@ -185,9 +218,9 @@ in }; } // lib.optionalAttrs (config.services.mysql.enable) { mysql-database = { mysqlPort = config.services.mysql.port; + mysqlSocket = "/run/mysqld/mysqld.sock"; } // lib.optionalAttrs cfg.enableAuthentication { mysqlUsername = "root"; - mysqlPassword = builtins.readFile (config.services.mysql.rootPassword); }; } // lib.optionalAttrs (config.services.postgresql.enable) { postgresql-database = { @@ -199,6 +232,13 @@ in tomcatPort = 8080; }; } // lib.optionalAttrs (config.services.mongodb.enable) { mongo-database = {}; } + // lib.optionalAttrs (config.services.influxdb.enable) { + influx-database = { + influxdbUsername = config.services.influxdb.user; + influxdbDataDir = "${config.services.influxdb.dataDir}/data"; + influxdbMetaDir = "${config.services.influxdb.dataDir}/meta"; + }; + } // lib.optionalAttrs (config.services.svnserve.enable) { subversion-repository = { svnBaseDir = config.services.svnserve.svnBaseDir; }; }) cfg.extraContainerProperties; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/fstrim.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/fstrim.nix index b8841a7fe74c..5258f5acb410 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/fstrim.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/fstrim.nix @@ -31,7 +31,7 @@ in { config = mkIf cfg.enable { - systemd.packages = [ pkgs.utillinux ]; + systemd.packages = [ pkgs.util-linux ]; systemd.timers.fstrim = { timerConfig = { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/gitlab.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/gitlab.nix index 122bc3000b41..3ee7a81dc375 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/gitlab.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/gitlab.nix @@ -43,9 +43,13 @@ let [gitlab-shell] dir = "${cfg.packages.gitlab-shell}" + + [gitlab] secret_file = "${cfg.statePath}/gitlab_shell_secret" - gitlab_url = "http+unix://${pathUrlQuote gitlabSocket}" - http_settings = { self_signed_cert = false } + url = "http+unix://${pathUrlQuote gitlabSocket}" + + [gitlab.http-settings] + self_signed_cert = false ${concatStringsSep "\n" (attrValues (mapAttrs (k: v: '' [[storage]] @@ -119,6 +123,7 @@ let receive_pack = true; }; workhorse.secret_file = "${cfg.statePath}/.gitlab_workhorse_secret"; + gitlab_kas.secret_file = "${cfg.statePath}/.gitlab_kas_secret"; git.bin_path = "git"; monitoring = { ip_whitelist = [ "127.0.0.0/8" "::1/128" ]; @@ -653,7 +658,7 @@ in { script = '' set -eu - PSQL="${pkgs.utillinux}/bin/runuser -u ${pgsql.superUser} -- psql --port=${toString pgsql.port}" + PSQL="${pkgs.util-linux}/bin/runuser -u ${pgsql.superUser} -- psql --port=${toString pgsql.port}" $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = '${cfg.databaseName}'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "${cfg.databaseName}" OWNER "${cfg.databaseUsername}"' current_owner=$($PSQL -tAc "SELECT pg_catalog.pg_get_userbyid(datdba) FROM pg_catalog.pg_database WHERE datname = '${cfg.databaseName}'") @@ -668,6 +673,7 @@ in { rm "${config.services.postgresql.dataDir}/.reassigning_${cfg.databaseName}" fi $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS pg_trgm" + $PSQL '${cfg.databaseName}' -tAc "CREATE EXTENSION IF NOT EXISTS btree_gist;" ''; serviceConfig = { @@ -750,7 +756,8 @@ in { }; systemd.services.gitaly = { - after = [ "network.target" ]; + after = [ "network.target" "gitlab.service" ]; + bindsTo = [ "gitlab.service" ]; wantedBy = [ "multi-user.target" ]; path = with pkgs; [ openssh @@ -839,7 +846,7 @@ in { }; systemd.services.gitlab = { - after = [ "gitlab-workhorse.service" "gitaly.service" "network.target" "gitlab-postgresql.service" "redis.service" ]; + after = [ "gitlab-workhorse.service" "network.target" "gitlab-postgresql.service" "redis.service" ]; requires = [ "gitlab-sidekiq.service" ]; wantedBy = [ "multi-user.target" ]; environment = gitlabEnv; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/gogs.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/gogs.nix index c5070aaa356a..d7233f10c7cb 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/gogs.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/gogs.nix @@ -25,7 +25,6 @@ let HTTP_ADDR = ${cfg.httpAddress} HTTP_PORT = ${toString cfg.httpPort} ROOT_URL = ${cfg.rootUrl} - STATIC_ROOT_PATH = ${cfg.staticRootPath} [session] COOKIE_NAME = session @@ -179,13 +178,6 @@ in ''; }; - staticRootPath = mkOption { - type = types.str; - default = "${pkgs.gogs.data}"; - example = "/var/lib/gogs/data"; - description = "Upper level of template and static files path."; - }; - extraConfig = mkOption { type = types.str; default = ""; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/home-assistant.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/home-assistant.nix index 0477254e7c18..1f2e13f37325 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/home-assistant.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/home-assistant.nix @@ -245,7 +245,11 @@ in { Group = "hass"; Restart = "on-failure"; ProtectSystem = "strict"; - ReadWritePaths = "${cfg.configDir}"; + ReadWritePaths = let + cfgPath = [ "config" "homeassistant" "allowlist_external_dirs" ]; + value = attrByPath cfgPath [] cfg; + allowPaths = if isList value then value else singleton value; + in [ "${cfg.configDir}" ] ++ allowPaths; KillSignal = "SIGINT"; PrivateTmp = true; RemoveIPC = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/jellyfin.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/jellyfin.nix index 0493dadea94e..6a47dc3628f4 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/jellyfin.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/jellyfin.nix @@ -45,6 +45,46 @@ in CacheDirectory = "jellyfin"; ExecStart = "${cfg.package}/bin/jellyfin --datadir '/var/lib/${StateDirectory}' --cachedir '/var/cache/${CacheDirectory}'"; Restart = "on-failure"; + + # Security options: + + NoNewPrivileges = true; + + AmbientCapabilities = ""; + CapabilityBoundingSet = ""; + + # ProtectClock= adds DeviceAllow=char-rtc r + DeviceAllow = ""; + + LockPersonality = true; + + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = true; + + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + + RemoveIPC = true; + + RestrictNamespaces = true; + # AF_NETLINK needed because Jellyfin monitors the network connection + RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET" "AF_INET6" ]; + RestrictRealtime = true; + RestrictSUIDSGID = true; + + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; + SystemCallFilter = [ + "@system-service" + + "~@chown" "~@cpu-emulation" "~@debug" "~@keyring" "~@memlock" "~@module" + "~@obsolete" "~@privileged" "~@setuid" + ]; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix index 7f42184735c8..3abb9b7d69c8 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/matrix-synapse.nix @@ -713,7 +713,7 @@ in { ${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) } --keys-directory ${cfg.dataDir} ''; - ExecReload = "${pkgs.utillinux}/bin/kill -HUP $MAINPID"; + ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID"; Restart = "on-failure"; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix index c5e8a5b85ec2..caeb4b04164f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/mautrix-telegram.nix @@ -21,6 +21,7 @@ in { default = { appservice = rec { database = "sqlite:///${dataDir}/mautrix-telegram.db"; + database_opts = {}; hostname = "0.0.0.0"; port = 8080; address = "http://localhost:${toString port}"; @@ -29,6 +30,8 @@ in { bridge = { permissions."*" = "relaybot"; relaybot.whitelist = [ ]; + double_puppet_server_map = {}; + login_shared_secret_map = {}; }; logging = { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/n8n.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/n8n.nix new file mode 100644 index 000000000000..516d0f70ef0b --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/n8n.nix @@ -0,0 +1,78 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.n8n; + format = pkgs.formats.json {}; + configFile = format.generate "n8n.json" cfg.settings; +in +{ + options.services.n8n = { + + enable = mkEnableOption "n8n server"; + + openFirewall = mkOption { + type = types.bool; + default = false; + description = "Open ports in the firewall for the n8n web interface."; + }; + + settings = mkOption { + type = format.type; + default = {}; + description = '' + Configuration for n8n, see <link xlink:href="https://docs.n8n.io/reference/configuration.html"/> + for supported values. + ''; + }; + + }; + + config = mkIf cfg.enable { + services.n8n.settings = { + # We use this to open the firewall, so we need to know about the default at eval time + port = lib.mkDefault 5678; + }; + + systemd.services.n8n = { + description = "N8N service"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + # This folder must be writeable as the application is storing + # its data in it, so the StateDirectory is a good choice + N8N_USER_FOLDER = "/var/lib/n8n"; + N8N_CONFIG_FILES = "${configFile}"; + }; + serviceConfig = { + Type = "simple"; + ExecStart = "${pkgs.n8n}/bin/n8n"; + Restart = "on-failure"; + StateDirectory = "n8n"; + + # Basic Hardening + NoNewPrivileges = "yes"; + PrivateTmp = "yes"; + PrivateDevices = "yes"; + DevicePolicy = "closed"; + DynamicUser = "true"; + ProtectSystem = "strict"; + ProtectHome = "read-only"; + ProtectControlGroups = "yes"; + ProtectKernelModules = "yes"; + ProtectKernelTunables = "yes"; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; + RestrictNamespaces = "yes"; + RestrictRealtime = "yes"; + RestrictSUIDSGID = "yes"; + MemoryDenyWriteExecute = "yes"; + LockPersonality = "yes"; + }; + }; + + networking.firewall = mkIf cfg.openFirewall { + allowedTCPPorts = [ cfg.settings.port ]; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/nix-daemon.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/nix-daemon.nix index 2680b1cc0d3b..0eeff31d6c4d 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/nix-daemon.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/nix-daemon.nix @@ -45,7 +45,7 @@ let trusted-substituters = ${toString cfg.trustedBinaryCaches} trusted-public-keys = ${toString cfg.binaryCachePublicKeys} auto-optimise-store = ${boolToString cfg.autoOptimiseStore} - require-sigs = ${if cfg.requireSignedBinaryCaches then "true" else "false"} + require-sigs = ${boolToString cfg.requireSignedBinaryCaches} trusted-users = ${toString cfg.trustedUsers} allowed-users = ${toString cfg.allowedUsers} ${optionalString (!cfg.distributedBuilds) '' @@ -539,7 +539,7 @@ in systemd.sockets.nix-daemon.wantedBy = [ "sockets.target" ]; systemd.services.nix-daemon = - { path = [ nix pkgs.utillinux config.programs.ssh.package ] + { path = [ nix pkgs.util-linux config.programs.ssh.package ] ++ optionals cfg.distributedBuilds [ pkgs.gzip ]; environment = cfg.envVars diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/octoprint.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/octoprint.nix index e2fbd3b401cc..a69e65073050 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/octoprint.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/octoprint.nix @@ -68,7 +68,7 @@ in plugins = mkOption { default = plugins: []; defaultText = "plugins: []"; - example = literalExample "plugins: with plugins; [ m33-fio stlviewer ]"; + example = literalExample "plugins: with plugins; [ themeify stlviewer ]"; description = "Additional plugins to be used. Available plugins are passed through the plugins input."; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/safeeyes.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/safeeyes.nix index 6ecb0d13187c..1e748195e41a 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/safeeyes.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/safeeyes.nix @@ -32,14 +32,14 @@ in wantedBy = [ "graphical-session.target" ]; partOf = [ "graphical-session.target" ]; + startLimitIntervalSec = 350; + startLimitBurst = 10; serviceConfig = { ExecStart = '' ${pkgs.safeeyes}/bin/safeeyes ''; Restart = "on-failure"; RestartSec = 3; - StartLimitInterval = 350; - StartLimitBurst = 10; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/siproxd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/siproxd.nix index 0e87fc461d3f..20fe0793b84b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/siproxd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/siproxd.nix @@ -39,7 +39,7 @@ in default = false; description = '' Whether to enable the Siproxd SIP - proxy/masquerading daemon. + proxy/masquerading daemon. ''; }; @@ -57,29 +57,29 @@ in hostsAllowReg = mkOption { type = types.listOf types.str; - default = [ ]; + default = [ ]; example = [ "192.168.1.0/24" "192.168.2.0/24" ]; - description = '' + description = '' Acess control list for incoming SIP registrations. ''; }; hostsAllowSip = mkOption { type = types.listOf types.str; - default = [ ]; + default = [ ]; example = [ "123.45.0.0/16" "123.46.0.0/16" ]; - description = '' + description = '' Acess control list for incoming SIP traffic. ''; }; hostsDenySip = mkOption { type = types.listOf types.str; - default = [ ]; + default = [ ]; example = [ "10.0.0.0/8" "11.0.0.0/8" ]; - description = '' + description = '' Acess control list for denying incoming - SIP registrations and traffic. + SIP registrations and traffic. ''; }; @@ -87,7 +87,7 @@ in type = types.int; default = 5060; description = '' - Port to listen for incoming SIP messages. + Port to listen for incoming SIP messages. ''; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/svnserve.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/svnserve.nix index 3335ed09d40e..f70e3ca7fef0 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/svnserve.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/svnserve.nix @@ -25,7 +25,7 @@ in svnBaseDir = mkOption { default = "/repos"; - description = "Base directory from which Subversion repositories are accessed."; + description = "Base directory from which Subversion repositories are accessed."; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix b/infra/libkookie/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix index 0957920f1a09..cd987eb76c76 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/misc/zigbee2mqtt.nix @@ -70,6 +70,7 @@ in description = "Zigbee2mqtt Service"; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; + environment.ZIGBEE2MQTT_DATA = cfg.dataDir; serviceConfig = { ExecStart = "${cfg.package}/bin/zigbee2mqtt"; User = "zigbee2mqtt"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/loki.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/loki.nix index f4eec7e0d284..51cabaa274a3 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/loki.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/loki.nix @@ -39,7 +39,7 @@ in { }; configuration = mkOption { - type = types.attrs; + type = (pkgs.formats.json {}).type; default = {}; description = '' Specify the configuration for Loki in Nix. @@ -78,6 +78,8 @@ in { ''; }]; + environment.systemPackages = [ pkgs.grafana-loki ]; # logcli + users.groups.${cfg.group} = { }; users.users.${cfg.user} = { description = "Loki Service User"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix new file mode 100644 index 000000000000..7046de9d403c --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/mackerel-agent.nix @@ -0,0 +1,111 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.mackerel-agent; + settingsFmt = pkgs.formats.toml {}; +in { + options.services.mackerel-agent = { + enable = mkEnableOption "mackerel.io agent"; + + # the upstream package runs as root, but doesn't seem to be strictly + # necessary for basic functionality + runAsRoot = mkEnableOption "Whether to run as root."; + + autoRetirement = mkEnableOption '' + Whether to automatically retire the host upon OS shutdown. + ''; + + apiKeyFile = mkOption { + type = types.path; + default = ""; + example = "/run/keys/mackerel-api-key"; + description = '' + Path to file containing the Mackerel API key. The file should contain a + single line of the following form: + + <literallayout>apikey = "EXAMPLE_API_KEY"</literallayout> + ''; + }; + + settings = mkOption { + description = '' + Options for mackerel-agent.conf. + + Documentation: + <link xlink:href="https://mackerel.io/docs/entry/spec/agent"/> + ''; + + default = {}; + example = { + verbose = false; + silent = false; + }; + + type = types.submodule { + freeformType = settingsFmt.type; + + options.host_status = { + on_start = mkOption { + type = types.enum [ "working" "standby" "maintenance" "poweroff" ]; + description = "Host status after agent startup."; + default = "working"; + }; + on_stop = mkOption { + type = types.enum [ "working" "standby" "maintenance" "poweroff" ]; + description = "Host status after agent shutdown."; + default = "poweroff"; + }; + }; + + options.diagnostic = + mkEnableOption "Collect memory usage for the agent itself"; + }; + }; + }; + + config = mkIf cfg.enable { + environment.systemPackages = with pkgs; [ mackerel-agent ]; + + environment.etc = { + "mackerel-agent/mackerel-agent.conf".source = + settingsFmt.generate "mackerel-agent.conf" cfg.settings; + "mackerel-agent/conf.d/api-key.conf".source = cfg.apiKeyFile; + }; + + services.mackerel-agent.settings = { + root = mkDefault "/var/lib/mackerel-agent"; + pidfile = mkDefault "/run/mackerel-agent/mackerel-agent.pid"; + + # conf.d stores the symlink to cfg.apiKeyFile + include = mkDefault "/etc/mackerel-agent/conf.d/*.conf"; + }; + + # upstream service file in https://git.io/JUt4Q + systemd.services.mackerel-agent = { + description = "mackerel.io agent"; + after = [ "network-online.target" "nss-lookup.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + MACKEREL_PLUGIN_WORKDIR = mkDefault "%C/mackerel-agent"; + }; + serviceConfig = { + DynamicUser = !cfg.runAsRoot; + PrivateTmp = mkDefault true; + CacheDirectory = "mackerel-agent"; + ConfigurationDirectory = "mackerel-agent"; + RuntimeDirectory = "mackerel-agent"; + StateDirectory = "mackerel-agent"; + ExecStart = "${pkgs.mackerel-agent}/bin/mackerel-agent supervise"; + ExecStopPost = mkIf cfg.autoRetirement "${pkg.mackerel-agent}/bin/mackerel-agent retire -force"; + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + LimitNOFILE = mkDefault 65536; + LimitNPROC = mkDefault 65536; + }; + restartTriggers = [ + config.environment.etc."mackerel-agent/mackerel-agent.conf".source + ]; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/netdata.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/netdata.nix index 2e73e15d3a86..db51fdbd2c61 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/netdata.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/netdata.nix @@ -142,7 +142,7 @@ in { serviceConfig = { Environment="PYTHONPATH=${cfg.package}/libexec/netdata/python.d/python_modules"; ExecStart = "${cfg.package}/bin/netdata -P /run/netdata/netdata.pid -D -c ${configFile}"; - ExecReload = "${pkgs.utillinux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID"; + ExecReload = "${pkgs.util-linux}/bin/kill -s HUP -s USR1 -s USR2 $MAINPID"; TimeoutStopSec = 60; Restart = "on-failure"; # User and group diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix index 98aaa9c0f030..72428957109c 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/default.nix @@ -45,7 +45,7 @@ let cmdlineArgs = cfg.extraFlags ++ [ "--storage.tsdb.path=${workingDir}/data/" - "--config.file=${prometheusYml}" + "--config.file=/run/prometheus/prometheus-substituted.yaml" "--web.listen-address=${cfg.listenAddress}:${builtins.toString cfg.port}" "--alertmanager.notification-queue-capacity=${toString cfg.alertmanagerNotificationQueueCapacity}" "--alertmanager.timeout=${toString cfg.alertmanagerTimeout}s" @@ -522,6 +522,45 @@ in { ''; }; + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/root/prometheus.env"; + description = '' + Environment file as defined in <citerefentry> + <refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum> + </citerefentry>. + + Secrets may be passed to the service without adding them to the + world-readable Nix store, by specifying placeholder variables as + the option value in Nix and setting these variables accordingly in the + environment file. + + Environment variables from this file will be interpolated into the + config file using envsubst with this syntax: + <literal>$ENVIRONMENT ''${VARIABLE}</literal> + + <programlisting> + # Example scrape config entry handling an OAuth bearer token + { + job_name = "home_assistant"; + metrics_path = "/api/prometheus"; + scheme = "https"; + bearer_token = "\''${HOME_ASSISTANT_BEARER_TOKEN}"; + [...] + } + </programlisting> + + <programlisting> + # Content of the environment file + HOME_ASSISTANT_BEARER_TOKEN=someoauthbearertoken + </programlisting> + + Note that this file needs to be available on the host on which + <literal>Prometheus</literal> is running. + ''; + }; + configText = mkOption { type = types.nullOr types.lines; default = null; @@ -662,12 +701,19 @@ in { systemd.services.prometheus = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; + preStart = '' + ${lib.getBin pkgs.envsubst}/bin/envsubst -o "/run/prometheus/prometheus-substituted.yaml" \ + -i "${prometheusYml}" + ''; serviceConfig = { ExecStart = "${cfg.package}/bin/prometheus" + optionalString (length cmdlineArgs != 0) (" \\\n " + concatStringsSep " \\\n " cmdlineArgs); User = "prometheus"; Restart = "always"; + EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; + RuntimeDirectory = "prometheus"; + RuntimeDirectoryMode = "0700"; WorkingDirectory = workingDir; StateDirectory = cfg.stateDir; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix index 1233e5cdd1a9..995afca96ff8 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -43,7 +43,9 @@ let "postgres" "redis" "rspamd" + "rtl_433" "snmp" + "sql" "surfboard" "tor" "unifi" @@ -217,6 +219,14 @@ in Please specify either 'services.prometheus.exporters.mail.configuration' or 'services.prometheus.exporters.mail.configFile'. ''; + } { + assertion = cfg.sql.enable -> ( + (cfg.sql.configFile == null) != (cfg.sql.configuration == null) + ); + message = '' + Please specify either 'services.prometheus.exporters.sql.configuration' or + 'services.prometheus.exporters.sql.configFile' + ''; } ]; }] ++ [(mkIf config.services.minio.enable { services.prometheus.exporters.minio.minioAddress = mkDefault "http://localhost:9000"; @@ -224,6 +234,8 @@ in services.prometheus.exporters.minio.minioAccessSecret = mkDefault config.services.minio.secretKey; })] ++ [(mkIf config.services.rspamd.enable { services.prometheus.exporters.rspamd.url = mkDefault "http://localhost:11334/stat"; + })] ++ [(mkIf config.services.prometheus.exporters.rtl_433.enable { + hardware.rtl-sdr.enable = mkDefault true; })] ++ [(mkIf config.services.nginx.enable { systemd.services.prometheus-nginx-exporter.after = [ "nginx.service" ]; systemd.services.prometheus-nginx-exporter.requires = [ "nginx.service" ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix new file mode 100644 index 000000000000..01e420db3897 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/rtl_433.nix @@ -0,0 +1,78 @@ +{ config, lib, pkgs, options }: + +let + cfg = config.services.prometheus.exporters.rtl_433; +in +{ + port = 9550; + + extraOpts = let + mkMatcherOptionType = field: description: with lib.types; + listOf (submodule { + options = { + name = lib.mkOption { + type = str; + description = "Name to match."; + }; + "${field}" = lib.mkOption { + type = int; + inherit description; + }; + location = lib.mkOption { + type = str; + description = "Location to match."; + }; + }; + }); + in + { + rtl433Flags = lib.mkOption { + type = lib.types.str; + default = "-C si"; + example = "-C si -R 19"; + description = '' + Flags passed verbatim to rtl_433 binary. + Having <literal>-C si</literal> (the default) is recommended since only Celsius temperatures are parsed. + ''; + }; + channels = lib.mkOption { + type = mkMatcherOptionType "channel" "Channel to match."; + default = []; + example = [ + { name = "Acurite"; channel = 6543; location = "Kitchen"; } + ]; + description = '' + List of channel matchers to export. + ''; + }; + ids = lib.mkOption { + type = mkMatcherOptionType "id" "ID to match."; + default = []; + example = [ + { name = "Nexus"; id = 1; location = "Bedroom"; } + ]; + description = '' + List of ID matchers to export. + ''; + }; + }; + + serviceOpts = { + serviceConfig = { + # rtl-sdr udev rules make supported USB devices +rw by plugdev. + SupplementaryGroups = "plugdev"; + ExecStart = let + matchers = (map (m: + "--channel_matcher '${m.name},${toString m.channel},${m.location}'" + ) cfg.channels) ++ (map (m: + "--id_matcher '${m.name},${toString m.id},${m.location}'" + ) cfg.ids); in '' + ${pkgs.prometheus-rtl_433-exporter}/bin/rtl_433_prometheus \ + -listen ${cfg.listenAddress}:${toString cfg.port} \ + -subprocess "${pkgs.rtl_433}/bin/rtl_433 -F json ${cfg.rtl433Flags}" \ + ${lib.concatStringsSep " \\\n " matchers} \ + ${lib.concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix new file mode 100644 index 000000000000..d9be724ebc03 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/prometheus/exporters/sql.nix @@ -0,0 +1,104 @@ +{ config, lib, pkgs, options }: +with lib; +let + cfg = config.services.prometheus.exporters.sql; + cfgOptions = { + options = with types; { + jobs = mkOption { + type = attrsOf (submodule jobOptions); + default = { }; + description = "An attrset of metrics scraping jobs to run."; + }; + }; + }; + jobOptions = { + options = with types; { + interval = mkOption { + type = str; + description = '' + How often to run this job, specified in + <link xlink:href="https://golang.org/pkg/time/#ParseDuration">Go duration</link> format. + ''; + }; + connections = mkOption { + type = listOf str; + description = "A list of connection strings of the SQL servers to scrape metrics from"; + }; + startupSql = mkOption { + type = listOf str; + default = []; + description = "A list of SQL statements to execute once after making a connection."; + }; + queries = mkOption { + type = attrsOf (submodule queryOptions); + description = "SQL queries to run."; + }; + }; + }; + queryOptions = { + options = with types; { + help = mkOption { + type = nullOr str; + default = null; + description = "A human-readable description of this metric."; + }; + labels = mkOption { + type = listOf str; + default = [ ]; + description = "A set of columns that will be used as Prometheus labels."; + }; + query = mkOption { + type = str; + description = "The SQL query to run."; + }; + values = mkOption { + type = listOf str; + description = "A set of columns that will be used as values of this metric."; + }; + }; + }; + + configFile = + if cfg.configFile != null + then cfg.configFile + else + let + nameInline = mapAttrsToList (k: v: v // { name = k; }); + renameStartupSql = j: removeAttrs (j // { startup_sql = j.startupSql; }) [ "startupSql" ]; + configuration = { + jobs = map renameStartupSql + (nameInline (mapAttrs (k: v: (v // { queries = nameInline v.queries; })) cfg.configuration.jobs)); + }; + in + builtins.toFile "config.yaml" (builtins.toJSON configuration); +in +{ + extraOpts = { + configFile = mkOption { + type = with types; nullOr path; + default = null; + description = '' + Path to configuration file. + ''; + }; + configuration = mkOption { + type = with types; nullOr (submodule cfgOptions); + default = null; + description = '' + Exporter configuration as nix attribute set. Mutually exclusive with 'configFile' option. + ''; + }; + }; + + port = 9237; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-sql-exporter}/bin/sql_exporter \ + -web.listen-address ${cfg.listenAddress}:${toString cfg.port} \ + -config.file ${configFile} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/smartd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/smartd.nix index c72b4abfcdce..3ea254371142 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/smartd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/smartd.nix @@ -36,7 +36,7 @@ let $SMARTD_MESSAGE EOF - } | ${pkgs.utillinux}/bin/wall 2>/dev/null + } | ${pkgs.util-linux}/bin/wall 2>/dev/null ''} ${optionalString nx.enable '' export DISPLAY=${nx.display} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix index 8d781d82d086..ce9e57a187cd 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/teamviewer.nix @@ -31,14 +31,14 @@ in after = [ "NetworkManager-wait-online.service" "network.target" ]; preStart = "mkdir -pv /var/lib/teamviewer /var/log/teamviewer"; + startLimitIntervalSec = 60; + startLimitBurst = 10; serviceConfig = { Type = "forking"; ExecStart = "${pkgs.teamviewer}/bin/teamviewerd -d"; PIDFile = "/run/teamviewerd.pid"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; Restart = "on-abort"; - StartLimitInterval = "60"; - StartLimitBurst = "10"; }; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/telegraf.nix b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/telegraf.nix index 5d131557e8be..b341a9005c2a 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/telegraf.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/monitoring/telegraf.nix @@ -5,14 +5,8 @@ with lib; let cfg = config.services.telegraf; - configFile = pkgs.runCommand "config.toml" { - buildInputs = [ pkgs.remarshal ]; - preferLocalBuild = true; - } '' - remarshal -if json -of toml \ - < ${pkgs.writeText "config.json" (builtins.toJSON cfg.extraConfig)} \ - > $out - ''; + settingsFormat = pkgs.formats.toml {}; + configFile = settingsFormat.generate "config.toml" cfg.extraConfig; in { ###### interface options = { @@ -26,22 +20,31 @@ in { type = types.package; }; + environmentFiles = mkOption { + type = types.listOf types.path; + default = []; + example = "/run/keys/telegraf.env"; + description = '' + File to load as environment file. Environment variables + from this file will be interpolated into the config file + using envsubst with this syntax: + <literal>$ENVIRONMENT ''${VARIABLE}</literal> + This is useful to avoid putting secrets into the nix store. + ''; + }; + extraConfig = mkOption { default = {}; description = "Extra configuration options for telegraf"; - type = types.attrs; + type = settingsFormat.type; example = { - outputs = { - influxdb = { - urls = ["http://localhost:8086"]; - database = "telegraf"; - }; + outputs.influxdb = { + urls = ["http://localhost:8086"]; + database = "telegraf"; }; - inputs = { - statsd = { - service_address = ":8125"; - delete_timings = true; - }; + inputs.statsd = { + service_address = ":8125"; + delete_timings = true; }; }; }; @@ -51,15 +54,28 @@ in { ###### implementation config = mkIf config.services.telegraf.enable { - systemd.services.telegraf = { + systemd.services.telegraf = let + finalConfigFile = if config.services.telegraf.environmentFiles == [] + then configFile + else "/var/run/telegraf/config.toml"; + in { description = "Telegraf Agent"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; serviceConfig = { - ExecStart=''${cfg.package}/bin/telegraf -config "${configFile}"''; + EnvironmentFile = config.services.telegraf.environmentFiles; + ExecStartPre = lib.optional (config.services.telegraf.environmentFiles != []) + (pkgs.writeShellScript "pre-start" '' + umask 077 + ${pkgs.envsubst}/bin/envsubst -i "${configFile}" > /var/run/telegraf/config.toml + ''); + ExecStart=''${cfg.package}/bin/telegraf -config ${finalConfigFile}''; ExecReload="${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + RuntimeDirectory = "telegraf"; User = "telegraf"; Restart = "on-failure"; + # for ping probes + AmbientCapabilities = [ "CAP_NET_RAW" ]; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix index d17959a6a305..f2dc740fd88e 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ceph.nix @@ -28,6 +28,9 @@ let # Don't start services that are not yet initialized unitConfig.ConditionPathExists = "/var/lib/${stateDirectory}/keyring"; + startLimitBurst = + if daemonType == "osd" then 30 else if lib.elem daemonType ["mgr" "mds"] then 3 else 5; + startLimitIntervalSec = 60 * 30; # 30 mins serviceConfig = { LimitNOFILE = 1048576; @@ -39,8 +42,6 @@ let ProtectHome = "true"; ProtectSystem = "full"; Restart = "on-failure"; - StartLimitBurst = "5"; - StartLimitInterval = "30min"; StateDirectory = stateDirectory; User = "ceph"; Group = if daemonType == "osd" then "disk" else "ceph"; @@ -48,13 +49,10 @@ let -f --cluster ${clusterName} --id ${daemonId}''; } // optionalAttrs (daemonType == "osd") { ExecStartPre = ''${ceph.lib}/libexec/ceph/ceph-osd-prestart.sh --id ${daemonId} --cluster ${clusterName}''; - StartLimitBurst = "30"; RestartSec = "20s"; PrivateDevices = "no"; # osd needs disk access } // optionalAttrs ( daemonType == "mon") { RestartSec = "10"; - } // optionalAttrs (lib.elem daemonType ["mgr" "mds"]) { - StartLimitBurst = "3"; }; }); diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix index f298f831fa7b..2082d513161e 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/ipfs.nix @@ -44,6 +44,13 @@ in { enable = mkEnableOption "Interplanetary File System (WARNING: may cause severe network degredation)"; + package = mkOption { + type = types.package; + default = pkgs.ipfs; + defaultText = "pkgs.ipfs"; + description = "Which IPFS package to use."; + }; + user = mkOption { type = types.str; default = "ipfs"; @@ -176,7 +183,7 @@ in { ###### implementation config = mkIf cfg.enable { - environment.systemPackages = [ pkgs.ipfs ]; + environment.systemPackages = [ cfg.package ]; environment.variables.IPFS_PATH = cfg.dataDir; programs.fuse = mkIf cfg.autoMount { @@ -207,14 +214,14 @@ in { "d '${cfg.ipnsMountDir}' - ${cfg.user} ${cfg.group} - -" ]; - systemd.packages = [ pkgs.ipfs ]; + systemd.packages = [ cfg.package ]; systemd.services.ipfs-init = { description = "IPFS Initializer"; environment.IPFS_PATH = cfg.dataDir; - path = [ pkgs.ipfs ]; + path = [ cfg.package ]; script = '' if [[ ! -f ${cfg.dataDir}/config ]]; then @@ -239,7 +246,7 @@ in { }; systemd.services.ipfs = { - path = [ "/run/wrappers" pkgs.ipfs ]; + path = [ "/run/wrappers" cfg.package ]; environment.IPFS_PATH = cfg.dataDir; wants = [ "ipfs-init.service" ]; @@ -267,7 +274,7 @@ in { cfg.extraConfig)) ); serviceConfig = { - ExecStart = ["" "${pkgs.ipfs}/bin/ipfs daemon ${ipfsFlags}"]; + ExecStart = ["" "${cfg.package}/bin/ipfs daemon ${ipfsFlags}"]; User = cfg.user; Group = cfg.group; } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix index 7674c8f7fa8d..ca9d32311f5f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/netatalk.nix @@ -108,10 +108,10 @@ in extmap = mkOption { type = types.lines; - default = ""; - description = '' - File name extension mappings. - See <literal>man extmap.conf</literal> for more information. + default = ""; + description = '' + File name extension mappings. + See <literal>man extmap.conf</literal> for more information. ''; }; @@ -132,10 +132,10 @@ in Type = "forking"; GuessMainPID = "no"; PIDFile = "/run/lock/netatalk"; - ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0755 -p /var/lib/netatalk/CNID"; + ExecStartPre = "${pkgs.coreutils}/bin/mkdir -m 0755 -p /var/lib/netatalk/CNID"; ExecStart = "${pkgs.netatalk}/sbin/netatalk -F ${afpConfFile}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID"; + ExecStop = "${pkgs.coreutils}/bin/kill -TERM $MAINPID"; Restart = "always"; RestartSec = 1; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix index 677111814a01..03884cb72976 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/client.nix @@ -244,7 +244,7 @@ in # postStop, then we get a hang + kernel oops, because AFS can't be # stopped simply by sending signals to processes. preStop = '' - ${pkgs.utillinux}/bin/umount ${cfg.mountPoint} + ${pkgs.util-linux}/bin/umount ${cfg.mountPoint} ${openafsBin}/sbin/afsd -shutdown ${pkgs.kmod}/sbin/rmmod libafs ''; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix index 095024d2c8af..d782f7821656 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/openafs/server.nix @@ -251,7 +251,6 @@ in { wantedBy = [ "multi-user.target" ]; restartIfChanged = false; unitConfig.ConditionPathExists = [ - "|/etc/openafs/server/rxkad.keytab" "|/etc/openafs/server/KeyFileExt" ]; preStart = '' diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix new file mode 100644 index 000000000000..004d07064afd --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/samba-wsdd.nix @@ -0,0 +1,124 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.samba-wsdd; + +in { + options = { + services.samba-wsdd = { + enable = mkEnableOption '' + Enable Web Services Dynamic Discovery host daemon. This enables (Samba) hosts, like your local NAS device, + to be found by Web Service Discovery Clients like Windows. + <note> + <para>If you use the firewall consider adding the following:</para> + <programlisting> + networking.firewall.allowedTCPPorts = [ 5357 ]; + networking.firewall.allowedUDPPorts = [ 3702 ]; + </programlisting> + </note> + ''; + interface = mkOption { + type = types.nullOr types.str; + default = null; + example = "eth0"; + description = "Interface or address to use."; + }; + hoplimit = mkOption { + type = types.nullOr types.int; + default = null; + example = 2; + description = "Hop limit for multicast packets (default = 1)."; + }; + workgroup = mkOption { + type = types.nullOr types.str; + default = null; + example = "HOME"; + description = "Set workgroup name (default WORKGROUP)."; + }; + hostname = mkOption { + type = types.nullOr types.str; + default = null; + example = "FILESERVER"; + description = "Override (NetBIOS) hostname to be used (default hostname)."; + }; + domain = mkOption { + type = types.nullOr types.str; + default = null; + description = "Set domain name (disables workgroup)."; + }; + discovery = mkOption { + type = types.bool; + default = false; + description = "Enable discovery operation mode."; + }; + listen = mkOption { + type = types.str; + default = "/run/wsdd/wsdd.sock"; + description = "Listen on path or localhost port in discovery mode."; + }; + extraOptions = mkOption { + type = types.listOf types.str; + default = [ "--shortlog" ]; + example = [ "--verbose" "--no-http" "--ipv4only" "--no-host" ]; + description = "Additional wsdd options."; + }; + }; + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.wsdd ]; + + systemd.services.samba-wsdd = { + description = "Web Services Dynamic Discovery host daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + DynamicUser = true; + Type = "simple"; + ExecStart = '' + ${pkgs.wsdd}/bin/wsdd ${optionalString (cfg.interface != null) "--interface '${cfg.interface}'"} \ + ${optionalString (cfg.hoplimit != null) "--hoplimit '${toString cfg.hoplimit}'"} \ + ${optionalString (cfg.workgroup != null) "--workgroup '${cfg.workgroup}'"} \ + ${optionalString (cfg.hostname != null) "--hostname '${cfg.hostname}'"} \ + ${optionalString (cfg.domain != null) "--domain '${cfg.domain}'"} \ + ${optionalString cfg.discovery "--discovery --listen '${cfg.listen}'"} \ + ${escapeShellArgs cfg.extraOptions} + ''; + # Runtime directory and mode + RuntimeDirectory = "wsdd"; + RuntimeDirectoryMode = "0750"; + # Access write directories + UMask = "0027"; + # Capabilities + CapabilityBoundingSet = ""; + # Security + NoNewPrivileges = true; + # Sandboxing + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = false; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + PrivateMounts = true; + # System Call Filtering + SystemCallArchitectures = "native"; + SystemCallFilter = "~@clock @cpu-emulation @debug @module @mount @obsolete @privileged @raw-io @reboot @resources @swap"; + }; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix index b8f8c1d71174..27a9fe847c58 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/network-filesystems/xtreemfs.nix @@ -112,7 +112,7 @@ in description = '' Must be set to a unique identifier, preferably a UUID according to RFC 4122. UUIDs can be generated with `uuidgen` command, found in - the `utillinux` package. + the `util-linux` package. ''; }; port = mkOption { @@ -232,7 +232,7 @@ in description = '' Must be set to a unique identifier, preferably a UUID according to RFC 4122. UUIDs can be generated with `uuidgen` command, found in - the `utillinux` package. + the `util-linux` package. ''; }; port = mkOption { @@ -370,7 +370,7 @@ in description = '' Must be set to a unique identifier, preferably a UUID according to RFC 4122. UUIDs can be generated with `uuidgen` command, found in - the `utillinux` package. + the `util-linux` package. ''; }; port = mkOption { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix index 2900c37f990f..0b7d5575c11f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/avahi-daemon.nix @@ -86,7 +86,8 @@ in ipv6 = mkOption { type = types.bool; - default = false; + default = config.networking.enableIPv6; + defaultText = "config.networking.enableIPv6"; description = "Whether to use IPv6."; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/babeld.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/babeld.nix index e62c74d0069d..90395dbd3c54 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/babeld.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/babeld.nix @@ -87,9 +87,37 @@ in description = "Babel routing daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - serviceConfig.ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile}"; + serviceConfig = { + ExecStart = "${pkgs.babeld}/bin/babeld -c ${configFile} -I /run/babeld/babeld.pid -S /var/lib/babeld/state"; + CapabilityBoundingSet = [ "CAP_NET_ADMIN" ]; + IPAddressAllow = [ "fe80::/64" "ff00::/8" "::1/128" "127.0.0.0/8" ]; + IPAddressDeny = "any"; + LockPersonality = true; + NoNewPrivileges = true; + MemoryDenyWriteExecute = true; + ProtectSystem = "strict"; + ProtectClock = true; + ProtectKernelTunables = false; # Couldn't write sysctl: Read-only file system + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_NETLINK" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + ProtectHome = true; + ProtectHostname = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateDevices = true; + PrivateUsers = false; # kernel_route(ADD): Operation not permitted + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" ]; + UMask = "0177"; + RuntimeDirectory = "babeld"; + StateDirectory = "babeld"; + }; }; - }; - } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix index dde24522756a..ca323e495ec1 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/blockbook-frontend.nix @@ -158,15 +158,21 @@ let type = types.attrs; default = {}; example = literalExample '' { - alternative_estimate_fee = "whatthefee-disabled"; - alternative_estimate_fee_params = "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}"; - fiat_rates = "coingecko"; - fiat_rates_params = "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"bitcoin\", \"periodSeconds\": 60}"; - coin_shortcut = "BTC"; - coin_label = "Bitcoin"; - xpub_magic = 76067358; - xpub_magic_segwit_p2sh = 77429938; - xpub_magic_segwit_native = 78792518; + "alternative_estimate_fee" = "whatthefee-disabled"; + "alternative_estimate_fee_params" = "{\"url\": \"https://whatthefee.io/data.json\", \"periodSeconds\": 60}"; + "fiat_rates" = "coingecko"; + "fiat_rates_params" = "{\"url\": \"https://api.coingecko.com/api/v3\", \"coin\": \"bitcoin\", \"periodSeconds\": 60}"; + "coin_shortcut" = "BTC"; + "coin_label" = "Bitcoin"; + "parse" = true; + "subversion" = ""; + "address_format" = ""; + "xpub_magic" = 76067358; + "xpub_magic_segwit_p2sh" = 77429938; + "xpub_magic_segwit_native" = 78792518; + "mempool_workers" = 8; + "mempool_sub_workers" = 2; + "block_addresses_to_keep" = 300; }''; description = '' Additional configurations to be appended to <filename>coin.conf</filename>. diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/cjdns.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/cjdns.nix index 5f8ac96b2292..f116d6392ea7 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/cjdns.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/cjdns.nix @@ -264,10 +264,10 @@ in '' ); + startLimitIntervalSec = 0; serviceConfig = { Type = "forking"; Restart = "always"; - StartLimitInterval = 0; RestartSec = 1; CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SETUID"; ProtectSystem = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/dhcpcd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/dhcpcd.nix index 0507b739d499..d10bffd91474 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/dhcpcd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/dhcpcd.nix @@ -69,6 +69,11 @@ let if-carrier-up = ""; }.${cfg.wait}} + ${optionalString (config.networking.enableIPv6 == false) '' + # Don't solicit or accept IPv6 Router Advertisements and DHCPv6 if disabled IPv6 + noipv6 + ''} + ${cfg.extraConfig} ''; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix index b9333cd19a2a..ee7e9b0454de 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnscrypt-wrapper.nix @@ -55,7 +55,10 @@ let rotateKeys = '' # check if keys are not expired keyValid() { - fingerprint=$(dnscrypt-wrapper --show-provider-publickey | awk '{print $(NF)}') + fingerprint=$(dnscrypt-wrapper \ + --show-provider-publickey \ + --provider-publickey-file=${publicKey} \ + | awk '{print $(NF)}') dnscrypt-proxy --test=${toString (cfg.keys.checkInterval + 1)} \ --resolver-address=127.0.0.1:${toString cfg.port} \ --provider-name=${cfg.providerName} \ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnsdist.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnsdist.nix index c48835e73612..05c2bdef83e7 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnsdist.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/dnsdist.nix @@ -41,6 +41,7 @@ in { systemd.services.dnsdist = { wantedBy = [ "multi-user.target" ]; + startLimitIntervalSec = 0; serviceConfig = { DynamicUser = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/kresd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/kresd.nix index ccb34163d5f3..6f1c4c48b430 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/kresd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/kresd.nix @@ -23,18 +23,14 @@ let ''; configFile = pkgs.writeText "kresd.conf" ( - optionalString (cfg.listenDoH != []) '' - modules.load('http') - '' + "" + concatMapStrings (mkListen "dns") cfg.listenPlain + concatMapStrings (mkListen "tls") cfg.listenTLS - + concatMapStrings (mkListen "doh") cfg.listenDoH + + concatMapStrings (mkListen "doh2") cfg.listenDoH + cfg.extraConfig ); - package = if cfg.listenDoH == [] - then pkgs.knot-resolver # never force `extraFeatures = false` - else pkgs.knot-resolver.override { extraFeatures = true; }; + package = pkgs.knot-resolver; in { meta.maintainers = [ maintainers.vcunat /* upstream developer */ ]; @@ -92,7 +88,7 @@ in { default = []; example = [ "198.51.100.1:443" "[2001:db8::1]:443" "443" ]; description = '' - Addresses and ports on which kresd should provide DNS over HTTPS (see RFC 8484). + Addresses and ports on which kresd should provide DNS over HTTPS/2 (see RFC 8484). For detailed syntax see ListenStream in man systemd.socket. ''; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/morty.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/morty.nix index e3a6444c1163..e110a5c86101 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/morty.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/morty.nix @@ -29,9 +29,11 @@ in key = mkOption { type = types.str; default = ""; - description = "HMAC url validation key (hexadecimal encoded). - Leave blank to disable. Without validation key, anyone can - submit proxy requests. Leave blank to disable."; + description = '' + HMAC url validation key (hexadecimal encoded). + Leave blank to disable. Without validation key, anyone can + submit proxy requests. Leave blank to disable. + ''; defaultText = "No HMAC url validation. Generate with echo -n somevalue | openssl dgst -sha1 -hmac somekey"; }; @@ -85,10 +87,10 @@ in serviceConfig = { User = "morty"; ExecStart = ''${cfg.package}/bin/morty \ - -listen ${cfg.listenAddress}:${toString cfg.port} \ - ${optionalString cfg.ipv6 "-ipv6"} \ - ${optionalString (cfg.key != "") "-key " + cfg.key} \ - ''; + -listen ${cfg.listenAddress}:${toString cfg.port} \ + ${optionalString cfg.ipv6 "-ipv6"} \ + ${optionalString (cfg.key != "") "-key " + cfg.key} \ + ''; }; }; environment.systemPackages = [ cfg.package ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/mosquitto.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/mosquitto.nix index d2feb93e2b72..10b49d9b2206 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/mosquitto.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/mosquitto.nix @@ -123,12 +123,33 @@ in ''; }; + passwordFile = mkOption { + type = with types; uniq (nullOr str); + example = "/path/to/file"; + default = null; + description = '' + Specifies the path to a file containing the + clear text password for the MQTT user. + ''; + }; + hashedPassword = mkOption { type = with types; uniq (nullOr str); default = null; description = '' Specifies the hashed password for the MQTT User. - <option>hashedPassword</option> overrides <option>password</option>. + To generate hashed password install <literal>mosquitto</literal> + package and use <literal>mosquitto_passwd</literal>. + ''; + }; + + hashedPasswordFile = mkOption { + type = with types; uniq (nullOr str); + example = "/path/to/file"; + default = null; + description = '' + Specifies the path to a file containing the + hashed password for the MQTT user. To generate hashed password install <literal>mosquitto</literal> package and use <literal>mosquitto_passwd</literal>. ''; @@ -190,6 +211,13 @@ in config = mkIf cfg.enable { + assertions = mapAttrsToList (name: cfg: { + assertion = length (filter (s: s != null) (with cfg; [ + password passwordFile hashedPassword hashedPasswordFile + ])) <= 1; + message = "Cannot set more than one password option"; + }) cfg.users; + systemd.services.mosquitto = { description = "Mosquitto MQTT Broker Daemon"; wantedBy = [ "multi-user.target" ]; @@ -204,13 +232,27 @@ in Restart = "on-failure"; ExecStart = "${pkgs.mosquitto}/bin/mosquitto -c ${mosquittoConf}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; + + ProtectSystem = "strict"; + ProtectHome = true; + PrivateDevices = true; + PrivateTmp = true; + ReadWritePaths = "${cfg.dataDir}"; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + NoNewPrivileges = true; }; preStart = '' rm -f ${cfg.dataDir}/passwd touch ${cfg.dataDir}/passwd '' + concatStringsSep "\n" ( mapAttrsToList (n: c: - if c.hashedPassword != null then + if c.hashedPasswordFile != null then + "echo '${n}:'$(cat '${c.hashedPasswordFile}') >> ${cfg.dataDir}/passwd" + else if c.passwordFile != null then + "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} $(cat '${c.passwordFile}')" + else if c.hashedPassword != null then "echo '${n}:${c.hashedPassword}' >> ${cfg.dataDir}/passwd" else optionalString (c.password != null) "${pkgs.mosquitto}/bin/mosquitto_passwd -b ${cfg.dataDir}/passwd ${n} '${c.password}'" diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix index cc98414257ca..6f595ca4be2b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/mullvad-vpn.nix @@ -15,6 +15,9 @@ with lib; config = mkIf cfg.enable { boot.kernelModules = [ "tun" ]; + # mullvad-daemon writes to /etc/iproute2/rt_tables + networking.iproute2.enable = true; + systemd.services.mullvad-daemon = { description = "Mullvad VPN daemon"; wantedBy = [ "multi-user.target" ]; @@ -29,9 +32,9 @@ with lib; # Needed for ping "/run/wrappers" ]; + startLimitBurst = 5; + startLimitIntervalSec = 20; serviceConfig = { - StartLimitBurst = 5; - StartLimitIntervalSec = 20; ExecStart = "${pkgs.mullvad-vpn}/bin/mullvad-daemon -v --disable-stdout-timestamps"; Restart = "always"; RestartSec = 1; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/murmur.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/murmur.nix index b384f436861d..c6e5649ec479 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/murmur.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/murmur.nix @@ -278,6 +278,10 @@ in home = "/var/lib/murmur"; createHome = true; uid = config.ids.uids.murmur; + group = "murmur"; + }; + users.groups.murmur = { + gid = config.ids.gids.murmur; }; systemd.services.murmur = { @@ -300,6 +304,7 @@ in RuntimeDirectory = "murmur"; RuntimeDirectoryMode = "0700"; User = "murmur"; + Group = "murmur"; }; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/namecoind.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/namecoind.nix index 16f85df2e77c..4966ed2cac8d 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/namecoind.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/namecoind.nix @@ -165,6 +165,8 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; + startLimitIntervalSec = 120; + startLimitBurst = 5; serviceConfig = { User = "namecoin"; Group = "namecoin"; @@ -176,8 +178,6 @@ in TimeoutStopSec = "60s"; TimeoutStartSec = "2s"; Restart = "always"; - StartLimitInterval = "120s"; - StartLimitBurst = "5"; }; preStart = optionalString (cfg.wallet != "${dataDir}/wallet.dat") '' diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nar-serve.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nar-serve.nix new file mode 100644 index 000000000000..ddd42fa01073 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nar-serve.nix @@ -0,0 +1,55 @@ +{ config, pkgs, lib, ... }: + +with lib; +let + cfg = config.services.nar-serve; +in +{ + meta = { + maintainers = [ maintainers.rizary ]; + }; + options = { + services.nar-serve = { + enable = mkEnableOption "Serve NAR file contents via HTTP"; + + port = mkOption { + type = types.int; + default = 8383; + description = '' + Port number where nar-serve will listen on. + ''; + }; + + cacheURL = mkOption { + type = types.str; + default = "https://cache.nixos.org/"; + description = '' + Binary cache URL to connect to. + + The URL format is compatible with the nix remote url style, such as: + - http://, https:// for binary caches via HTTP or HTTPS + - s3:// for binary caches stored in Amazon S3 + - gs:// for binary caches stored in Google Cloud Storage + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.nar-serve = { + description = "NAR server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment.PORT = toString cfg.port; + environment.NAR_CACHE_URL = cfg.cacheURL; + + serviceConfig = { + Restart = "always"; + RestartSec = "5s"; + ExecStart = "${pkgs.nar-serve}/bin/nar-serve"; + DynamicUser = true; + }; + }; + }; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix index 21ae9eb8b6d4..45eb500fe8ce 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix @@ -9,7 +9,14 @@ with lib; let cfg = config.networking.nat; - dest = if cfg.externalIP == null then "-j MASQUERADE" else "-j SNAT --to-source ${cfg.externalIP}"; + mkDest = externalIP: if externalIP == null + then "-j MASQUERADE" + else "-j SNAT --to-source ${externalIP}"; + dest = mkDest cfg.externalIP; + destIPv6 = mkDest cfg.externalIPv6; + + # Whether given IP (plus optional port) is an IPv6. + isIPv6 = ip: builtins.length (lib.splitString ":" ip) > 2; helpers = import ./helpers.nix { inherit config lib; }; @@ -28,63 +35,80 @@ let ${cfg.extraStopCommands} ''; - setupNat = '' - ${helpers} - # Create subchain where we store rules - ip46tables -w -t nat -N nixos-nat-pre - ip46tables -w -t nat -N nixos-nat-post - ip46tables -w -t nat -N nixos-nat-out - + mkSetupNat = { iptables, dest, internalIPs, forwardPorts }: '' # We can't match on incoming interface in POSTROUTING, so # mark packets coming from the internal interfaces. ${concatMapStrings (iface: '' - iptables -w -t nat -A nixos-nat-pre \ + ${iptables} -w -t nat -A nixos-nat-pre \ -i '${iface}' -j MARK --set-mark 1 '') cfg.internalInterfaces} # NAT the marked packets. ${optionalString (cfg.internalInterfaces != []) '' - iptables -w -t nat -A nixos-nat-post -m mark --mark 1 \ + ${iptables} -w -t nat -A nixos-nat-post -m mark --mark 1 \ ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest} ''} # NAT packets coming from the internal IPs. ${concatMapStrings (range: '' - iptables -w -t nat -A nixos-nat-post \ + ${iptables} -w -t nat -A nixos-nat-post \ -s '${range}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest} - '') cfg.internalIPs} + '') internalIPs} # NAT from external ports to internal ports. ${concatMapStrings (fwd: '' - iptables -w -t nat -A nixos-nat-pre \ + ${iptables} -w -t nat -A nixos-nat-pre \ -i ${toString cfg.externalInterface} -p ${fwd.proto} \ --dport ${builtins.toString fwd.sourcePort} \ -j DNAT --to-destination ${fwd.destination} ${concatMapStrings (loopbackip: let - m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination; - destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0; - destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1); + matchIP = if isIPv6 fwd.destination then "[[]([0-9a-fA-F:]+)[]]" else "([0-9.]+)"; + m = builtins.match "${matchIP}:([0-9-]+)" fwd.destination; + destinationIP = if m == null then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0; + destinationPorts = if m == null then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1); in '' # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself - iptables -w -t nat -A nixos-nat-out \ + ${iptables} -w -t nat -A nixos-nat-out \ -d ${loopbackip} -p ${fwd.proto} \ --dport ${builtins.toString fwd.sourcePort} \ -j DNAT --to-destination ${fwd.destination} # Allow connections to ${loopbackip}:${toString fwd.sourcePort} from other hosts behind NAT - iptables -w -t nat -A nixos-nat-pre \ + ${iptables} -w -t nat -A nixos-nat-pre \ -d ${loopbackip} -p ${fwd.proto} \ --dport ${builtins.toString fwd.sourcePort} \ -j DNAT --to-destination ${fwd.destination} - iptables -w -t nat -A nixos-nat-post \ + ${iptables} -w -t nat -A nixos-nat-post \ -d ${destinationIP} -p ${fwd.proto} \ --dport ${destinationPorts} \ -j SNAT --to-source ${loopbackip} '') fwd.loopbackIPs} - '') cfg.forwardPorts} + '') forwardPorts} + ''; + + setupNat = '' + ${helpers} + # Create subchains where we store rules + ip46tables -w -t nat -N nixos-nat-pre + ip46tables -w -t nat -N nixos-nat-post + ip46tables -w -t nat -N nixos-nat-out + + ${mkSetupNat { + iptables = "iptables"; + inherit dest; + inherit (cfg) internalIPs; + forwardPorts = filter (x: !(isIPv6 x.destination)) cfg.forwardPorts; + }} + + ${optionalString cfg.enableIPv6 (mkSetupNat { + iptables = "ip6tables"; + dest = destIPv6; + internalIPs = cfg.internalIPv6s; + forwardPorts = filter (x: isIPv6 x.destination) cfg.forwardPorts; + })} ${optionalString (cfg.dmzHost != null) '' iptables -w -t nat -A nixos-nat-pre \ @@ -117,6 +141,15 @@ in ''; }; + networking.nat.enableIPv6 = mkOption { + type = types.bool; + default = false; + description = + '' + Whether to enable IPv6 NAT. + ''; + }; + networking.nat.internalInterfaces = mkOption { type = types.listOf types.str; default = []; @@ -141,6 +174,18 @@ in ''; }; + networking.nat.internalIPv6s = mkOption { + type = types.listOf types.str; + default = []; + example = [ "fc00::/64" ]; + description = + '' + The IPv6 address ranges for which to perform NAT. Packets + coming from these addresses (on any interface) and destined + for the external interface will be rewritten. + ''; + }; + networking.nat.externalInterface = mkOption { type = types.nullOr types.str; default = null; @@ -164,6 +209,19 @@ in ''; }; + networking.nat.externalIPv6 = mkOption { + type = types.nullOr types.str; + default = null; + example = "2001:dc0:2001:11::175"; + description = + '' + The public IPv6 address to which packets from the local + network are to be rewritten. If this is left empty, the + IP address associated with the external interface will be + used. + ''; + }; + networking.nat.forwardPorts = mkOption { type = with types; listOf (submodule { options = { @@ -176,7 +234,7 @@ in destination = mkOption { type = types.str; example = "10.0.0.1:80"; - description = "Forward connection to destination ip:port; to specify a port range, use ip:start-end"; + description = "Forward connection to destination ip:port (or [ipv6]:port); to specify a port range, use ip:start-end"; }; proto = mkOption { @@ -195,11 +253,15 @@ in }; }); default = []; - example = [ { sourcePort = 8080; destination = "10.0.0.1:80"; proto = "tcp"; } ]; + example = [ + { sourcePort = 8080; destination = "10.0.0.1:80"; proto = "tcp"; } + { sourcePort = 8080; destination = "[fc00::2]:80"; proto = "tcp"; } + ]; description = '' List of forwarded ports from the external interface to - internal destinations by using DNAT. + internal destinations by using DNAT. Destination can be + IPv6 if IPv6 NAT is enabled. ''; }; @@ -246,6 +308,9 @@ in (mkIf config.networking.nat.enable { assertions = [ + { assertion = cfg.enableIPv6 -> config.networking.enableIPv6; + message = "networking.nat.enableIPv6 requires networking.enableIPv6"; + } { assertion = (cfg.dmzHost != null) -> (cfg.externalInterface != null); message = "networking.nat.dmzHost requires networking.nat.externalInterface"; } @@ -261,6 +326,15 @@ in kernel.sysctl = { "net.ipv4.conf.all.forwarding" = mkOverride 99 true; "net.ipv4.conf.default.forwarding" = mkOverride 99 true; + } // optionalAttrs cfg.enableIPv6 { + # Do not prevent IPv6 autoconfiguration. + # See <http://strugglers.net/~andy/blog/2011/09/04/linux-ipv6-router-advertisements-and-forwarding/>. + "net.ipv6.conf.all.accept_ra" = mkOverride 99 2; + "net.ipv6.conf.default.accept_ra" = mkOverride 99 2; + + # Forward IPv6 packets. + "net.ipv6.conf.all.forwarding" = mkOverride 99 true; + "net.ipv6.conf.default.forwarding" = mkOverride 99 true; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/networkmanager.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/networkmanager.nix index 17c549d42c32..2e680544ec24 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/networkmanager.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/networkmanager.nix @@ -15,6 +15,7 @@ let networkmanager-openconnect networkmanager-openvpn networkmanager-vpnc + networkmanager-sstp ] ++ optional (!delegateWireless && !enableIwd) wpa_supplicant; delegateWireless = config.networking.wireless.enable == true && cfg.unmanaged != []; @@ -386,6 +387,9 @@ in { "NetworkManager/VPN/nm-iodine-service.name".source = "${networkmanager-iodine}/lib/NetworkManager/VPN/nm-iodine-service.name"; + + "NetworkManager/VPN/nm-sstp-service.name".source = + "${networkmanager-sstp}/lib/NetworkManager/VPN/nm-sstp-service.name"; } // optionalAttrs (cfg.appendNameservers != [] || cfg.insertNameservers != []) { @@ -461,7 +465,7 @@ in { restartTriggers = [ configFile overrideNameserversScript ]; # useful binaries for user-specified hooks - path = [ pkgs.iproute pkgs.utillinux pkgs.coreutils ]; + path = [ pkgs.iproute pkgs.util-linux pkgs.coreutils ]; aliases = [ "dbus-org.freedesktop.nm-dispatcher.service" ]; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nextdns.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nextdns.nix index a633bff62ec7..b070eeec894f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nextdns.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nextdns.nix @@ -28,9 +28,9 @@ in { environment = { SERVICE_RUN_MODE = "1"; }; + startLimitIntervalSec = 5; + startLimitBurst = 10; serviceConfig = { - StartLimitInterval = 5; - StartLimitBurst = 10; ExecStart = "${pkgs.nextdns}/bin/nextdns run ${escapeShellArgs config.services.nextdns.arguments}"; RestartSec = 120; LimitMEMLOCK = "infinity"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix index 3f2ce5bca4da..0012302db2e3 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nix-store-gcs-proxy.nix @@ -42,9 +42,9 @@ in description = "A HTTP nix store that proxies requests to Google Storage"; wantedBy = ["multi-user.target"]; + startLimitIntervalSec = 10; serviceConfig = { RestartSec = 5; - StartLimitInterval = 10; ExecStart = '' ${pkgs.nix-store-gcs-proxy}/bin/nix-store-gcs-proxy \ --bucket-name ${cfg.bucketName} \ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nsd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nsd.nix index 3ecbd06ee416..f33c350a257a 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nsd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nsd.nix @@ -916,14 +916,14 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; + startLimitBurst = 4; + startLimitIntervalSec = 5 * 60; # 5 mins serviceConfig = { ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf"; StandardError = "null"; PIDFile = pidFile; Restart = "always"; RestartSec = "4s"; - StartLimitBurst = 4; - StartLimitInterval = "5min"; }; preStart = '' diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix index 78de50583f34..e6fa48daf46c 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/ntp/chrony.nix @@ -6,6 +6,7 @@ let cfg = config.services.chrony; stateDir = "/var/lib/chrony"; + driftFile = "${stateDir}/chrony.drift"; keyFile = "${stateDir}/chrony.keys"; configFile = pkgs.writeText "chrony.conf" '' @@ -16,7 +17,7 @@ let "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.servers}" } - driftfile ${stateDir}/chrony.drift + driftfile ${driftFile} keyfile ${keyFile} ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"} @@ -95,6 +96,7 @@ in systemd.tmpfiles.rules = [ "d ${stateDir} 0755 chrony chrony - -" + "f ${driftFile} 0640 chrony chrony -" "f ${keyFile} 0640 chrony chrony -" ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix index 6ff181377fcc..a326eccfd65d 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/pdns-recursor.nix @@ -3,9 +3,6 @@ with lib; let - dataDir = "/var/lib/pdns-recursor"; - username = "pdns-recursor"; - cfg = config.services.pdns-recursor; oneOrMore = type: with types; either type (listOf type); @@ -21,7 +18,7 @@ let else if builtins.isList val then (concatMapStringsSep "," serialize val) else ""; - configFile = pkgs.writeText "recursor.conf" + configDir = pkgs.writeTextDir "recursor.conf" (concatStringsSep "\n" (flip mapAttrsToList cfg.settings (name: val: "${name}=${serialize val}"))); @@ -173,45 +170,30 @@ in { serve-rfc1918 = cfg.serveRFC1918; lua-config-file = pkgs.writeText "recursor.lua" cfg.luaConfig; + daemon = false; + write-pid = false; log-timestamp = false; disable-syslog = true; }; - users.users.${username} = { - home = dataDir; - createHome = true; - uid = config.ids.uids.pdns-recursor; - description = "PowerDNS Recursor daemon user"; - }; + systemd.packages = [ pkgs.pdns-recursor ]; systemd.services.pdns-recursor = { - unitConfig.Documentation = "man:pdns_recursor(1) man:rec_control(1)"; - description = "PowerDNS recursive server"; wantedBy = [ "multi-user.target" ]; - after = [ "network.target" ]; serviceConfig = { - User = username; - Restart ="on-failure"; - RestartSec = "5"; - PrivateTmp = true; - PrivateDevices = true; - AmbientCapabilities = "cap_net_bind_service"; - ExecStart = ''${pkgs.pdns-recursor}/bin/pdns_recursor \ - --config-dir=${dataDir} \ - --socket-dir=${dataDir} - ''; + ExecStart = [ "" "${pkgs.pdns-recursor}/bin/pdns_recursor --config-dir=${configDir}" ]; }; + }; - preStart = '' - # Link configuration file into recursor home directory - configPath=${dataDir}/recursor.conf - if [ "$(realpath $configPath)" != "${configFile}" ]; then - rm -f $configPath - ln -s ${configFile} $configPath - fi - ''; + users.users.pdns-recursor = { + isSystemUser = true; + group = "pdns-recursor"; + description = "PowerDNS Recursor daemon user"; }; + + users.groups.pdns-recursor = {}; + }; imports = [ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/powerdns.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/powerdns.nix index ba05e15389f6..8cae61b83543 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/powerdns.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/powerdns.nix @@ -8,42 +8,40 @@ let in { options = { services.powerdns = { - enable = mkEnableOption "Powerdns domain name server"; + enable = mkEnableOption "PowerDNS domain name server"; extraConfig = mkOption { type = types.lines; default = "launch=bind"; description = '' - Extra lines to be added verbatim to pdns.conf. - Powerdns will chroot to /var/lib/powerdns. - So any file, powerdns is supposed to be read, - should be in /var/lib/powerdns and needs to specified - relative to the chroot. + PowerDNS configuration. Refer to + <link xlink:href="https://doc.powerdns.com/authoritative/settings.html"/> + for details on supported values. ''; }; }; }; - config = mkIf config.services.powerdns.enable { + config = mkIf cfg.enable { + + systemd.packages = [ pkgs.powerdns ]; + systemd.services.pdns = { - unitConfig.Documentation = "man:pdns_server(1) man:pdns_control(1)"; - description = "Powerdns name server"; wantedBy = [ "multi-user.target" ]; - after = ["network.target" "mysql.service" "postgresql.service" "openldap.service"]; + after = [ "network.target" "mysql.service" "postgresql.service" "openldap.service" ]; serviceConfig = { - Restart="on-failure"; - RestartSec="1"; - StartLimitInterval="0"; - PrivateDevices=true; - CapabilityBoundingSet="CAP_CHOWN CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT"; - NoNewPrivileges=true; - ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/powerdns"; - ExecStart = "${pkgs.powerdns}/bin/pdns_server --setuid=nobody --setgid=nogroup --chroot=/var/lib/powerdns --socket-dir=/ --daemon=no --guardian=no --disable-syslog --write-pid=no --config-dir=${configDir}"; - ProtectSystem="full"; - ProtectHome=true; - RestrictAddressFamilies="AF_UNIX AF_INET AF_INET6"; + ExecStart = [ "" "${pkgs.powerdns}/bin/pdns_server --config-dir=${configDir} --guardian=no --daemon=no --disable-syslog --log-timestamp=no --write-pid=no" ]; }; }; + + users.users.pdns = { + isSystemUser = true; + group = "pdns"; + description = "PowerDNS"; + }; + + users.groups.pdns = {}; + }; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/prosody.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/prosody.nix index a6c1cb0f4797..e7a7aa700be6 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/prosody.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/prosody.nix @@ -261,7 +261,7 @@ let toLua = x: if builtins.isString x then ''"${x}"'' - else if builtins.isBool x then (if x == true then "true" else "false") + else if builtins.isBool x then boolToString x else if builtins.isInt x then toString x else if builtins.isList x then ''{ ${lib.concatStringsSep ", " (map (n: toLua n) x) } }'' else throw "Invalid Lua value"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix index 5365b8b9b107..3cc77e4cb938 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/ssh/sshd.nix @@ -269,6 +269,7 @@ in kexAlgorithms = mkOption { type = types.listOf types.str; default = [ + "curve25519-sha256" "curve25519-sha256@libssh.org" "diffie-hellman-group-exchange-sha256" ]; @@ -279,7 +280,7 @@ in Defaults to recommended settings from both <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" /> and - <link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" /> + <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" /> ''; }; @@ -300,7 +301,7 @@ in Defaults to recommended settings from both <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" /> and - <link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" /> + <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" /> ''; }; @@ -321,7 +322,7 @@ in Defaults to recommended settings from both <link xlink:href="https://stribika.github.io/2015/01/04/secure-secure-shell.html" /> and - <link xlink:href="https://wiki.mozilla.org/Security/Guidelines/OpenSSH#Modern_.28OpenSSH_6.7.2B.29" /> + <link xlink:href="https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67" /> ''; }; @@ -476,7 +477,7 @@ in # https://github.com/NixOS/nixpkgs/pull/10155 # https://github.com/NixOS/nixpkgs/pull/41745 services.openssh.authorizedKeysFiles = - [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ]; + [ "%h/.ssh/authorized_keys" "%h/.ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ]; services.openssh.extraConfig = mkOrder 0 '' diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/sslh.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/sslh.nix index 0921febba668..4c2740d20192 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/sslh.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/sslh.nix @@ -31,7 +31,7 @@ let { name: "openvpn"; host: "localhost"; port: "1194"; probe: "builtin"; }, { name: "xmpp"; host: "localhost"; port: "5222"; probe: "builtin"; }, { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; }, - { name: "ssl"; host: "localhost"; port: "443"; probe: "builtin"; }, + { name: "tls"; host: "localhost"; port: "443"; probe: "builtin"; }, { name: "anyprot"; host: "localhost"; port: "443"; probe: "builtin"; } ); ''; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix index 0fec3ef00ad9..f67eedac2961 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/module.nix @@ -63,7 +63,7 @@ in { description = "strongSwan IPsec IKEv1/IKEv2 daemon using swanctl"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; - path = with pkgs; [ kmod iproute iptables utillinux ]; + path = with pkgs; [ kmod iproute iptables util-linux ]; environment = { STRONGSWAN_CONF = pkgs.writeTextFile { name = "strongswan.conf"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix index 808cb863a9cf..1d1e0bd1ca19 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan-swanctl/swanctl-params.nix @@ -1173,20 +1173,20 @@ in { ppk = mkPrefixedAttrsOfParams { secret = mkOptionalStrParam '' - Value of the PPK. It may either be an ASCII string, a hex encoded string - if it has a <literal>0x</literal> prefix or a Base64 encoded string if - it has a <literal>0s</literal> prefix in its value. Should have at least - 256 bits of entropy for 128-bit security. + Value of the PPK. It may either be an ASCII string, a hex encoded string + if it has a <literal>0x</literal> prefix or a Base64 encoded string if + it has a <literal>0s</literal> prefix in its value. Should have at least + 256 bits of entropy for 128-bit security. ''; id = mkPrefixedAttrsOfParam (mkOptionalStrParam "") '' - PPK identity the PPK belongs to. Multiple unique identities may be - specified, each having an <literal>id</literal> prefix, if a secret is - shared between multiple peers. + PPK identity the PPK belongs to. Multiple unique identities may be + specified, each having an <literal>id</literal> prefix, if a secret is + shared between multiple peers. ''; } '' - Postquantum Preshared Key (PPK) section for a specific secret. Each PPK is - defined in a unique section having the <literal>ppk</literal> prefix. + Postquantum Preshared Key (PPK) section for a specific secret. Each PPK is + defined in a unique section having the <literal>ppk</literal> prefix. ''; private = mkPrefixedAttrsOfParams { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan.nix index 13a1a897c5ed..f6170b813654 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/strongswan.nix @@ -152,7 +152,7 @@ in systemd.services.strongswan = { description = "strongSwan IPSec Service"; wantedBy = [ "multi-user.target" ]; - path = with pkgs; [ kmod iproute iptables utillinux ]; # XXX Linux + path = with pkgs; [ kmod iproute iptables util-linux ]; # XXX Linux after = [ "network-online.target" ]; environment = { STRONGSWAN_CONF = strongswanConf { inherit setup connections ca secretsFile managePlugins enabledPlugins; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/stunnel.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/stunnel.nix index ab51bba2f6ac..fe1616f411f0 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/stunnel.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/stunnel.nix @@ -16,8 +16,12 @@ let serverConfig = { options = { accept = mkOption { - type = types.int; - description = "On which port stunnel should listen for incoming TLS connections."; + type = types.either types.str types.int; + description = '' + On which [host:]port stunnel should listen for incoming TLS connections. + Note that unlike other softwares stunnel ipv6 address need no brackets, + so to listen on all IPv6 addresses on port 1234 one would use ':::1234'. + ''; }; connect = mkOption { @@ -129,7 +133,6 @@ in type = with types; attrsOf (submodule serverConfig); example = { fancyWebserver = { - enable = true; accept = 443; connect = 8080; cert = "/path/to/pem/file"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/supybot.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/supybot.nix index dc9fb31ffd0b..7a62e04ec7c4 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/supybot.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/supybot.nix @@ -103,6 +103,8 @@ in rm -f '${cfg.stateDir}/supybot.cfg.bak' ''; + startLimitIntervalSec = 5 * 60; # 5 min + startLimitBurst = 1; serviceConfig = { ExecStart = "${pyEnv}/bin/supybot ${cfg.stateDir}/supybot.cfg"; PIDFile = "/run/supybot.pid"; @@ -110,8 +112,6 @@ in Group = "supybot"; UMask = "0007"; Restart = "on-abort"; - StartLimitInterval = "5m"; - StartLimitBurst = "1"; NoNewPrivileges = true; PrivateDevices = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/tailscale.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/tailscale.nix index 4d6aeb75ebd1..1a1474595beb 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/tailscale.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/tailscale.nix @@ -14,36 +14,21 @@ in { default = 41641; description = "The port to listen on for tunnel traffic (0=autoselect)."; }; + + package = mkOption { + type = types.package; + default = pkgs.tailscale; + defaultText = "pkgs.tailscale"; + description = "The package to use for tailscale"; + }; }; config = mkIf cfg.enable { - systemd.services.tailscale = { - description = "Tailscale client daemon"; - - after = [ "network-pre.target" ]; - wants = [ "network-pre.target" ]; + environment.systemPackages = [ cfg.package ]; # for the CLI + systemd.packages = [ cfg.package ]; + systemd.services.tailscaled = { wantedBy = [ "multi-user.target" ]; - - unitConfig = { - StartLimitIntervalSec = 0; - StartLimitBurst = 0; - }; - - serviceConfig = { - ExecStart = - "${pkgs.tailscale}/bin/tailscaled --port ${toString cfg.port}"; - - RuntimeDirectory = "tailscale"; - RuntimeDirectoryMode = 755; - - StateDirectory = "tailscale"; - StateDirectoryMode = 750; - - CacheDirectory = "tailscale"; - CacheDirectoryMode = 750; - - Restart = "on-failure"; - }; + serviceConfig.Environment = "PORT=${toString cfg.port}"; }; }; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/unbound.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/unbound.nix index baed83591e1e..9a46fa3075fa 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/unbound.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/unbound.nix @@ -1,9 +1,7 @@ { config, lib, pkgs, ... }: with lib; - let - cfg = config.services.unbound; stateDir = "/var/lib/unbound"; @@ -17,12 +15,12 @@ let forward = optionalString (any isLocalAddress cfg.forwardAddresses) '' do-not-query-localhost: no - '' + - optionalString (cfg.forwardAddresses != []) '' + '' + + optionalString (cfg.forwardAddresses != []) '' forward-zone: name: . - '' + - concatMapStringsSep "\n" (x: " forward-addr: ${x}") cfg.forwardAddresses; + '' + + concatMapStringsSep "\n" (x: " forward-addr: ${x}") cfg.forwardAddresses; rootTrustAnchorFile = "${stateDir}/root.key"; @@ -31,19 +29,25 @@ let confFile = pkgs.writeText "unbound.conf" '' server: + ip-freebind: yes directory: "${stateDir}" username: unbound - chroot: "${stateDir}" + chroot: "" pidfile: "" + # when running under systemd there is no need to daemonize + do-daemonize: no ${interfaces} ${access} ${trustAnchor} + ${lib.optionalString (cfg.localControlSocketPath != null) '' + remote-control: + control-enable: yes + control-interface: ${cfg.localControlSocketPath} + ''} ${cfg.extraConfig} ${forward} ''; - in - { ###### interface @@ -55,8 +59,8 @@ in package = mkOption { type = types.package; - default = pkgs.unbound; - defaultText = "pkgs.unbound"; + default = pkgs.unbound-with-systemd; + defaultText = "pkgs.unbound-with-systemd"; description = "The unbound package to use"; }; @@ -69,11 +73,14 @@ in interfaces = mkOption { default = [ "127.0.0.1" ] ++ optional config.networking.enableIPv6 "::1"; type = types.listOf types.str; - description = "What addresses the server should listen on."; + description = '' + What addresses the server should listen on. This supports the interface syntax documented in + <citerefentry><refentrytitle>unbound.conf</refentrytitle><manvolnum>8</manvolnum></citerefentry>. + ''; }; forwardAddresses = mkOption { - default = [ ]; + default = []; type = types.listOf types.str; description = "What servers to forward queries to."; }; @@ -84,6 +91,28 @@ in description = "Use and update root trust anchor for DNSSEC validation."; }; + localControlSocketPath = mkOption { + default = null; + # FIXME: What is the proper type here so users can specify strings, + # paths and null? + # My guess would be `types.nullOr (types.either types.str types.path)` + # but I haven't verified yet. + type = types.nullOr types.str; + example = "/run/unbound/unbound.ctl"; + description = '' + When not set to <literal>null</literal> this option defines the path + at which the unbound remote control socket should be created at. The + socket will be owned by the unbound user (<literal>unbound</literal>) + and group will be <literal>nogroup</literal>. + + Users that should be permitted to access the socket must be in the + <literal>unbound</literal> group. + + If this option is <literal>null</literal> remote control will not be + configured at all. Unbounds default values apply. + ''; + }; + extraConfig = mkOption { default = ""; type = types.lines; @@ -106,43 +135,85 @@ in users.users.unbound = { description = "unbound daemon user"; isSystemUser = true; + group = lib.mkIf (cfg.localControlSocketPath != null) (lib.mkDefault "unbound"); + }; + + # We need a group so that we can give users access to the configured + # control socket. Unbound allows access to the socket only to the unbound + # user and the primary group. + users.groups = lib.mkIf (cfg.localControlSocketPath != null) { + unbound = {}; }; networking.resolvconf.useLocalResolver = mkDefault true; + + environment.etc."unbound/unbound.conf".source = confFile; + systemd.services.unbound = { description = "Unbound recursive Domain Name Server"; after = [ "network.target" ]; before = [ "nss-lookup.target" ]; - wants = [ "nss-lookup.target" ]; - wantedBy = [ "multi-user.target" ]; - - preStart = '' - mkdir -m 0755 -p ${stateDir}/dev/ - cp ${confFile} ${stateDir}/unbound.conf - ${optionalString cfg.enableRootTrustAnchor '' - ${cfg.package}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!" - chown unbound ${stateDir} ${rootTrustAnchorFile} - ''} - touch ${stateDir}/dev/random - ${pkgs.utillinux}/bin/mount --bind -n /dev/urandom ${stateDir}/dev/random + wantedBy = [ "multi-user.target" "nss-lookup.target" ]; + + preStart = lib.mkIf cfg.enableRootTrustAnchor '' + ${cfg.package}/bin/unbound-anchor -a ${rootTrustAnchorFile} || echo "Root anchor updated!" ''; - serviceConfig = { - ExecStart = "${cfg.package}/bin/unbound -d -c ${stateDir}/unbound.conf"; - ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random"; + restartTriggers = [ + confFile + ]; - ProtectSystem = true; - ProtectHome = true; + serviceConfig = { + ExecStart = "${cfg.package}/bin/unbound -p -d -c /etc/unbound/unbound.conf"; + ExecReload = "+/run/current-system/sw/bin/kill -HUP $MAINPID"; + + NotifyAccess = "main"; + Type = "notify"; + + # FIXME: Which of these do we actualy need, can we drop the chroot flag? + AmbientCapabilities = [ + "CAP_NET_BIND_SERVICE" + "CAP_NET_RAW" + "CAP_SETGID" + "CAP_SETUID" + "CAP_SYS_CHROOT" + "CAP_SYS_RESOURCE" + ]; + + User = "unbound"; + Group = lib.mkIf (cfg.localControlSocketPath != null) (lib.mkDefault "unbound"); + + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; PrivateDevices = true; - Restart = "always"; - RestartSec = "5s"; + PrivateTmp = true; + ProtectHome = true; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectSystem = "strict"; + RuntimeDirectory = "unbound"; + ConfigurationDirectory = "unbound"; + StateDirectory = "unbound"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "~@clock" + "@cpu-emulation" + "@debug" + "@keyring" + "@module" + "mount" + "@obsolete" + "@resources" + ]; + RestrictNamespaces = true; + LockPersonality = true; + RestrictSUIDSGID = true; }; }; - # If networkmanager is enabled, ask it to interface with unbound. networking.networkmanager.dns = "unbound"; - }; - } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/wasabibackend.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/wasabibackend.nix index 6eacffe709b0..8482823e197f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/wasabibackend.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/wasabibackend.nix @@ -21,7 +21,7 @@ let RegTestBitcoinCoreRpcEndPoint = "${cfg.rpc.ip}:${toString cfg.rpc.port}"; }; - configFile = pkgs.writeText "wasabibackend.conf" (builtins.toJSON confOptions); + configFile = pkgs.writeText "wasabibackend.conf" (builtins.toJSON confOptions); in { diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/security/fail2ban.nix b/infra/libkookie/nixpkgs/nixos/modules/services/security/fail2ban.nix index 3f84f9c2560c..cf0d72d5c531 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/security/fail2ban.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/security/fail2ban.nix @@ -282,12 +282,12 @@ in services.fail2ban.jails.DEFAULT = '' ${optionalString cfg.bantime-increment.enable '' # Bantime incremental - bantime.increment = ${if cfg.bantime-increment.enable then "true" else "false"} + bantime.increment = ${boolToString cfg.bantime-increment.enable} bantime.maxtime = ${cfg.bantime-increment.maxtime} bantime.factor = ${cfg.bantime-increment.factor} bantime.formula = ${cfg.bantime-increment.formula} bantime.multipliers = ${cfg.bantime-increment.multipliers} - bantime.overalljails = ${if cfg.bantime-increment.overalljails then "true" else "false"} + bantime.overalljails = ${boolToString cfg.bantime-increment.overalljails} ''} # Miscellaneous options ignoreip = 127.0.0.1/8 ${optionalString config.networking.enableIPv6 "::1"} ${concatStringsSep " " cfg.ignoreIP} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix b/infra/libkookie/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix index 2f9e94bd77ba..486f3ab05386 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/security/oauth2_proxy.nix @@ -448,7 +448,7 @@ in default = false; description = '' In case when running behind a reverse proxy, controls whether headers - like <literal>X-Real-Ip</literal> are accepted. Usage behind a reverse + like <literal>X-Real-Ip</literal> are accepted. Usage behind a reverse proxy will require this flag to be set to avoid logging the reverse proxy IP address. ''; @@ -524,7 +524,7 @@ in type = types.nullOr types.str; default = null; description = '' - Profile access endpoint. + Profile access endpoint. ''; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/security/usbguard.nix b/infra/libkookie/nixpkgs/nixos/modules/services/security/usbguard.nix index 16a90da52314..71fd71a2cab2 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/security/usbguard.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/security/usbguard.nix @@ -19,13 +19,13 @@ let PresentDevicePolicy=${cfg.presentDevicePolicy} PresentControllerPolicy=${cfg.presentControllerPolicy} InsertedDevicePolicy=${cfg.insertedDevicePolicy} - RestoreControllerDeviceState=${if cfg.restoreControllerDeviceState then "true" else "false"} + RestoreControllerDeviceState=${boolToString cfg.restoreControllerDeviceState} # this does not seem useful for endusers to change DeviceManagerBackend=uevent IPCAllowedUsers=${concatStringsSep " " cfg.IPCAllowedUsers} IPCAllowedGroups=${concatStringsSep " " cfg.IPCAllowedGroups} IPCAccessControlFiles=/var/lib/usbguard/IPCAccessControl.d/ - DeviceRulesWithPort=${if cfg.deviceRulesWithPort then "true" else "false"} + DeviceRulesWithPort=${boolToString cfg.deviceRulesWithPort} # HACK: that way audit logs still land in the journal AuditFilePath=/dev/null ''; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/security/vault.nix b/infra/libkookie/nixpkgs/nixos/modules/services/security/vault.nix index 6a8a3a93327e..64622454b9de 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/security/vault.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/security/vault.nix @@ -131,6 +131,8 @@ in restartIfChanged = false; # do not restart on "nixos-rebuild switch". It would seal the storage and disrupt the clients. + startLimitIntervalSec = 60; + startLimitBurst = 3; serviceConfig = { User = "vault"; Group = "vault"; @@ -145,8 +147,6 @@ in KillSignal = "SIGINT"; TimeoutStopSec = "30s"; Restart = "on-failure"; - StartLimitInterval = "60s"; - StartLimitBurst = 3; }; unitConfig.RequiresMountsFor = optional (cfg.storagePath != null) cfg.storagePath; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/system/cloud-init.nix b/infra/libkookie/nixpkgs/nixos/modules/services/system/cloud-init.nix index 15fe822aec67..3518e0ee9dca 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/system/cloud-init.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/system/cloud-init.nix @@ -9,7 +9,7 @@ let cfg = config.services.cloud-init; nettools openssh shadow - utillinux + util-linux ] ++ optional cfg.btrfs.enable btrfs-progs ++ optional cfg.ext4.enable e2fsprogs ; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/system/dbus.nix b/infra/libkookie/nixpkgs/nixos/modules/services/system/dbus.nix index d9dd26f0f189..d4cacb85694b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/system/dbus.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/system/dbus.nix @@ -1,6 +1,6 @@ # D-Bus configuration and system bus daemon. -{ config, lib, pkgs, ... }: +{ config, lib, options, pkgs, ... }: with lib; @@ -11,6 +11,7 @@ let homeDir = "/run/dbus"; configDir = pkgs.makeDBusConf { + inherit (cfg) apparmor; suidHelper = "${config.security.wrapperDir}/dbus-daemon-launch-helper"; serviceDirectories = cfg.packages; }; @@ -18,13 +19,6 @@ let in { - - imports = [ - (mkRemovedOptionModule - [ "services" "dbus" "socketActivated" ] - "The user D-Bus session is now always socket activated and this option can safely be removed.") - ]; - ###### interface options = { @@ -57,12 +51,43 @@ in <filename><replaceable>pkg</replaceable>/share/dbus-1/services</filename> ''; }; + + apparmor = mkOption { + type = types.enum [ "enabled" "disabled" "required" ]; + description = '' + AppArmor mode for dbus. + + <literal>enabled</literal> enables mediation when it's + supported in the kernel, <literal>disabled</literal> + always disables AppArmor even with kernel support, and + <literal>required</literal> fails when AppArmor was not found + in the kernel. + ''; + default = "disabled"; + }; + + socketActivated = mkOption { + type = types.nullOr types.bool; + default = null; + visible = false; + description = '' + Removed option, do not use. + ''; + }; }; }; ###### implementation config = mkIf cfg.enable { + warnings = optional (cfg.socketActivated != null) ( + let + files = showFiles options.services.dbus.socketActivated.files; + in + "The option 'services.dbus.socketActivated' in ${files} no longer has" + + " any effect and can be safely removed: the user D-Bus session is" + + " now always socket activated." + ); environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/torrent/transmission.nix b/infra/libkookie/nixpkgs/nixos/modules/services/torrent/transmission.nix index 014a22bb5a8d..7bec073e26f7 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/torrent/transmission.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/torrent/transmission.nix @@ -197,7 +197,7 @@ in install -D -m 600 -o '${cfg.user}' -g '${cfg.group}' /dev/stdin \ '${cfg.home}/${settingsDir}/settings.json' '')]; - ExecStart="${pkgs.transmission}/bin/transmission-daemon -f"; + ExecStart="${pkgs.transmission}/bin/transmission-daemon -f -g ${cfg.home}/${settingsDir}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; User = cfg.user; Group = cfg.group; @@ -236,6 +236,7 @@ in # an AppArmor profile is provided to get a confinement based upon paths and rights. builtins.storeDir "/etc" + "/run" ] ++ optional (cfg.settings.script-torrent-done-enabled && cfg.settings.script-torrent-done-filename != "") @@ -396,9 +397,9 @@ in mr ${getLib pkgs.openssl}/lib/libcrypto*.so*, mr ${getLib pkgs.openssl}/lib/libssl*.so*, mr ${getLib pkgs.systemd}/lib/libsystemd*.so*, - mr ${getLib pkgs.utillinuxMinimal.out}/lib/libblkid.so*, - mr ${getLib pkgs.utillinuxMinimal.out}/lib/libmount.so*, - mr ${getLib pkgs.utillinuxMinimal.out}/lib/libuuid.so*, + mr ${getLib pkgs.util-linuxMinimal.out}/lib/libblkid.so*, + mr ${getLib pkgs.util-linuxMinimal.out}/lib/libmount.so*, + mr ${getLib pkgs.util-linuxMinimal.out}/lib/libuuid.so*, mr ${getLib pkgs.xz}/lib/liblzma*.so*, mr ${getLib pkgs.zlib}/lib/libz*.so*, @@ -408,6 +409,7 @@ in #r @{PROC}/@{pid}/environ, r @{PROC}/@{pid}/mounts, rwk /tmp/tr_session_id_*, + r /run/systemd/resolve/stub-resolv.conf, r ${pkgs.openssl.out}/etc/**, r ${config.systemd.services.transmission.environment.CURL_CA_BUNDLE}, diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/ttys/agetty.nix b/infra/libkookie/nixpkgs/nixos/modules/services/ttys/agetty.nix index f3a629f7af70..d07746be2377 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/ttys/agetty.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/ttys/agetty.nix @@ -5,7 +5,7 @@ with lib; let autologinArg = optionalString (config.services.mingetty.autologinUser != null) "--autologin ${config.services.mingetty.autologinUser}"; - gettyCmd = extraArgs: "@${pkgs.utillinux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login ${autologinArg} ${extraArgs}"; + gettyCmd = extraArgs: "@${pkgs.util-linux}/sbin/agetty agetty --login-program ${pkgs.shadow}/bin/login ${autologinArg} ${extraArgs}"; in diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/generate b/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/generate deleted file mode 100755 index 2940768b6d2c..000000000000 --- a/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/generate +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env -S nix-build --no-out-link - -# Script to generate default streaming configurations for EPGStation. There's -# no need to run this script directly since generate.sh in the EPGStation -# package directory would run this script for you. -# -# Usage: ./generate | xargs cat > streaming.json - -{ pkgs ? (import ../../../../.. {}) }: - -let - sampleConfigPath = "${pkgs.epgstation.src}/config/config.sample.json"; - sampleConfig = builtins.fromJSON (builtins.readFile sampleConfigPath); - streamingConfig = { - inherit (sampleConfig) - mpegTsStreaming - mpegTsViewer - liveHLS - liveMP4 - liveWebM - recordedDownloader - recordedStreaming - recordedViewer - recordedHLS; - }; -in -pkgs.runCommand "streaming.json" { nativeBuildInputs = [ pkgs.jq ]; } '' - jq . <<<'${builtins.toJSON streamingConfig}' > $out -'' - -# vim:set ft=nix: diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/streaming.json b/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/streaming.json index 37957f6cb6a2..8eb99cf85584 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/streaming.json +++ b/infra/libkookie/nixpkgs/nixos/modules/services/video/epgstation/streaming.json @@ -1,119 +1,119 @@ { "liveHLS": [ { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%", - "name": "720p" + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" }, { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%", - "name": "480p" + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" }, { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%", - "name": "180p" + "name": "180p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%" } ], "liveMP4": [ { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", - "name": "720p" + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" }, { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", - "name": "480p" + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1" } ], "liveWebM": [ { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", - "name": "720p" + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" }, { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", - "name": "480p" + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1" } ], "mpegTsStreaming": [ { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1", - "name": "720p" + "name": "720p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1" }, { - "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1", - "name": "480p" + "name": "480p", + "cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1" }, { "name": "Original" } ], "mpegTsViewer": { - "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end", - "ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS" + "ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS", + "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end" }, "recordedDownloader": { - "android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end", - "ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME" + "ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME", + "android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end" }, - "recordedHLS": [ - { - "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%", - "name": "720p" - }, - { - "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%", - "name": "480p" - }, - { - "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%", - "name": "480p(h265)" - } - ], "recordedStreaming": { - "mp4": [ + "webm": [ { - "ab": "192k", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", "name": "720p", - "vb": "3000k" + "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", + "vb": "3000k", + "ab": "192k" }, { - "ab": "128k", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", "name": "360p", - "vb": "1500k" + "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", + "vb": "1500k", + "ab": "128k" } ], - "mpegTs": [ + "mp4": [ { - "ab": "192k", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", - "name": "720p (H.264)", - "vb": "3000k" + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", + "vb": "3000k", + "ab": "192k" }, { - "ab": "128k", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", - "name": "360p (H.264)", - "vb": "1500k" + "name": "360p", + "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1", + "vb": "1500k", + "ab": "128k" } ], - "webm": [ + "mpegTs": [ { - "ab": "192k", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", - "name": "720p", - "vb": "3000k" + "name": "720p (H.264)", + "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", + "vb": "3000k", + "ab": "192k" }, { - "ab": "128k", - "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1", - "name": "360p", - "vb": "1500k" + "name": "360p (H.264)", + "cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1", + "vb": "1500k", + "ab": "128k" } ] }, + "recordedHLS": [ + { + "name": "720p", + "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%" + }, + { + "name": "480p", + "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%" + }, + { + "name": "480p(h265)", + "cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%" + } + ], "recordedViewer": { - "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end", - "ios": "infuse://x-callback-url/play?url=http://ADDRESS" + "ios": "infuse://x-callback-url/play?url=http://ADDRESS", + "android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end" } } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/codimd.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/codimd.nix index c787c36b877c..0fbc9ee820e6 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/codimd.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/codimd.nix @@ -6,8 +6,10 @@ let cfg = config.services.codimd; prettyJSON = conf: - pkgs.runCommand "codimd-config.json" { preferLocalBuild = true; } '' - echo '${builtins.toJSON conf}' | ${pkgs.jq}/bin/jq \ + pkgs.runCommandLocal "codimd-config.json" { + nativeBuildInputs = [ pkgs.jq ]; + } '' + echo '${builtins.toJSON conf}' | jq \ '{production:del(.[]|nulls)|del(.[][]?|nulls)}' > $out ''; in @@ -878,7 +880,6 @@ in }; }; - environmentFile = mkOption { type = with types; nullOr path; default = null; @@ -908,6 +909,14 @@ in <literal>CodiMD</literal> is running. ''; }; + + package = mkOption { + type = types.package; + default = pkgs.codimd; + description = '' + Package that provides CodiMD. + ''; + }; }; config = mkIf cfg.enable { @@ -938,7 +947,7 @@ in ''; serviceConfig = { WorkingDirectory = cfg.workDir; - ExecStart = "${pkgs.codimd}/bin/codimd"; + ExecStart = "${cfg.package}/bin/codimd"; EnvironmentFile = mkIf (cfg.environmentFile != null) [ cfg.environmentFile ]; Environment = [ "CMD_CONFIG_FILE=${cfg.workDir}/config.json" diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix index 899582a20304..2e755ae9d523 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/engelsystem.nix @@ -10,7 +10,7 @@ in { default = false; example = true; description = '' - Whether to enable engelsystem, an online tool for coordinating helpers + Whether to enable engelsystem, an online tool for coordinating volunteers and shifts on large events. ''; type = lib.types.bool; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/gerrit.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/gerrit.nix index 657b1a4fc5ba..864587aea565 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/gerrit.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/gerrit.nix @@ -143,7 +143,7 @@ in Set a UUID that uniquely identifies the server. This can be generated with - <literal>nix-shell -p utillinux --run uuidgen</literal>. + <literal>nix-shell -p util-linux --run uuidgen</literal>. ''; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/keycloak.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/keycloak.nix new file mode 100644 index 000000000000..bbb0c8d04831 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/keycloak.nix @@ -0,0 +1,692 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.keycloak; +in +{ + options.services.keycloak = { + + enable = lib.mkOption { + type = lib.types.bool; + default = false; + example = true; + description = '' + Whether to enable the Keycloak identity and access management + server. + ''; + }; + + bindAddress = lib.mkOption { + type = lib.types.str; + default = "\${jboss.bind.address:0.0.0.0}"; + example = "127.0.0.1"; + description = '' + On which address Keycloak should accept new connections. + + A special syntax can be used to allow command line Java system + properties to override the value: ''${property.name:value} + ''; + }; + + httpPort = lib.mkOption { + type = lib.types.str; + default = "\${jboss.http.port:80}"; + example = "8080"; + description = '' + On which port Keycloak should listen for new HTTP connections. + + A special syntax can be used to allow command line Java system + properties to override the value: ''${property.name:value} + ''; + }; + + httpsPort = lib.mkOption { + type = lib.types.str; + default = "\${jboss.https.port:443}"; + example = "8443"; + description = '' + On which port Keycloak should listen for new HTTPS connections. + + A special syntax can be used to allow command line Java system + properties to override the value: ''${property.name:value} + ''; + }; + + frontendUrl = lib.mkOption { + type = lib.types.str; + example = "keycloak.example.com/auth"; + description = '' + The public URL used as base for all frontend requests. Should + normally include a trailing <literal>/auth</literal>. + + See <link xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the + Hostname section of the Keycloak server installation + manual</link> for more information. + ''; + }; + + forceBackendUrlToFrontendUrl = lib.mkOption { + type = lib.types.bool; + default = false; + example = true; + description = '' + Whether Keycloak should force all requests to go through the + frontend URL configured in <xref + linkend="opt-services.keycloak.frontendUrl" />. By default, + Keycloak allows backend requests to instead use its local + hostname or IP address and may also advertise it to clients + through its OpenID Connect Discovery endpoint. + + See <link + xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">the + Hostname section of the Keycloak server installation + manual</link> for more information. + ''; + }; + + certificatePrivateKeyBundle = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/keys/ssl_cert"; + description = '' + The path to a PEM formatted bundle of the private key and + certificate to use for TLS connections. + + This should be a string, not a Nix path, since Nix paths are + copied into the world-readable Nix store. + ''; + }; + + databaseType = lib.mkOption { + type = lib.types.enum [ "mysql" "postgresql" ]; + default = "postgresql"; + example = "mysql"; + description = '' + The type of database Keycloak should connect to. + ''; + }; + + databaseHost = lib.mkOption { + type = lib.types.str; + default = "localhost"; + description = '' + Hostname of the database to connect to. + ''; + }; + + databasePort = + let + dbPorts = { + postgresql = 5432; + mysql = 3306; + }; + in + lib.mkOption { + type = lib.types.port; + default = dbPorts.${cfg.databaseType}; + description = '' + Port of the database to connect to. + ''; + }; + + databaseUseSSL = lib.mkOption { + type = lib.types.bool; + default = cfg.databaseHost != "localhost"; + description = '' + Whether the database connection should be secured by SSL / + TLS. + ''; + }; + + databaseCaCert = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + The SSL / TLS CA certificate that verifies the identity of the + database server. + + Required when PostgreSQL is used and SSL is turned on. + + For MySQL, if left at <literal>null</literal>, the default + Java keystore is used, which should suffice if the server + certificate is issued by an official CA. + ''; + }; + + databaseCreateLocally = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether a database should be automatically created on the + local host. Set this to false if you plan on provisioning a + local database yourself. This has no effect if + services.keycloak.databaseHost is customized. + ''; + }; + + databaseUsername = lib.mkOption { + type = lib.types.str; + default = "keycloak"; + description = '' + Username to use when connecting to an external or manually + provisioned database; has no effect when a local database is + automatically provisioned. + ''; + }; + + databasePasswordFile = lib.mkOption { + type = lib.types.path; + example = "/run/keys/db_password"; + description = '' + File containing the database password. + + This should be a string, not a Nix path, since Nix paths are + copied into the world-readable Nix store. + ''; + }; + + package = lib.mkOption { + type = lib.types.package; + default = pkgs.keycloak; + description = '' + Keycloak package to use. + ''; + }; + + initialAdminPassword = lib.mkOption { + type = lib.types.str; + default = "changeme"; + description = '' + Initial password set for the <literal>admin</literal> + user. The password is not stored safely and should be changed + immediately in the admin panel. + ''; + }; + + extraConfig = lib.mkOption { + type = lib.types.attrs; + default = { }; + example = lib.literalExample '' + { + "subsystem=keycloak-server" = { + "spi=hostname" = { + "provider=default" = null; + "provider=fixed" = { + enabled = true; + properties.hostname = "keycloak.example.com"; + }; + default-provider = "fixed"; + }; + }; + } + ''; + description = '' + Additional Keycloak configuration options to set in + <literal>standalone.xml</literal>. + + Options are expressed as a Nix attribute set which matches the + structure of the jboss-cli configuration. The configuration is + effectively overlayed on top of the default configuration + shipped with Keycloak. To remove existing nodes and undefine + attributes from the default configuration, set them to + <literal>null</literal>. + + The example configuration does the equivalent of the following + script, which removes the hostname provider + <literal>default</literal>, adds the deprecated hostname + provider <literal>fixed</literal> and defines it the default: + + <programlisting> + /subsystem=keycloak-server/spi=hostname/provider=default:remove() + /subsystem=keycloak-server/spi=hostname/provider=fixed:add(enabled = true, properties = { hostname = "keycloak.example.com" }) + /subsystem=keycloak-server/spi=hostname:write-attribute(name=default-provider, value="fixed") + </programlisting> + + You can discover available options by using the <link + xlink:href="http://docs.wildfly.org/21/Admin_Guide.html#Command_Line_Interface">jboss-cli.sh</link> + program and by referring to the <link + xlink:href="https://www.keycloak.org/docs/latest/server_installation/index.html">Keycloak + Server Installation and Configuration Guide</link>. + ''; + }; + + }; + + config = + let + # We only want to create a database if we're actually going to connect to it. + databaseActuallyCreateLocally = cfg.databaseCreateLocally && cfg.databaseHost == "localhost"; + createLocalPostgreSQL = databaseActuallyCreateLocally && cfg.databaseType == "postgresql"; + createLocalMySQL = databaseActuallyCreateLocally && cfg.databaseType == "mysql"; + + mySqlCaKeystore = pkgs.runCommandNoCC "mysql-ca-keystore" {} '' + ${pkgs.jre}/bin/keytool -importcert -trustcacerts -alias MySQLCACert -file ${cfg.databaseCaCert} -keystore $out -storepass notsosecretpassword -noprompt + ''; + + keycloakConfig' = builtins.foldl' lib.recursiveUpdate { + "interface=public".inet-address = cfg.bindAddress; + "socket-binding-group=standard-sockets"."socket-binding=http".port = cfg.httpPort; + "subsystem=keycloak-server"."spi=hostname" = { + "provider=default" = { + enabled = true; + properties = { + inherit (cfg) frontendUrl forceBackendUrlToFrontendUrl; + }; + }; + }; + "subsystem=datasources"."data-source=KeycloakDS" = { + max-pool-size = "20"; + user-name = if databaseActuallyCreateLocally then "keycloak" else cfg.databaseUsername; + password = "@db-password@"; + }; + } [ + (lib.optionalAttrs (cfg.databaseType == "postgresql") { + "subsystem=datasources" = { + "jdbc-driver=postgresql" = { + driver-module-name = "org.postgresql"; + driver-name = "postgresql"; + driver-xa-datasource-class-name = "org.postgresql.xa.PGXADataSource"; + }; + "data-source=KeycloakDS" = { + connection-url = "jdbc:postgresql://${cfg.databaseHost}:${builtins.toString cfg.databasePort}/keycloak"; + driver-name = "postgresql"; + "connection-properties=ssl".value = lib.boolToString cfg.databaseUseSSL; + } // (lib.optionalAttrs (cfg.databaseCaCert != null) { + "connection-properties=sslrootcert".value = cfg.databaseCaCert; + "connection-properties=sslmode".value = "verify-ca"; + }); + }; + }) + (lib.optionalAttrs (cfg.databaseType == "mysql") { + "subsystem=datasources" = { + "jdbc-driver=mysql" = { + driver-module-name = "com.mysql"; + driver-name = "mysql"; + driver-class-name = "com.mysql.jdbc.Driver"; + }; + "data-source=KeycloakDS" = { + connection-url = "jdbc:mysql://${cfg.databaseHost}:${builtins.toString cfg.databasePort}/keycloak"; + driver-name = "mysql"; + "connection-properties=useSSL".value = lib.boolToString cfg.databaseUseSSL; + "connection-properties=requireSSL".value = lib.boolToString cfg.databaseUseSSL; + "connection-properties=verifyServerCertificate".value = lib.boolToString cfg.databaseUseSSL; + "connection-properties=characterEncoding".value = "UTF-8"; + valid-connection-checker-class-name = "org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"; + validate-on-match = true; + exception-sorter-class-name = "org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"; + } // (lib.optionalAttrs (cfg.databaseCaCert != null) { + "connection-properties=trustCertificateKeyStoreUrl".value = "file:${mySqlCaKeystore}"; + "connection-properties=trustCertificateKeyStorePassword".value = "notsosecretpassword"; + }); + }; + }) + (lib.optionalAttrs (cfg.certificatePrivateKeyBundle != null) { + "socket-binding-group=standard-sockets"."socket-binding=https".port = cfg.httpsPort; + "core-service=management"."security-realm=UndertowRealm"."server-identity=ssl" = { + keystore-path = "/run/keycloak/ssl/certificate_private_key_bundle.p12"; + keystore-password = "notsosecretpassword"; + }; + "subsystem=undertow"."server=default-server"."https-listener=https".security-realm = "UndertowRealm"; + }) + cfg.extraConfig + ]; + + + /* Produces a JBoss CLI script that creates paths and sets + attributes matching those described by `attrs`. When the + script is run, the existing settings are effectively overlayed + by those from `attrs`. Existing attributes can be unset by + defining them `null`. + + JBoss paths and attributes / maps are distinguished by their + name, where paths follow a `key=value` scheme. + + Example: + mkJbossScript { + "subsystem=keycloak-server"."spi=hostname" = { + "provider=fixed" = null; + "provider=default" = { + enabled = true; + properties = { + inherit frontendUrl; + forceBackendUrlToFrontendUrl = false; + }; + }; + }; + } + => '' + if (outcome != success) of /:read-resource() + /:add() + end-if + if (outcome != success) of /subsystem=keycloak-server:read-resource() + /subsystem=keycloak-server:add() + end-if + if (outcome != success) of /subsystem=keycloak-server/spi=hostname:read-resource() + /subsystem=keycloak-server/spi=hostname:add() + end-if + if (outcome != success) of /subsystem=keycloak-server/spi=hostname/provider=default:read-resource() + /subsystem=keycloak-server/spi=hostname/provider=default:add(enabled = true, properties = { forceBackendUrlToFrontendUrl = false, frontendUrl = "https://keycloak.example.com/auth" }) + end-if + if (result != true) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="enabled") + /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=enabled, value=true) + end-if + if (result != false) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.forceBackendUrlToFrontendUrl") + /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.forceBackendUrlToFrontendUrl, value=false) + end-if + if (result != "https://keycloak.example.com/auth") of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.frontendUrl") + /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl, value="https://keycloak.example.com/auth") + end-if + if (outcome != success) of /subsystem=keycloak-server/spi=hostname/provider=fixed:read-resource() + /subsystem=keycloak-server/spi=hostname/provider=fixed:remove() + end-if + '' + */ + mkJbossScript = attrs: + let + /* From a JBoss path and an attrset, produces a JBoss CLI + snippet that writes the corresponding attributes starting + at `path`. Recurses down into subattrsets as necessary, + producing the variable name from its full path in the + attrset. + + Example: + writeAttributes "/subsystem=keycloak-server/spi=hostname/provider=default" { + enabled = true; + properties = { + forceBackendUrlToFrontendUrl = false; + frontendUrl = "https://keycloak.example.com/auth"; + }; + } + => '' + if (result != true) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="enabled") + /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=enabled, value=true) + end-if + if (result != false) of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.forceBackendUrlToFrontendUrl") + /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.forceBackendUrlToFrontendUrl, value=false) + end-if + if (result != "https://keycloak.example.com/auth") of /subsystem=keycloak-server/spi=hostname/provider=default:read-attribute(name="properties.frontendUrl") + /subsystem=keycloak-server/spi=hostname/provider=default:write-attribute(name=properties.frontendUrl, value="https://keycloak.example.com/auth") + end-if + '' + */ + writeAttributes = path: set: + let + # JBoss expressions like `${var}` need to be prefixed + # with `expression` to evaluate. + prefixExpression = string: + let + match = (builtins.match ''"\$\{.*}"'' string); + in + if match != null then + "expression " + string + else + string; + + writeAttribute = attribute: value: + let + type = builtins.typeOf value; + in + if type == "set" then + let + names = builtins.attrNames value; + in + builtins.foldl' (text: name: text + (writeAttribute "${attribute}.${name}" value.${name})) "" names + else if value == null then '' + if (outcome == success) of ${path}:read-attribute(name="${attribute}") + ${path}:undefine-attribute(name="${attribute}") + end-if + '' + else if builtins.elem type [ "string" "path" "bool" ] then + let + value' = if type == "bool" then lib.boolToString value else ''"${value}"''; + in '' + if (result != ${prefixExpression value'}) of ${path}:read-attribute(name="${attribute}") + ${path}:write-attribute(name=${attribute}, value=${value'}) + end-if + '' + else throw "Unsupported type '${type}' for path '${path}'!"; + in + lib.concatStrings + (lib.mapAttrsToList + (attribute: value: (writeAttribute attribute value)) + set); + + + /* Produces an argument list for the JBoss `add()` function, + which adds a JBoss path and takes as its arguments the + required subpaths and attributes. + + Example: + makeArgList { + enabled = true; + properties = { + forceBackendUrlToFrontendUrl = false; + frontendUrl = "https://keycloak.example.com/auth"; + }; + } + => '' + enabled = true, properties = { forceBackendUrlToFrontendUrl = false, frontendUrl = "https://keycloak.example.com/auth" } + '' + */ + makeArgList = set: + let + makeArg = attribute: value: + let + type = builtins.typeOf value; + in + if type == "set" then + "${attribute} = { " + (makeArgList value) + " }" + else if builtins.elem type [ "string" "path" "bool" ] then + "${attribute} = ${if type == "bool" then lib.boolToString value else ''"${value}"''}" + else if value == null then + "" + else + throw "Unsupported type '${type}' for attribute '${attribute}'!"; + in + lib.concatStringsSep ", " (lib.mapAttrsToList makeArg set); + + + /* Recurses into the `attrs` attrset, beginning at the path + resolved from `state.path ++ node`; if `node` is `null`, + starts from `state.path`. Only subattrsets that are JBoss + paths, i.e. follows the `key=value` format, are recursed + into - the rest are considered JBoss attributes / maps. + */ + recurse = state: node: + let + path = state.path ++ (lib.optional (node != null) node); + isPath = name: + let + value = lib.getAttrFromPath (path ++ [ name ]) attrs; + in + if (builtins.match ".*([=]).*" name) == [ "=" ] then + if builtins.isAttrs value || value == null then + true + else + throw "Parsing path '${lib.concatStringsSep "." (path ++ [ name ])}' failed: JBoss attributes cannot contain '='!" + else + false; + jbossPath = "/" + (lib.concatStringsSep "/" path); + nodeValue = lib.getAttrFromPath path attrs; + children = if !builtins.isAttrs nodeValue then {} else nodeValue; + subPaths = builtins.filter isPath (builtins.attrNames children); + jbossAttrs = lib.filterAttrs (name: _: !(isPath name)) children; + in + state // { + text = state.text + ( + if nodeValue != null then '' + if (outcome != success) of ${jbossPath}:read-resource() + ${jbossPath}:add(${makeArgList jbossAttrs}) + end-if + '' + (writeAttributes jbossPath jbossAttrs) + else '' + if (outcome == success) of ${jbossPath}:read-resource() + ${jbossPath}:remove() + end-if + '') + (builtins.foldl' recurse { text = ""; inherit path; } subPaths).text; + }; + in + (recurse { text = ""; path = []; } null).text; + + + jbossCliScript = pkgs.writeText "jboss-cli-script" (mkJbossScript keycloakConfig'); + + keycloakConfig = pkgs.runCommandNoCC "keycloak-config" {} '' + export JBOSS_BASE_DIR="$(pwd -P)"; + export JBOSS_MODULEPATH="${cfg.package}/modules"; + export JBOSS_LOG_DIR="$JBOSS_BASE_DIR/log"; + + cp -r ${cfg.package}/standalone/configuration . + chmod -R u+rwX ./configuration + + mkdir -p {deployments,ssl} + + "${cfg.package}/bin/standalone.sh"& + + attempt=1 + max_attempts=30 + while ! ${cfg.package}/bin/jboss-cli.sh --connect ':read-attribute(name=server-state)'; do + if [[ "$attempt" == "$max_attempts" ]]; then + echo "ERROR: Could not connect to Keycloak after $attempt attempts! Failing.." >&2 + exit 1 + fi + echo "Keycloak not fully started yet, retrying.. ($attempt/$max_attempts)" + sleep 1 + (( attempt++ )) + done + + ${cfg.package}/bin/jboss-cli.sh --connect --file=${jbossCliScript} --echo-command + + cp configuration/standalone.xml $out + ''; + in + lib.mkIf cfg.enable { + + assertions = [ + { + assertion = (cfg.databaseUseSSL && cfg.databaseType == "postgresql") -> (cfg.databaseCaCert != null); + message = ''A CA certificate must be specified (in 'services.keycloak.databaseCaCert') when PostgreSQL is used with SSL''; + } + ]; + + environment.systemPackages = [ cfg.package ]; + + systemd.services.keycloakPostgreSQLInit = lib.mkIf createLocalPostgreSQL { + after = [ "postgresql.service" ]; + before = [ "keycloak.service" ]; + bindsTo = [ "postgresql.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = "postgres"; + Group = "postgres"; + }; + script = '' + set -eu + + PSQL=${config.services.postgresql.package}/bin/psql + + db_password="$(<'${cfg.databasePasswordFile}')" + $PSQL -tAc "SELECT 1 FROM pg_roles WHERE rolname='keycloak'" | grep -q 1 || $PSQL -tAc "CREATE ROLE keycloak WITH LOGIN PASSWORD '$db_password' CREATEDB" + $PSQL -tAc "SELECT 1 FROM pg_database WHERE datname = 'keycloak'" | grep -q 1 || $PSQL -tAc 'CREATE DATABASE "keycloak" OWNER "keycloak"' + ''; + }; + + systemd.services.keycloakMySQLInit = lib.mkIf createLocalMySQL { + after = [ "mysql.service" ]; + before = [ "keycloak.service" ]; + bindsTo = [ "mysql.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = config.services.mysql.user; + Group = config.services.mysql.group; + }; + script = '' + set -eu + + db_password="$(<'${cfg.databasePasswordFile}')" + ( echo "CREATE USER IF NOT EXISTS 'keycloak'@'localhost' IDENTIFIED BY '$db_password';" + echo "CREATE DATABASE keycloak CHARACTER SET utf8 COLLATE utf8_unicode_ci;" + echo "GRANT ALL PRIVILEGES ON keycloak.* TO 'keycloak'@'localhost';" + ) | ${config.services.mysql.package}/bin/mysql -N + ''; + }; + + systemd.services.keycloak = + let + databaseServices = + if createLocalPostgreSQL then [ + "keycloakPostgreSQLInit.service" "postgresql.service" + ] + else if createLocalMySQL then [ + "keycloakMySQLInit.service" "mysql.service" + ] + else [ ]; + in { + after = databaseServices; + bindsTo = databaseServices; + wantedBy = [ "multi-user.target" ]; + environment = { + JBOSS_LOG_DIR = "/var/log/keycloak"; + JBOSS_BASE_DIR = "/run/keycloak"; + JBOSS_MODULEPATH = "${cfg.package}/modules"; + }; + serviceConfig = { + ExecStartPre = let + startPreFullPrivileges = '' + set -eu + + install -T -m 0400 -o keycloak -g keycloak '${cfg.databasePasswordFile}' /run/keycloak/secrets/db_password + '' + lib.optionalString (cfg.certificatePrivateKeyBundle != null) '' + install -T -m 0400 -o keycloak -g keycloak '${cfg.certificatePrivateKeyBundle}' /run/keycloak/secrets/ssl_cert_pk_bundle + ''; + startPre = '' + set -eu + + install -m 0600 ${cfg.package}/standalone/configuration/*.properties /run/keycloak/configuration + install -T -m 0600 ${keycloakConfig} /run/keycloak/configuration/standalone.xml + + db_password="$(</run/keycloak/secrets/db_password)" + ${pkgs.replace}/bin/replace-literal -fe '@db-password@' "$db_password" /run/keycloak/configuration/standalone.xml + + export JAVA_OPTS=-Djboss.server.config.user.dir=/run/keycloak/configuration + ${cfg.package}/bin/add-user-keycloak.sh -u admin -p '${cfg.initialAdminPassword}' + '' + lib.optionalString (cfg.certificatePrivateKeyBundle != null) '' + pushd /run/keycloak/ssl/ + cat /run/keycloak/secrets/ssl_cert_pk_bundle <(echo) /etc/ssl/certs/ca-certificates.crt > allcerts.pem + ${pkgs.openssl}/bin/openssl pkcs12 -export -in /run/keycloak/secrets/ssl_cert_pk_bundle -chain \ + -name "${cfg.frontendUrl}" -out certificate_private_key_bundle.p12 \ + -CAfile allcerts.pem -passout pass:notsosecretpassword + popd + ''; + in [ + "+${pkgs.writeShellScript "keycloak-start-pre-full-privileges" startPreFullPrivileges}" + "${pkgs.writeShellScript "keycloak-start-pre" startPre}" + ]; + ExecStart = "${cfg.package}/bin/standalone.sh"; + User = "keycloak"; + Group = "keycloak"; + DynamicUser = true; + RuntimeDirectory = map (p: "keycloak/" + p) [ + "secrets" + "configuration" + "deployments" + "data" + "ssl" + "log" + "tmp" + ]; + RuntimeDirectoryMode = 0700; + LogsDirectory = "keycloak"; + AmbientCapabilities = "CAP_NET_BIND_SERVICE"; + }; + }; + + services.postgresql.enable = lib.mkDefault createLocalPostgreSQL; + services.mysql.enable = lib.mkDefault createLocalMySQL; + services.mysql.package = lib.mkIf createLocalMySQL pkgs.mysql; + }; + + meta.doc = ./keycloak.xml; +} diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/keycloak.xml b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/keycloak.xml new file mode 100644 index 000000000000..ca5e223eee46 --- /dev/null +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/keycloak.xml @@ -0,0 +1,205 @@ +<chapter xmlns="http://docbook.org/ns/docbook" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:xi="http://www.w3.org/2001/XInclude" + version="5.0" + xml:id="module-services-keycloak"> + <title>Keycloak</title> + <para> + <link xlink:href="https://www.keycloak.org/">Keycloak</link> is an + open source identity and access management server with support for + <link xlink:href="https://openid.net/connect/">OpenID + Connect</link>, <link xlink:href="https://oauth.net/2/">OAUTH + 2.0</link> and <link + xlink:href="https://en.wikipedia.org/wiki/SAML_2.0">SAML + 2.0</link>. + </para> + <section xml:id="module-services-keycloak-admin"> + <title>Administration</title> + <para> + An administrative user with the username + <literal>admin</literal> is automatically created in the + <literal>master</literal> realm. Its initial password can be + configured by setting <xref linkend="opt-services.keycloak.initialAdminPassword" /> + and defaults to <literal>changeme</literal>. The password is + not stored safely and should be changed immediately in the + admin panel. + </para> + + <para> + Refer to the <link + xlink:href="https://www.keycloak.org/docs/latest/server_admin/index.html#admin-console">Admin + Console section of the Keycloak Server Administration Guide</link> for + information on how to administer your + <productname>Keycloak</productname> instance. + </para> + </section> + + <section xml:id="module-services-keycloak-database"> + <title>Database access</title> + <para> + <productname>Keycloak</productname> can be used with either + <productname>PostgreSQL</productname> or + <productname>MySQL</productname>. Which one is used can be + configured in <xref + linkend="opt-services.keycloak.databaseType" />. The selected + database will automatically be enabled and a database and role + created unless <xref + linkend="opt-services.keycloak.databaseHost" /> is changed from + its default of <literal>localhost</literal> or <xref + linkend="opt-services.keycloak.databaseCreateLocally" /> is set + to <literal>false</literal>. + </para> + + <para> + External database access can also be configured by setting + <xref linkend="opt-services.keycloak.databaseHost" />, <xref + linkend="opt-services.keycloak.databaseUsername" />, <xref + linkend="opt-services.keycloak.databaseUseSSL" /> and <xref + linkend="opt-services.keycloak.databaseCaCert" /> as + appropriate. Note that you need to manually create a database + called <literal>keycloak</literal> and allow the configured + database user full access to it. + </para> + + <para> + <xref linkend="opt-services.keycloak.databasePasswordFile" /> + must be set to the path to a file containing the password used + to log in to the database. If <xref linkend="opt-services.keycloak.databaseHost" /> + and <xref linkend="opt-services.keycloak.databaseCreateLocally" /> + are kept at their defaults, the database role + <literal>keycloak</literal> with that password is provisioned + on the local database instance. + </para> + + <warning> + <para> + The path should be provided as a string, not a Nix path, since Nix + paths are copied into the world readable Nix store. + </para> + </warning> + </section> + + <section xml:id="module-services-keycloak-frontendurl"> + <title>Frontend URL</title> + <para> + The frontend URL is used as base for all frontend requests and + must be configured through <xref linkend="opt-services.keycloak.frontendUrl" />. + It should normally include a trailing <literal>/auth</literal> + (the default web context). + </para> + + <para> + <xref linkend="opt-services.keycloak.forceBackendUrlToFrontendUrl" /> + determines whether Keycloak should force all requests to go + through the frontend URL. By default, + <productname>Keycloak</productname> allows backend requests to + instead use its local hostname or IP address and may also + advertise it to clients through its OpenID Connect Discovery + endpoint. + </para> + + <para> + See the <link + xlink:href="https://www.keycloak.org/docs/latest/server_installation/#_hostname">Hostname + section of the Keycloak Server Installation and Configuration + Guide</link> for more information. + </para> + </section> + + <section xml:id="module-services-keycloak-tls"> + <title>Setting up TLS/SSL</title> + <para> + By default, <productname>Keycloak</productname> won't accept + unsecured HTTP connections originating from outside its local + network. + </para> + + <para> + For HTTPS support, a TLS certificate and private key is + required. They should be <link + xlink:href="https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail">PEM + formatted</link> and concatenated into a single file. The path + to this file should be configured in + <xref linkend="opt-services.keycloak.certificatePrivateKeyBundle" />. + </para> + + <warning> + <para> + The path should be provided as a string, not a Nix path, + since Nix paths are copied into the world readable Nix store. + </para> + </warning> + </section> + + <section xml:id="module-services-keycloak-extra-config"> + <title>Additional configuration</title> + <para> + Additional Keycloak configuration options, for which no + explicit <productname>NixOS</productname> options are provided, + can be set in <xref linkend="opt-services.keycloak.extraConfig" />. + </para> + + <para> + Options are expressed as a Nix attribute set which matches the + structure of the jboss-cli configuration. The configuration is + effectively overlayed on top of the default configuration + shipped with Keycloak. To remove existing nodes and undefine + attributes from the default configuration, set them to + <literal>null</literal>. + </para> + <para> + For example, the following script, which removes the hostname + provider <literal>default</literal>, adds the deprecated + hostname provider <literal>fixed</literal> and defines it the + default: + +<programlisting> +/subsystem=keycloak-server/spi=hostname/provider=default:remove() +/subsystem=keycloak-server/spi=hostname/provider=fixed:add(enabled = true, properties = { hostname = "keycloak.example.com" }) +/subsystem=keycloak-server/spi=hostname:write-attribute(name=default-provider, value="fixed") +</programlisting> + + would be expressed as + +<programlisting> +services.keycloak.extraConfig = { + "subsystem=keycloak-server" = { + "spi=hostname" = { + "provider=default" = null; + "provider=fixed" = { + enabled = true; + properties.hostname = "keycloak.example.com"; + }; + default-provider = "fixed"; + }; + }; +}; +</programlisting> + </para> + <para> + You can discover available options by using the <link + xlink:href="http://docs.wildfly.org/21/Admin_Guide.html#Command_Line_Interface">jboss-cli.sh</link> + program and by referring to the <link + xlink:href="https://www.keycloak.org/docs/latest/server_installation/index.html">Keycloak + Server Installation and Configuration Guide</link>. + </para> + </section> + + <section xml:id="module-services-keycloak-example-config"> + <title>Example configuration</title> + <para> + A basic configuration with some custom settings could look like this: +<programlisting> +services.keycloak = { + <link linkend="opt-services.keycloak.enable">enable</link> = true; + <link linkend="opt-services.keycloak.initialAdminPassword">initialAdminPassword</link> = "e6Wcm0RrtegMEHl"; # change on first login + <link linkend="opt-services.keycloak.frontendUrl">frontendUrl</link> = "https://keycloak.example.com/auth"; + <link linkend="opt-services.keycloak.forceBackendUrlToFrontendUrl">forceBackendUrlToFrontendUrl</link> = true; + <link linkend="opt-services.keycloak.certificatePrivateKeyBundle">certificatePrivateKeyBundle</link> = "/run/keys/ssl_cert"; + <link linkend="opt-services.keycloak.databasePasswordFile">databasePasswordFile</link> = "/run/keys/db_password"; +}; +</programlisting> + </para> + + </section> + </chapter> diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix index dc7abce2a5cb..3a876f75f4a4 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/moinmoin.nix @@ -224,6 +224,8 @@ in chmod -R u+w ${dataDir}/${wikiIdent}/underlay ''; + startLimitIntervalSec = 30; + serviceConfig = { User = user; Group = group; @@ -237,7 +239,6 @@ in Restart = "on-failure"; RestartSec = "2s"; - StartLimitIntervalSec = "30s"; StateDirectory = "moin/${wikiIdent}"; StateDirectoryMode = "0750"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix index bad1bd9c767d..53c2ab76fdfa 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/nextcloud.nix @@ -549,9 +549,7 @@ in { }; "/" = { priority = 900; - extraConfig = if major < 20 - then "rewrite ^ /index.php;" - else "try_files $uri $uri/ /index.php$request_uri;"; + extraConfig = "rewrite ^ /index.php;"; }; "~ ^/store-apps" = { priority = 201; @@ -575,7 +573,7 @@ in { "~ ^/(?:\\.|autotest|occ|issue|indie|db_|console)".extraConfig = '' return 404; ''; - ${if major < 20 then "~ ^\\/(?:index|remote|public|cron|core\\/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|oc[ms]-provider\\/.+|.+\\/richdocumentscode\\/proxy)\\.php(?:$|\\/)" else "~ \\.php(?:$|/)"} = { + "~ ^\\/(?:index|remote|public|cron|core\\/ajax\\/update|status|ocs\\/v[12]|updater\\/.+|oc[ms]-provider\\/.+|.+\\/richdocumentscode\\/proxy)\\.php(?:$|\\/)" = { priority = 500; extraConfig = '' include ${config.services.nginx.package}/conf/fastcgi.conf; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/shiori.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/shiori.nix index 1817a2039352..9083ddfa2206 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/shiori.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-apps/shiori.nix @@ -37,11 +37,60 @@ in { description = "Shiori simple bookmarks manager"; wantedBy = [ "multi-user.target" ]; + environment.SHIORI_DIR = "/var/lib/shiori"; + serviceConfig = { ExecStart = "${package}/bin/shiori serve --address '${address}' --port '${toString port}'"; + DynamicUser = true; - Environment = "SHIORI_DIR=/var/lib/shiori"; StateDirectory = "shiori"; + # As the RootDirectory + RuntimeDirectory = "shiori"; + + # Security options + + BindReadOnlyPaths = [ + "/nix/store" + + # For SSL certificates, and the resolv.conf + "/etc" + ]; + + CapabilityBoundingSet = ""; + + DeviceAllow = ""; + + LockPersonality = true; + + MemoryDenyWriteExecute = true; + + PrivateDevices = true; + PrivateUsers = true; + + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + + RestrictNamespaces = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictRealtime = true; + RestrictSUIDSGID = true; + + RootDirectory = "/run/shiori"; + + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; + SystemCallFilter = [ + "@system-service" + + "~@chown" "~@cpu-emulation" "~@debug" "~@ipc" "~@keyring" "~@memlock" + "~@module" "~@obsolete" "~@privileged" "~@process" "~@raw-io" + "~@resources" "~@setuid" + ]; }; }; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix index 6ffda3d63614..dc78728d6636 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/apache-httpd/default.nix @@ -750,8 +750,8 @@ in # Get rid of old semaphores. These tend to accumulate across # server restarts, eventually preventing it from restarting # successfully. - for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do - ${pkgs.utillinux}/bin/ipcrm -s $i + for i in $(${pkgs.util-linux}/bin/ipcs -s | grep ' ${cfg.user} ' | cut -f2 -d ' '); do + ${pkgs.util-linux}/bin/ipcrm -s $i done ''; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/caddy.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/caddy.nix index 72bf9a9a1f44..297b73273392 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/caddy.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/caddy.nix @@ -24,6 +24,10 @@ let ${pkgs.jq}/bin/jq -s '.[0] * .[1]' ${adaptedConfig} ${tlsJSON} > $out ''; in { + imports = [ + (mkRemovedOptionModule [ "services" "caddy" "agree" ] "this option is no longer necessary for Caddy 2") + ]; + options.services.caddy = { enable = mkEnableOption "Caddy web server"; @@ -66,12 +70,6 @@ in { description = "Email address (for Let's Encrypt certificate)"; }; - agree = mkOption { - default = false; - type = types.bool; - description = "Agree to Let's Encrypt Subscriber Agreement"; - }; - dataDir = mkOption { default = "/var/lib/caddy"; type = types.path; @@ -103,6 +101,8 @@ in { after = [ "network-online.target" ]; wants = [ "network-online.target" ]; # systemd-networkd-wait-online.service wantedBy = [ "multi-user.target" ]; + startLimitIntervalSec = 14400; + startLimitBurst = 10; serviceConfig = { ExecStart = "${cfg.package}/bin/caddy run --config ${configJSON}"; ExecReload = "${cfg.package}/bin/caddy reload --config ${configJSON}"; @@ -110,8 +110,6 @@ in { User = "caddy"; Group = "caddy"; Restart = "on-abnormal"; - StartLimitIntervalSec = 14400; - StartLimitBurst = 10; AmbientCapabilities = "cap_net_bind_service"; CapabilityBoundingSet = "cap_net_bind_service"; NoNewPrivileges = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix index 39bcb14e5afe..e9630d379f36 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/default.nix @@ -34,7 +34,6 @@ let proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; - proxy_set_header Accept-Encoding ""; ''; upstreamConfig = toString (flip mapAttrsToList cfg.upstreams (name: upstream: '' @@ -87,7 +86,7 @@ let ''} ssl_protocols ${cfg.sslProtocols}; - ssl_ciphers ${cfg.sslCiphers}; + ${optionalString (cfg.sslCiphers != null) "ssl_ciphers ${cfg.sslCiphers};"} ${optionalString (cfg.sslDhparam != null) "ssl_dhparam ${cfg.sslDhparam};"} ${optionalString (cfg.recommendedTlsSettings) '' @@ -262,10 +261,7 @@ let ssl_trusted_certificate ${vhost.sslTrustedCertificate}; ''} - ${optionalString (vhost.basicAuthFile != null || vhost.basicAuth != {}) '' - auth_basic secured; - auth_basic_user_file ${if vhost.basicAuthFile != null then vhost.basicAuthFile else mkHtpasswd vhostName vhost.basicAuth}; - ''} + ${mkBasicAuth vhostName vhost} ${mkLocations vhost.locations} @@ -294,9 +290,19 @@ let ${optionalString (config.return != null) "return ${config.return};"} ${config.extraConfig} ${optionalString (config.proxyPass != null && cfg.recommendedProxySettings) "include ${recommendedProxyConfig};"} + ${mkBasicAuth "sublocation" config} } '') (sortProperties (mapAttrsToList (k: v: v // { location = k; }) locations))); - mkHtpasswd = vhostName: authDef: pkgs.writeText "${vhostName}.htpasswd" ( + + mkBasicAuth = name: zone: optionalString (zone.basicAuthFile != null || zone.basicAuth != {}) (let + auth_file = if zone.basicAuthFile != null + then zone.basicAuthFile + else mkHtpasswd name zone.basicAuth; + in '' + auth_basic secured; + auth_basic_user_file ${auth_file}; + ''); + mkHtpasswd = name: authDef: pkgs.writeText "${name}.htpasswd" ( concatStringsSep "\n" (mapAttrsToList (user: password: '' ${user}:{PLAIN}${password} '') authDef) @@ -488,7 +494,7 @@ in }; sslCiphers = mkOption { - type = types.str; + type = types.nullOr types.str; # Keep in sync with https://ssl-config.mozilla.org/#server=nginx&config=intermediate default = "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; description = "Ciphers to choose from when negotiating TLS handshakes."; @@ -694,6 +700,8 @@ in ${cfg.preStart} ${execCommand} -t ''; + + startLimitIntervalSec = 60; serviceConfig = { ExecStart = execCommand; ExecReload = [ @@ -702,7 +710,6 @@ in ]; Restart = "always"; RestartSec = "10s"; - StartLimitInterval = "1min"; # User and group User = cfg.user; Group = cfg.group; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix index 3d9e391ecf20..f2fc07255725 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/location-options.nix @@ -9,6 +9,34 @@ with lib; { options = { + basicAuth = mkOption { + type = types.attrsOf types.str; + default = {}; + example = literalExample '' + { + user = "password"; + }; + ''; + description = '' + Basic Auth protection for a vhost. + + WARNING: This is implemented to store the password in plain text in the + Nix store. + ''; + }; + + basicAuthFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + Basic Auth password file for a vhost. + Can be created via: <command>htpasswd -c <filename> <username></command>. + + WARNING: The generate file contains the users' passwords in a + non-cryptographically-securely hashed way. + ''; + }; + proxyPass = mkOption { type = types.nullOr types.str; default = null; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix index 455854e2a965..cf211ea9a71b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/nginx/vhost-options.nix @@ -198,7 +198,7 @@ with lib; Basic Auth protection for a vhost. WARNING: This is implemented to store the password in plain text in the - nix store. + Nix store. ''; }; @@ -207,7 +207,10 @@ with lib; default = null; description = '' Basic Auth password file for a vhost. - Can be created via: <command>htpasswd -c <filename> <username></command> + Can be created via: <command>htpasswd -c <filename> <username></command>. + + WARNING: The generate file contains the users' passwords in a + non-cryptographically-securely hashed way. ''; }; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/traefik.nix b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/traefik.nix index 4ab7307c3b67..3d29199dd454 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/traefik.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/web-servers/traefik.nix @@ -136,6 +136,8 @@ in { description = "Traefik web server"; after = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; + startLimitIntervalSec = 86400; + startLimitBurst = 5; serviceConfig = { ExecStart = "${cfg.package}/bin/traefik --configfile=${staticConfigFile}"; @@ -143,8 +145,6 @@ in { User = "traefik"; Group = cfg.group; Restart = "on-failure"; - StartLimitInterval = 86400; - StartLimitBurst = 5; AmbientCapabilities = "cap_net_bind_service"; CapabilityBoundingSet = "cap_net_bind_service"; NoNewPrivileges = true; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix index acccbdb9950a..68a65d77d62f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -17,6 +17,11 @@ let ''; }; + defaultFavoriteAppsOverride = '' + [org.gnome.shell] + favorite-apps=[ 'org.gnome.Geary.desktop', 'org.gnome.Calendar.desktop', 'org.gnome.Music.desktop', 'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop' ] + ''; + nixos-gsettings-desktop-schemas = let defaultPackages = with pkgs; [ gsettings-desktop-schemas gnome3.gnome-shell ]; in @@ -42,8 +47,7 @@ let [org.gnome.desktop.screensaver] picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath}' - [org.gnome.shell] - favorite-apps=[ 'org.gnome.Epiphany.desktop', 'org.gnome.Geary.desktop', 'org.gnome.Music.desktop', 'org.gnome.Photos.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Software.desktop' ] + ${cfg.favoriteAppsOverride} ${cfg.extraGSettingsOverrides} EOF @@ -69,6 +73,7 @@ in core-os-services.enable = mkEnableOption "essential services for GNOME3"; core-shell.enable = mkEnableOption "GNOME Shell services"; core-utilities.enable = mkEnableOption "GNOME core utilities"; + core-developer-tools.enable = mkEnableOption "GNOME core developer tools"; games.enable = mkEnableOption "GNOME games"; experimental-features = { @@ -123,6 +128,17 @@ in apply = list: list ++ [ pkgs.gnome3.gnome-shell pkgs.gnome3.gnome-shell-extensions ]; }; + favoriteAppsOverride = mkOption { + internal = true; # this is messy + default = defaultFavoriteAppsOverride; + type = types.lines; + example = literalExample '' + [org.gnome.shell] + favorite-apps=[ 'firefox.desktop', 'org.gnome.Calendar.desktop' ] + ''; + description = "List of desktop files to put as favorite apps into gnome-shell. These need to be installed somehow globally."; + }; + extraGSettingsOverrides = mkOption { default = ""; type = types.lines; @@ -179,6 +195,14 @@ in config = mkMerge [ (mkIf (cfg.enable || flashbackEnabled) { + # Seed our configuration into nixos-generate-config + system.nixos-generate-config.desktopConfiguration = '' + # Enable the GNOME 3 Desktop Environment. + services.xserver.enable = true; + services.xserver.displayManager.gdm.enable = true; + services.xserver.desktopManager.gnome3.enable = true; + ''; + services.gnome3.core-os-services.enable = true; services.gnome3.core-shell.enable = true; services.gnome3.core-utilities.enable = mkDefault true; @@ -207,6 +231,11 @@ in # If gnome3 is installed, build vim for gtk3 too. nixpkgs.config.vim.gui = "gtk3"; + + # Install gnome-software if flatpak is enabled + services.flatpak.guiPackages = [ + pkgs.gnome3.gnome-software + ]; }) (mkIf flashbackEnabled { @@ -294,6 +323,12 @@ in gnome-shell ]; + services.udev.packages = with pkgs.gnome3; [ + # Force enable KMS modifiers for devices that require them. + # https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1443 + mutter + ]; + services.avahi.enable = mkDefault true; xdg.portal.extraPortals = [ @@ -323,7 +358,7 @@ in source-sans-pro ]; - # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-36/elements/core/meta-gnome-core-shell.bst + # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-shell.bst environment.systemPackages = with pkgs.gnome3; [ adwaita-icon-theme gnome-backgrounds @@ -368,7 +403,7 @@ in }; }) - # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-36/elements/core/meta-gnome-core-utilities.bst + # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/blob/gnome-3-38/elements/core/meta-gnome-core-utilities.bst (mkIf serviceCfg.core-utilities.enable { environment.systemPackages = (with pkgs.gnome3; removePackagesByName [ baobab @@ -387,17 +422,15 @@ in gnome-logs gnome-maps gnome-music - gnome-photos + pkgs.gnome-photos gnome-screenshot - gnome-software gnome-system-monitor gnome-weather nautilus + pkgs.gnome-connections simple-scan totem yelp - # Unsure if sensible for NixOS - /* gnome-boxes */ ] config.environment.gnome3.excludePackages); # Enable default program modules @@ -426,12 +459,43 @@ in (mkIf serviceCfg.games.enable { environment.systemPackages = (with pkgs.gnome3; removePackagesByName [ - aisleriot atomix five-or-more four-in-a-row gnome-chess gnome-klotski - gnome-mahjongg gnome-mines gnome-nibbles gnome-robots gnome-sudoku - gnome-taquin gnome-tetravex hitori iagno lightsoff quadrapassel - swell-foop tali + aisleriot + atomix + five-or-more + four-in-a-row + gnome-chess + gnome-klotski + gnome-mahjongg + gnome-mines + gnome-nibbles + gnome-robots + gnome-sudoku + gnome-taquin + gnome-tetravex + hitori + iagno + lightsoff + quadrapassel + swell-foop + tali ] config.environment.gnome3.excludePackages); }) + + # Adapt from https://gitlab.gnome.org/GNOME/gnome-build-meta/-/blob/3.38.0/elements/core/meta-gnome-core-developer-tools.bst + (mkIf serviceCfg.core-developer-tools.enable { + environment.systemPackages = (with pkgs.gnome3; removePackagesByName [ + dconf-editor + devhelp + pkgs.gnome-builder + # boxes would make sense in this option, however + # it doesn't function well enough to be included + # in default configurations. + # https://github.com/NixOS/nixpkgs/issues/60908 + /* gnome-boxes */ + ] config.environment.gnome3.excludePackages); + + services.sysprof.enable = true; + }) ]; } diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix index e67e216f90d9..cf02a71248b1 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/pantheon.nix @@ -180,7 +180,6 @@ in gtk3.out hicolor-icon-theme lightlocker - nixos-artwork.wallpapers.simple-dark-gray onboard qgnomeplatform shared-mime-info diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix index e48b5f23b58f..8cc579af2ca0 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/desktop-managers/plasma5.nix @@ -184,6 +184,14 @@ in config = mkMerge [ (mkIf cfg.enable { + # Seed our configuration into nixos-generate-config + system.nixos-generate-config.desktopConfiguration = '' + # Enable the Plasma 5 Desktop Environment. + services.xserver.enable = true; + services.xserver.displayManager.sddm.enable = true; + services.xserver.desktopManager.plasma5.enable = true; + ''; + services.xserver.desktopManager.session = singleton { name = "plasma5"; bgSupport = true; @@ -192,7 +200,7 @@ in security.wrappers = { kcheckpass.source = "${lib.getBin plasma5.kscreenlocker}/libexec/kcheckpass"; - start_kdeinit.source = "${lib.getBin pkgs.kinit}/libexec/kf5/start_kdeinit"; + start_kdeinit.source = "${lib.getBin pkgs.kdeFrameworks.kinit}/libexec/kf5/start_kdeinit"; kwin_wayland = { source = "${lib.getBin plasma5.kwin}/bin/kwin_wayland"; capabilities = "cap_sys_nice+ep"; @@ -359,7 +367,7 @@ in security.pam.services.sddm.enableKwallet = true; xdg.portal.enable = true; - xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-kde ]; + xdg.portal.extraPortals = [ plasma5.xdg-desktop-portal-kde ]; # Update the start menu for each user that is currently logged in system.userActivationScripts.plasmaSetup = activationScript; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/default.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/default.nix index 568aeaceef75..6945a241f92f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/default.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/default.nix @@ -474,6 +474,12 @@ in ) [dms wms] ); + + # Make xsessions and wayland sessions available in XDG_DATA_DIRS + # as some programs have behavior that depends on them being present + environment.sessionVariables.XDG_DATA_DIRS = [ + "${cfg.displayManager.sessionData.desktops}/share" + ]; }; imports = [ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix index eae70a57c781..e3c5adb9737f 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/gdm.nix @@ -160,7 +160,7 @@ in ]; # Otherwise GDM will not be able to start correctly and display Wayland sessions - systemd.packages = with pkgs.gnome3; [ gnome-session gnome-shell ]; + systemd.packages = with pkgs.gnome3; [ gdm gnome-session gnome-shell ]; environment.systemPackages = [ pkgs.gnome3.adwaita-icon-theme ]; systemd.services.display-manager.wants = [ @@ -264,7 +264,7 @@ in # presented and there's a little delay. environment.etc."gdm/custom.conf".text = '' [daemon] - WaylandEnable=${if cfg.gdm.wayland then "true" else "false"} + WaylandEnable=${boolToString cfg.gdm.wayland} ${optionalString cfg.autoLogin.enable ( if cfg.gdm.autoLogin.delay > 0 then '' TimedLoginEnable=true diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix index 143785db0b4f..2dafee9e36e3 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/lightdm.nix @@ -308,6 +308,7 @@ in home = "/var/lib/lightdm"; group = "lightdm"; uid = config.ids.uids.lightdm; + shell = pkgs.bash; }; systemd.tmpfiles.rules = [ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix index e63bb2e44539..a39bb55b38c4 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/display-managers/sddm.nix @@ -9,7 +9,12 @@ let cfg = dmcfg.sddm; xEnv = config.systemd.services.display-manager.environment; - inherit (pkgs) sddm; + sddm = if config.services.xserver.desktopManager.lxqt.enable then + # TODO: Move lxqt to libsForQt515 + pkgs.libsForQt514.sddm + else + pkgs.libsForQt5.sddm + ; xserverWrapper = pkgs.writeScript "xserver-wrapper" '' #!/bin/sh @@ -55,10 +60,10 @@ let XauthPath=${pkgs.xorg.xauth}/bin/xauth DisplayCommand=${Xsetup} DisplayStopCommand=${Xstop} - EnableHidpi=${if cfg.enableHidpi then "true" else "false"} + EnableHidpi=${boolToString cfg.enableHidpi} [Wayland] - EnableHidpi=${if cfg.enableHidpi then "true" else "false"} + EnableHidpi=${boolToString cfg.enableHidpi} SessionDir=${dmcfg.sessionData.desktops}/share/wayland-sessions ${optionalString dmcfg.autoLogin.enable '' diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/redshift.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/redshift.nix index 21b0b33553ac..60d80a28762b 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/redshift.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/redshift.nix @@ -82,6 +82,15 @@ in { ''; }; + executable = mkOption { + type = types.str; + default = "/bin/redshift"; + example = "/bin/redshift-gtk"; + description = '' + Redshift executable to use within the package. + ''; + }; + extraOptions = mkOption { type = types.listOf types.str; default = []; @@ -114,7 +123,7 @@ in { partOf = [ "graphical-session.target" ]; serviceConfig = { ExecStart = '' - ${cfg.package}/bin/redshift \ + ${cfg.package}${cfg.executable} \ -l ${providerString} \ -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \ -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} \ diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/terminal-server.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/terminal-server.nix index 503c14c9b624..e6b50c21a952 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/terminal-server.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/terminal-server.nix @@ -32,7 +32,7 @@ with lib; path = [ pkgs.xorg.xorgserver.out pkgs.gawk pkgs.which pkgs.openssl pkgs.xorg.xauth - pkgs.nettools pkgs.shadow pkgs.procps pkgs.utillinux pkgs.bash + pkgs.nettools pkgs.shadow pkgs.procps pkgs.util-linux pkgs.bash ]; environment.FD_GEOM = "1024x786x24"; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix index 6e19e3572c79..6f1db2110f87 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/evilwm.nix @@ -16,8 +16,8 @@ in services.xserver.windowManager.session = singleton { name = "evilwm"; start = '' - ${pkgs.evilwm}/bin/evilwm & - waitPID=$! + ${pkgs.evilwm}/bin/evilwm & + waitPID=$! ''; }; environment.systemPackages = [ pkgs.evilwm ]; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix index dc1d957c1709..88e13f4dbfb0 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/window-managers/exwm.nix @@ -5,7 +5,7 @@ with lib; let cfg = config.services.xserver.windowManager.exwm; loadScript = pkgs.writeText "emacs-exwm-load" '' - (require 'exwm) + ${cfg.loadScript} ${optionalString cfg.enableDefaultConfig '' (require 'exwm-config) (exwm-config-default) @@ -19,6 +19,18 @@ in options = { services.xserver.windowManager.exwm = { enable = mkEnableOption "exwm"; + loadScript = mkOption { + default = "(require 'exwm)"; + example = literalExample '' + (require 'exwm) + (exwm-enable) + ''; + description = '' + Emacs lisp code to be run after loading the user's init + file. If enableDefaultConfig is true, this will be run + before loading the default config. + ''; + }; enableDefaultConfig = mkOption { default = true; type = lib.types.bool; diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/x11/xserver.nix b/infra/libkookie/nixpkgs/nixos/modules/services/x11/xserver.nix index 55d3e742ef7c..9e971671c474 100644 --- a/infra/libkookie/nixpkgs/nixos/modules/services/x11/xserver.nix +++ b/infra/libkookie/nixpkgs/nixos/modules/services/x11/xserver.nix @@ -678,14 +678,14 @@ in script = "${cfg.displayManager.job.execCmd}"; + # Stop restarting if the display manager stops (crashes) 2 times + # in one minute. Starting X typically takes 3-4s. + startLimitIntervalSec = 30; + startLimitBurst = 3; serviceConfig = { Restart = "always"; RestartSec = "200ms"; SyslogIdentifier = "display-manager"; - # Stop restarting if the display manager stops (crashes) 2 times - # in one minute. Starting X typically takes 3-4s. - StartLimitInterval = "30s"; - StartLimitBurst = "3"; }; }; |