diff options
Diffstat (limited to 'nixos/modules')
67 files changed, 1245 insertions, 536 deletions
diff --git a/nixos/modules/config/i18n.nix b/nixos/modules/config/i18n.nix index cc2ddda9d32f..feb76581a720 100644 --- a/nixos/modules/config/i18n.nix +++ b/nixos/modules/config/i18n.nix @@ -68,7 +68,8 @@ with lib; config = { environment.systemPackages = - optional (config.i18n.supportedLocales != []) config.i18n.glibcLocales; + # We increase the priority a little, so that plain glibc in systemPackages can't win. + optional (config.i18n.supportedLocales != []) (lib.setPrio (-1) config.i18n.glibcLocales); environment.sessionVariables = { LANG = config.i18n.defaultLocale; diff --git a/nixos/modules/config/system-path.nix b/nixos/modules/config/system-path.nix index 4100ec897016..ae9710e3518b 100644 --- a/nixos/modules/config/system-path.nix +++ b/nixos/modules/config/system-path.nix @@ -8,8 +8,7 @@ with lib; let requiredPackages = map (pkg: setPrio ((pkg.meta.priority or 5) + 3) pkg) - [ config.nix.package - pkgs.acl + [ pkgs.acl pkgs.attr pkgs.bashInteractive # bash with ncurses support pkgs.bzip2 @@ -33,7 +32,6 @@ let pkgs.nano pkgs.ncurses pkgs.netcat - pkgs.nix-info config.programs.ssh.package pkgs.perl pkgs.procps @@ -43,6 +41,7 @@ let pkgs.time pkgs.utillinux pkgs.which # 88K size + pkgs.zstd ]; in diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix index 141e43fec39b..7fbbfcec7510 100644 --- a/nixos/modules/config/users-groups.nix +++ b/nixos/modules/config/users-groups.nix @@ -600,6 +600,38 @@ in { } ]; + warnings = + builtins.filter (x: x != null) ( + flip mapAttrsToList cfg.users (name: user: + # This regex matches a subset of the Modular Crypto Format (MCF)[1] + # informal standard. Since this depends largely on the OS or the + # specific implementation of crypt(3) we only support the (sane) + # schemes implemented by glibc and BSDs. In particular the original + # DES hash is excluded since, having no structure, it would validate + # common mistakes like typing the plaintext password. + # + # [1]: https://en.wikipedia.org/wiki/Crypt_(C) + let + sep = "\\$"; + base64 = "[a-zA-Z0-9./]+"; + id = "[a-z0-9-]+"; + value = "[a-zA-Z0-9/+.-]+"; + options = "${id}(=${value})?(,${id}=${value})*"; + scheme = "${id}(${sep}${options})?"; + content = "${base64}${sep}${base64}"; + mcf = "^${sep}${scheme}${sep}${content}$"; + in + if (user.hashedPassword != null + && builtins.match mcf user.hashedPassword == null) + then + '' + The password hash of user "${name}" may be invalid. You must set a + valid hash or the user will be locked out of his account. Please + check the value of option `users.users."${name}".hashedPassword`. + '' + else null + )); + }; } diff --git a/nixos/modules/installer/cd-dvd/iso-image.nix b/nixos/modules/installer/cd-dvd/iso-image.nix index cce7cc235ec8..1cd2252ecf24 100644 --- a/nixos/modules/installer/cd-dvd/iso-image.nix +++ b/nixos/modules/installer/cd-dvd/iso-image.nix @@ -413,7 +413,7 @@ in default = false; description = '' Whether the ISO image should be compressed using - <command>bzip2</command>. + <command>zstd</command>. ''; }; diff --git a/nixos/modules/installer/cd-dvd/sd-image.nix b/nixos/modules/installer/cd-dvd/sd-image.nix index 901c60befb6c..98c12e30633c 100644 --- a/nixos/modules/installer/cd-dvd/sd-image.nix +++ b/nixos/modules/installer/cd-dvd/sd-image.nix @@ -68,7 +68,7 @@ in default = null; example = "14e19a7b-0ae0-484d-9d54-43bd6fdc20c7"; description = '' - UUID for the main NixOS partition on the SD card. + UUID for the filesystem on the main NixOS partition on the SD card. ''; }; @@ -105,7 +105,7 @@ in default = true; description = '' Whether the SD image should be compressed using - <command>bzip2</command>. + <command>zstd</command>. ''; }; @@ -130,10 +130,10 @@ in sdImage.storePaths = [ config.system.build.toplevel ]; system.build.sdImage = pkgs.callPackage ({ stdenv, dosfstools, e2fsprogs, - mtools, libfaketime, utillinux, bzip2, zstd }: stdenv.mkDerivation { + mtools, libfaketime, utillinux, zstd }: stdenv.mkDerivation { name = config.sdImage.imageName; - nativeBuildInputs = [ dosfstools e2fsprogs mtools libfaketime utillinux bzip2 zstd ]; + nativeBuildInputs = [ dosfstools e2fsprogs mtools libfaketime utillinux zstd ]; inherit (config.sdImage) compressImage; @@ -143,7 +143,7 @@ in echo "${pkgs.stdenv.buildPlatform.system}" > $out/nix-support/system if test -n "$compressImage"; then - echo "file sd-image $img.bz2" >> $out/nix-support/hydra-build-products + echo "file sd-image $img.zst" >> $out/nix-support/hydra-build-products else echo "file sd-image $img" >> $out/nix-support/hydra-build-products fi @@ -190,7 +190,7 @@ in fsck.vfat -vn firmware_part.img dd conv=notrunc if=firmware_part.img of=$img seek=$START count=$SECTORS if test -n "$compressImage"; then - bzip2 $img + zstd -T$NIX_BUILD_CORES --rm $img fi ''; }) {}; diff --git a/nixos/modules/installer/tools/nix-fallback-paths.nix b/nixos/modules/installer/tools/nix-fallback-paths.nix index bfd8970d2b2b..35a7b382b7cf 100644 --- a/nixos/modules/installer/tools/nix-fallback-paths.nix +++ b/nixos/modules/installer/tools/nix-fallback-paths.nix @@ -1,6 +1,6 @@ { - x86_64-linux = "/nix/store/xb0nl3z356n0sfrhswfli2g19a19slys-nix-2.3.5"; - i686-linux = "/nix/store/k8kdd4yy1yap6lai5idyhmzcwsjh1fik-nix-2.3.5"; - aarch64-linux = "/nix/store/dr86cbipxqjcb8pf2k0v8wvw0h0adfpz-nix-2.3.5"; - x86_64-darwin = "/nix/store/n6dqdndkv9kac66kdr988kaiyavl44x8-nix-2.3.5"; + x86_64-linux = "/nix/store/j8dbv5w6jl34caywh2ygdy88knx1mdf7-nix-2.3.6"; + i686-linux = "/nix/store/9fqvbdisahqp0238vrs7wn5anpri0a65-nix-2.3.6"; + aarch64-linux = "/nix/store/72pwn0nm9bjqx9vpi8sgh4bl6g5wh814-nix-2.3.6"; + x86_64-darwin = "/nix/store/g37vk77m90p5zcl5nixjlzp3vqpisfn5-nix-2.3.6"; } diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index 85e5534e906f..3409e7ba22ea 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -239,7 +239,6 @@ in shout = 206; gateone = 207; namecoin = 208; - dnschain = 209; #lxd = 210; # unused kibana = 211; xtreemfs = 212; @@ -549,7 +548,6 @@ in #shout = 206; #unused gateone = 207; namecoin = 208; - #dnschain = 209; #unused lxd = 210; # unused #kibana = 211; xtreemfs = 212; diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index d4e6f753e9f9..448d432853d3 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -126,6 +126,7 @@ ./programs/gpaste.nix ./programs/gnupg.nix ./programs/gphoto2.nix + ./programs/hamster.nix ./programs/iftop.nix ./programs/iotop.nix ./programs/java.nix @@ -334,6 +335,7 @@ ./services/games/minecraft-server.nix ./services/games/minetest-server.nix ./services/games/openarena.nix + ./services/games/teeworlds.nix ./services/games/terraria.nix ./services/hardware/acpid.nix ./services/hardware/actkbd.nix @@ -361,7 +363,6 @@ ./services/hardware/throttled.nix ./services/hardware/trezord.nix ./services/hardware/triggerhappy.nix - ./services/hardware/u2f.nix ./services/hardware/udev.nix ./services/hardware/udisks2.nix ./services/hardware/upower.nix @@ -462,7 +463,9 @@ ./services/misc/lidarr.nix ./services/misc/mame.nix ./services/misc/mathics.nix + ./services/misc/matrix-appservice-discord.nix ./services/misc/matrix-synapse.nix + ./services/misc/mautrix-telegram.nix ./services/misc/mbpfan.nix ./services/misc/mediatomb.nix ./services/misc/mesos-master.nix @@ -599,7 +602,6 @@ ./services/networking/dhcpcd.nix ./services/networking/dhcpd.nix ./services/networking/dnscache.nix - ./services/networking/dnschain.nix ./services/networking/dnscrypt-proxy2.nix ./services/networking/dnscrypt-wrapper.nix ./services/networking/dnsdist.nix @@ -622,6 +624,7 @@ ./services/networking/gdomap.nix ./services/networking/git-daemon.nix ./services/networking/gnunet.nix + ./services/networking/go-neb.nix ./services/networking/go-shadowsocks2.nix ./services/networking/gogoclient.nix ./services/networking/gvpe.nix @@ -804,7 +807,6 @@ ./services/security/torsocks.nix ./services/security/usbguard.nix ./services/security/vault.nix - ./services/system/cgmanager.nix ./services/system/cloud-init.nix ./services/system/dbus.nix ./services/system/earlyoom.nix diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix index be964ce7f3f9..1b3254b54a59 100644 --- a/nixos/modules/programs/bash/bash.nix +++ b/nixos/modules/programs/bash/bash.nix @@ -238,9 +238,6 @@ in "/share/bash-completion" ]; - environment.systemPackages = optional cfg.enableCompletion - pkgs.nix-bash-completions; - environment.shells = [ "/run/current-system/sw/bin/bash" "/run/current-system/sw/bin/sh" diff --git a/nixos/modules/programs/chromium.nix b/nixos/modules/programs/chromium.nix index 16c063ebc89d..3f0429136190 100644 --- a/nixos/modules/programs/chromium.nix +++ b/nixos/modules/programs/chromium.nix @@ -69,11 +69,24 @@ in extraOpts = mkOption { type = types.attrs; description = '' - Extra chromium policy options, see - <link xlink:href="https://www.chromium.org/administrators/policy-list-3">https://www.chromium.org/administrators/policy-list-3</link> - for a list of avalible options + Extra chromium policy options. A list of available policies + can be found in the Chrome Enterprise documentation: + <link xlink:href="https://cloud.google.com/docs/chrome-enterprise/policies/">https://cloud.google.com/docs/chrome-enterprise/policies/</link> + Make sure the selected policy is supported on Linux and your browser version. ''; default = {}; + example = literalExample '' + { + "BrowserSignin" = 0; + "SyncDisabled" = true; + "PasswordManagerEnabled" = false; + "SpellcheckEnabled" = true; + "SpellcheckLanguage" = [ + "de" + "en-US" + ]; + } + ''; }; }; }; diff --git a/nixos/modules/programs/hamster.nix b/nixos/modules/programs/hamster.nix new file mode 100644 index 000000000000..ddf26a22fb53 --- /dev/null +++ b/nixos/modules/programs/hamster.nix @@ -0,0 +1,15 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + meta.maintainers = maintainers.fabianhauser; + + options.programs.hamster.enable = + mkEnableOption "Whether to enable hamster time tracking."; + + config = lib.mkIf config.programs.hamster.enable { + environment.systemPackages = [ pkgs.hamster ]; + services.dbus.packages = [ pkgs.hamster ]; + }; +} diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index fc352795c017..386ded9d98b6 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -114,8 +114,9 @@ in newgrp.source = "${pkgs.shadow.out}/bin/newgrp"; newuidmap.source = "${pkgs.shadow.out}/bin/newuidmap"; newgidmap.source = "${pkgs.shadow.out}/bin/newgidmap"; - } // (if config.users.mutableUsers then { + } // lib.optionalAttrs config.users.mutableUsers { + chsh.source = "${pkgs.shadow.out}/bin/chsh"; passwd.source = "${pkgs.shadow.out}/bin/passwd"; - } else {}); + }; }; } diff --git a/nixos/modules/programs/ssh.nix b/nixos/modules/programs/ssh.nix index 44e65ee8a9a0..a983ffa4b890 100644 --- a/nixos/modules/programs/ssh.nix +++ b/nixos/modules/programs/ssh.nix @@ -194,6 +194,33 @@ in ''; }; + kexAlgorithms = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + example = [ "curve25519-sha256@libssh.org" "diffie-hellman-group-exchange-sha256" ]; + description = '' + Specifies the available KEX (Key Exchange) algorithms. + ''; + }; + + ciphers = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + example = [ "chacha20-poly1305@openssh.com" "aes256-gcm@openssh.com" ]; + description = '' + Specifies the ciphers allowed and their order of preference. + ''; + }; + + macs = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + example = [ "hmac-sha2-512-etm@openssh.com" "hmac-sha1" ]; + description = '' + Specifies the MAC (message authentication code) algorithms in order of preference. The MAC algorithm is used + for data integrity protection. + ''; + }; }; }; @@ -232,6 +259,9 @@ in ${optionalString (cfg.pubkeyAcceptedKeyTypes != []) "PubkeyAcceptedKeyTypes ${concatStringsSep "," cfg.pubkeyAcceptedKeyTypes}"} ${optionalString (cfg.hostKeyAlgorithms != []) "HostKeyAlgorithms ${concatStringsSep "," cfg.hostKeyAlgorithms}"} + ${optionalString (cfg.kexAlgorithms != null) "KexAlgorithms ${concatStringsSep "," cfg.kexAlgorithms}"} + ${optionalString (cfg.ciphers != null) "Ciphers ${concatStringsSep "," cfg.ciphers}"} + ${optionalString (cfg.macs != null) "MACs ${concatStringsSep "," cfg.macs}"} ''; environment.etc."ssh/ssh_known_hosts".text = knownHostsText; diff --git a/nixos/modules/programs/ssmtp.nix b/nixos/modules/programs/ssmtp.nix index c7a947393496..15d2750c193f 100644 --- a/nixos/modules/programs/ssmtp.nix +++ b/nixos/modules/programs/ssmtp.nix @@ -21,9 +21,11 @@ in (mkRenamedOptionModule [ "networking" "defaultMailServer" "useTLS" ] [ "services" "ssmtp" "useTLS" ]) (mkRenamedOptionModule [ "networking" "defaultMailServer" "useSTARTTLS" ] [ "services" "ssmtp" "useSTARTTLS" ]) (mkRenamedOptionModule [ "networking" "defaultMailServer" "authUser" ] [ "services" "ssmtp" "authUser" ]) - (mkRenamedOptionModule [ "networking" "defaultMailServer" "authPass" ] [ "services" "ssmtp" "authPass" ]) (mkRenamedOptionModule [ "networking" "defaultMailServer" "authPassFile" ] [ "services" "ssmtp" "authPassFile" ]) (mkRenamedOptionModule [ "networking" "defaultMailServer" "setSendmail" ] [ "services" "ssmtp" "setSendmail" ]) + + (mkRemovedOptionModule [ "networking" "defaultMailServer" "authPass" ] "authPass has been removed since it leaks the clear-text password into the world-readable store. Use authPassFile instead and make sure it's not a store path") + (mkRemovedOptionModule [ "services" "ssmtp" "authPass" ] "authPass has been removed since it leaks the clear-text password into the world-readable store. Use authPassFile instead and make sure it's not a store path") ]; options = { @@ -45,6 +47,21 @@ in ''; }; + settings = mkOption { + type = with types; attrsOf (oneOf [ bool str ]); + default = {}; + description = '' + <citerefentry><refentrytitle>ssmtp</refentrytitle><manvolnum>5</manvolnum></citerefentry> configuration. Refer + to <link xlink:href="https://linux.die.net/man/5/ssmtp.conf"/> for details on supported values. + ''; + example = literalExample '' + { + Debug = true; + FromLineOverride = false; + } + ''; + }; + hostName = mkOption { type = types.str; example = "mail.example.org"; @@ -101,18 +118,6 @@ in ''; }; - authPass = mkOption { - type = types.str; - default = ""; - example = "correctHorseBatteryStaple"; - description = '' - Password used for SMTP auth. (STORED PLAIN TEXT, WORLD-READABLE IN NIX STORE) - - It's recommended to use <option>authPassFile</option> - which takes precedence over <option>authPass</option>. - ''; - }; - authPassFile = mkOption { type = types.nullOr types.str; default = null; @@ -121,11 +126,6 @@ in Path to a file that contains the password used for SMTP auth. The file should not contain a trailing newline, if the password does not contain one. This file should be readable by the users that need to execute ssmtp. - - <option>authPassFile</option> takes precedence over <option>authPass</option>. - - Warning: when <option>authPass</option> is non-empty <option>authPassFile</option> - defaults to a file in the WORLD-READABLE Nix store containing that password. ''; }; @@ -142,25 +142,28 @@ in config = mkIf cfg.enable { - services.ssmtp.authPassFile = mkIf (cfg.authPass != "") - (mkDefault (toString (pkgs.writeTextFile { - name = "ssmtp-authpass"; - text = cfg.authPass; - }))); - - environment.etc."ssmtp/ssmtp.conf".text = - let yesNo = yes : if yes then "YES" else "NO"; in - '' - MailHub=${cfg.hostName} - FromLineOverride=YES - ${optionalString (cfg.root != "") "root=${cfg.root}"} - ${optionalString (cfg.domain != "") "rewriteDomain=${cfg.domain}"} - UseTLS=${yesNo cfg.useTLS} - UseSTARTTLS=${yesNo cfg.useSTARTTLS} - #Debug=YES - ${optionalString (cfg.authUser != "") "AuthUser=${cfg.authUser}"} - ${optionalString (cfg.authPassFile != null) "AuthPassFile=${cfg.authPassFile}"} - ''; + services.ssmtp.settings = mkMerge [ + ({ + MailHub = cfg.hostName; + FromLineOverride = mkDefault true; + UseTLS = cfg.useTLS; + UseSTARTTLS = cfg.useSTARTTLS; + }) + (mkIf (cfg.root != "") { root = cfg.root; }) + (mkIf (cfg.domain != "") { rewriteDomain = cfg.domain; }) + (mkIf (cfg.authUser != "") { AuthUser = cfg.authUser; }) + (mkIf (cfg.authPassFile != null) { AuthPassFile = cfg.authPassFile; }) + ]; + + environment.etc."ssmtp/ssmtp.conf".source = + let + toStr = value: + if value == true then "YES" + else if value == false then "NO" + else builtins.toString value + ; + in + pkgs.writeText "ssmtp.conf" (concatStringsSep "\n" (mapAttrsToList (key: value: "${key}=${toStr value}") cfg.settings)); environment.systemPackages = [pkgs.ssmtp]; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 7776c648af8a..1dc7f8533176 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -24,6 +24,7 @@ with lib; (mkRemovedOptionModule [ "environment" "blcr" "enable" ] "The BLCR module has been removed") (mkRemovedOptionModule [ "services" "beegfsEnable" ] "The BeeGFS module has been removed") (mkRemovedOptionModule [ "services" "beegfs" ] "The BeeGFS module has been removed") + (mkRemovedOptionModule ["services" "cgmanager" "enable"] "cgmanager was deprecated by lxc and therefore removed from nixpkgs.") (mkRemovedOptionModule [ "services" "osquery" ] "The osquery module has been removed") (mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed") (mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed") @@ -54,6 +55,12 @@ with lib; prey-bash-client is deprecated upstream '') + (mkRemovedOptionModule ["hardware" "u2f" ] '' + The U2F modules module was removed, as all it did was adding the + udev rules from libu2f-host to the system. Udev gained native support + to handle FIDO security tokens, so this isn't necessary anymore. + '') + # Do NOT add any option renames here, see top of the file ]; } diff --git a/nixos/modules/security/pam.nix b/nixos/modules/security/pam.nix index e1a94b0121ac..688344852aeb 100644 --- a/nixos/modules/security/pam.nix +++ b/nixos/modules/security/pam.nix @@ -436,6 +436,8 @@ let "session required ${pkgs.pam}/lib/security/pam_lastlog.so silent"} ${optionalString config.security.pam.enableEcryptfs "session optional ${pkgs.ecryptfs}/lib/security/pam_ecryptfs.so"} + ${optionalString cfg.pamMount + "session optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} ${optionalString use_ldap "session optional ${pam_ldap}/lib/security/pam_ldap.so"} ${optionalString config.services.sssd.enable @@ -452,8 +454,6 @@ let "session required ${pkgs.pam}/lib/security/pam_limits.so conf=${makeLimitsConf cfg.limits}"} ${optionalString (cfg.showMotd && config.users.motd != null) "session optional ${pkgs.pam}/lib/security/pam_motd.so motd=${motd}"} - ${optionalString cfg.pamMount - "session optional ${pkgs.pam_mount}/lib/security/pam_mount.so"} ${optionalString (cfg.enableAppArmor && config.security.apparmor.enable) "session optional ${pkgs.apparmor-pam}/lib/security/pam_apparmor.so order=user,group,default debug"} ${optionalString (cfg.enableKwallet) diff --git a/nixos/modules/services/continuous-integration/buildbot/master.nix b/nixos/modules/services/continuous-integration/buildbot/master.nix index e3da3092d459..0185f490b0c2 100644 --- a/nixos/modules/services/continuous-integration/buildbot/master.nix +++ b/nixos/modules/services/continuous-integration/buildbot/master.nix @@ -16,7 +16,7 @@ let factory = util.BuildFactory() c = BuildmasterConfig = dict( workers = [${concatStringsSep "," cfg.workers}], - protocols = { 'pb': {'port': ${toString cfg.bpPort} } }, + protocols = { 'pb': {'port': ${toString cfg.pbPort} } }, title = '${escapeStr cfg.title}', titleURL = '${escapeStr cfg.titleUrl}', buildbotURL = '${escapeStr cfg.buildbotUrl}', @@ -155,10 +155,20 @@ in { description = "Specifies the Buildbot directory."; }; - bpPort = mkOption { + pbPort = mkOption { default = 9989; - type = types.int; - description = "Port where the master will listen to Buildbot Worker."; + type = types.either types.str types.int; + example = "'tcp:9990:interface=127.0.0.1'"; + description = '' + The buildmaster will listen on a TCP port of your choosing + for connections from workers. + It can also use this port for connections from remote Change Sources, + status clients, and debug tools. + This port should be visible to the outside world, and you’ll need to tell + your worker admins about your choice. + If put in (single) quotes, this can also be used as a connection string, + as defined in the <link xlink:href="https://twistedmatrix.com/documents/current/core/howto/endpoints.html">ConnectionStrings guide</link>. + ''; }; listenAddress = mkOption { @@ -264,5 +274,9 @@ in { }; }; + imports = [ + (mkRenamedOptionModule [ "services" "buildbot-master" "bpPort" ] [ "services" "buildbot-master" "pbPort" ]) + ]; + meta.maintainers = with lib.maintainers; [ nand0p mic92 ]; } diff --git a/nixos/modules/services/databases/mysql.nix b/nixos/modules/services/databases/mysql.nix index 51885881cf73..2e8c5b7640b2 100644 --- a/nixos/modules/services/databases/mysql.nix +++ b/nixos/modules/services/databases/mysql.nix @@ -334,7 +334,8 @@ in environment.etc."my.cnf".source = cfg.configFile; systemd.tmpfiles.rules = [ - "d '${cfg.dataDir}' 0700 ${cfg.user} mysql -" + "d '${cfg.dataDir}' 0700 ${cfg.user} mysql - -" + "z '${cfg.dataDir}' 0700 ${cfg.user} mysql - -" ]; systemd.services.mysql = let @@ -357,21 +358,17 @@ in preStart = if isMariaDB then '' if ! test -e ${cfg.dataDir}/mysql; then ${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${mysqldOptions} - touch /tmp/mysql_init + touch ${cfg.dataDir}/mysql_init fi '' else '' if ! test -e ${cfg.dataDir}/mysql; then ${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} --initialize-insecure - touch /tmp/mysql_init + touch ${cfg.dataDir}/mysql_init fi ''; serviceConfig = { - User = cfg.user; - Group = "mysql"; Type = if hasNotify then "notify" else "simple"; - RuntimeDirectory = "mysqld"; - RuntimeDirectoryMode = "0755"; Restart = "on-abort"; RestartSec = "5s"; # The last two environment variables are used for starting Galera clusters @@ -398,7 +395,7 @@ in done ''} - if [ -f /tmp/mysql_init ] + if [ -f ${cfg.dataDir}/mysql_init ] then ${concatMapStrings (database: '' # Create initial databases @@ -452,7 +449,7 @@ in cat ${toString cfg.initialScript} | ${mysql}/bin/mysql -u root -N ''} - rm /tmp/mysql_init + rm ${cfg.dataDir}/mysql_init fi ${optionalString (cfg.ensureDatabases != []) '' @@ -476,6 +473,35 @@ in # ensureDatbases & ensureUsers depends on this script being run as root # when the user has secured their mysql install "+${setupScript}"; + # User and group + User = cfg.user; + Group = "mysql"; + # Runtime directory and mode + RuntimeDirectory = "mysqld"; + RuntimeDirectoryMode = "0755"; + # Access write directories + ReadWritePaths = [ cfg.dataDir ]; + # Capabilities + CapabilityBoundingSet = ""; + # Security + NoNewPrivileges = true; + # Sandboxing + ProtectSystem = "strict"; + ProtectHome = true; + PrivateTmp = true; + PrivateDevices = true; + ProtectHostname = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + PrivateMounts = true; + # System Call Filtering + SystemCallArchitectures = "native"; }; }; diff --git a/nixos/modules/services/databases/redis.nix b/nixos/modules/services/databases/redis.nix index 799c3db62166..f1777854e141 100644 --- a/nixos/modules/services/databases/redis.nix +++ b/nixos/modules/services/databases/redis.nix @@ -218,6 +218,7 @@ in description = "Redis database user"; isSystemUser = true; }; + users.groups.redis = {}; environment.systemPackages = [ cfg.package ]; @@ -240,6 +241,7 @@ in StateDirectory = "redis"; Type = "notify"; User = "redis"; + Group = "redis"; }; }; }; diff --git a/nixos/modules/services/games/teeworlds.nix b/nixos/modules/services/games/teeworlds.nix new file mode 100644 index 000000000000..babf989c98ca --- /dev/null +++ b/nixos/modules/services/games/teeworlds.nix @@ -0,0 +1,119 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.teeworlds; + register = cfg.register; + + teeworldsConf = pkgs.writeText "teeworlds.cfg" '' + sv_port ${toString cfg.port} + sv_register ${if cfg.register then "1" else "0"} + ${optionalString (cfg.name != null) "sv_name ${cfg.name}"} + ${optionalString (cfg.motd != null) "sv_motd ${cfg.motd}"} + ${optionalString (cfg.password != null) "password ${cfg.password}"} + ${optionalString (cfg.rconPassword != null) "sv_rcon_password ${cfg.rconPassword}"} + ${concatStringsSep "\n" cfg.extraOptions} + ''; + +in +{ + options = { + services.teeworlds = { + enable = mkEnableOption "Teeworlds Server"; + + openPorts = mkOption { + type = types.bool; + default = false; + description = "Whether to open firewall ports for Teeworlds"; + }; + + name = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Name of the server. Defaults to 'unnamed server'. + ''; + }; + + register = mkOption { + type = types.bool; + example = true; + default = false; + description = '' + Whether the server registers as public server in the global server list. This is disabled by default because of privacy. + ''; + }; + + motd = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Set the server message of the day text. + ''; + }; + + password = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Password to connect to the server. + ''; + }; + + rconPassword = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Password to access the remote console. If not set, a randomly generated one is displayed in the server log. + ''; + }; + + port = mkOption { + type = types.int; + default = 8303; + description = '' + Port the server will listen on. + ''; + }; + + extraOptions = mkOption { + type = types.listOf types.str; + default = []; + description = '' + Extra configuration lines for the <filename>teeworlds.cfg</filename>. See <link xlink:href="https://www.teeworlds.com/?page=docs&wiki=server_settings">Teeworlds Documentation</link>. + ''; + example = [ "sv_map dm1" "sv_gametype dm" ]; + }; + }; + }; + + config = mkIf cfg.enable { + networking.firewall = mkIf cfg.openPorts { + allowedUDPPorts = [ cfg.port ]; + }; + + systemd.services.teeworlds = { + description = "Teeworlds Server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + serviceConfig = { + DynamicUser = true; + ExecStart = "${pkgs.teeworlds}/bin/teeworlds_srv -f ${teeworldsConf}"; + + # Hardening + CapabilityBoundingSet = false; + PrivateDevices = true; + PrivateUsers = true; + ProtectHome = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + SystemCallArchitectures = "native"; + }; + }; + }; +} diff --git a/nixos/modules/services/hardware/fwupd.nix b/nixos/modules/services/hardware/fwupd.nix index e586af25c2b1..222ac8e487eb 100644 --- a/nixos/modules/services/hardware/fwupd.nix +++ b/nixos/modules/services/hardware/fwupd.nix @@ -6,6 +6,23 @@ with lib; let cfg = config.services.fwupd; + + customEtc = { + "fwupd/daemon.conf" = { + source = pkgs.writeText "daemon.conf" '' + [fwupd] + BlacklistDevices=${lib.concatStringsSep ";" cfg.blacklistDevices} + BlacklistPlugins=${lib.concatStringsSep ";" cfg.blacklistPlugins} + ''; + }; + "fwupd/uefi.conf" = { + source = pkgs.writeText "uefi.conf" '' + [uefi] + OverrideESPMountPoint=${config.boot.loader.efi.efiSysMountPoint} + ''; + }; + }; + originalEtc = let mkEtcFile = n: nameValuePair n { source = "${cfg.package}/etc/${n}"; }; @@ -96,22 +113,8 @@ in { environment.systemPackages = [ cfg.package ]; - environment.etc = { - "fwupd/daemon.conf" = { - source = pkgs.writeText "daemon.conf" '' - [fwupd] - BlacklistDevices=${lib.concatStringsSep ";" cfg.blacklistDevices} - BlacklistPlugins=${lib.concatStringsSep ";" cfg.blacklistPlugins} - ''; - }; - "fwupd/uefi.conf" = { - source = pkgs.writeText "uefi.conf" '' - [uefi] - OverrideESPMountPoint=${config.boot.loader.efi.efiSysMountPoint} - ''; - }; - - } // originalEtc // extraTrustedKeys // testRemote; + # customEtc overrides some files from the package + environment.etc = originalEtc // customEtc // extraTrustedKeys // testRemote; services.dbus.packages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/u2f.nix b/nixos/modules/services/hardware/u2f.nix deleted file mode 100644 index bb4b2f05f890..000000000000 --- a/nixos/modules/services/hardware/u2f.nix +++ /dev/null @@ -1,23 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; -let - cfg = config.hardware.u2f; -in { - options = { - hardware.u2f = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable U2F hardware support. - ''; - }; - }; - }; - - config = mkIf cfg.enable { - services.udev.packages = [ pkgs.libu2f-host ]; - }; -} - diff --git a/nixos/modules/services/mail/dovecot.nix b/nixos/modules/services/mail/dovecot.nix index 9fbf0c19752c..51cbcbf1cbc8 100644 --- a/nixos/modules/services/mail/dovecot.nix +++ b/nixos/modules/services/mail/dovecot.nix @@ -125,6 +125,8 @@ let mailboxConfig = mailbox: '' mailbox "${mailbox.name}" { auto = ${toString mailbox.auto} + '' + optionalString (mailbox.autoexpunge != null) '' + autoexpunge = ${mailbox.autoexpunge} '' + optionalString (mailbox.specialUse != null) '' special_use = \${toString mailbox.specialUse} '' + "}"; @@ -132,8 +134,9 @@ let mailboxes = { ... }: { options = { name = mkOption { - type = types.strMatching ''[^"]+''; + type = types.nullOr (types.strMatching ''[^"]+''); example = "Spam"; + default = null; description = "The name of the mailbox."; }; auto = mkOption { @@ -148,6 +151,15 @@ let example = "Junk"; description = "Null if no special use flag is set. Other than that every use flag mentioned in the RFC is valid."; }; + autoexpunge = mkOption { + type = types.nullOr types.str; + default = null; + example = "60d"; + description = '' + To automatically remove all email from the mailbox which is older than the + specified time. + ''; + }; }; }; in @@ -323,9 +335,24 @@ in }; mailboxes = mkOption { - type = types.listOf (types.submodule mailboxes); - default = []; - example = [ { name = "Spam"; specialUse = "Junk"; auto = "create"; } ]; + type = with types; let m = submodule mailboxes; in either (listOf m) (attrsOf m); + default = {}; + apply = x: + if isList x then warn "Declaring `services.dovecot2.mailboxes' as a list is deprecated and will break eval in 21.03!" x + else mapAttrsToList (name: value: + if value.name != null + then throw '' + When specifying dovecot2 mailboxes as attributes, declaring + a `name'-attribute is prohibited! The name ${value.name} should + be the attribute key! + '' + else value // { inherit name; } + ) x; + example = literalExample '' + { + Spam = { specialUse = "Junk"; auto = "create"; }; + } + ''; description = "Configure mailboxes and auto create or subscribe them."; }; diff --git a/nixos/modules/services/mail/opensmtpd.nix b/nixos/modules/services/mail/opensmtpd.nix index 1fabe2da45c5..c838d3b949db 100644 --- a/nixos/modules/services/mail/opensmtpd.nix +++ b/nixos/modules/services/mail/opensmtpd.nix @@ -17,6 +17,10 @@ in { ###### interface + imports = [ + (mkRenamedOptionModule [ "services" "opensmtpd" "addSendmailToSystemPath" ] [ "services" "opensmtpd" "setSendmail" ]) + ]; + options = { services.opensmtpd = { @@ -34,13 +38,10 @@ in { description = "The OpenSMTPD package to use."; }; - addSendmailToSystemPath = mkOption { + setSendmail = mkOption { type = types.bool; default = true; - description = '' - Whether to add OpenSMTPD's sendmail binary to the - system path or not. - ''; + description = "Whether to set the system sendmail to OpenSMTPD's."; }; extraServerArgs = mkOption { @@ -82,7 +83,7 @@ in { ###### implementation - config = mkIf cfg.enable { + config = mkIf cfg.enable rec { users.groups = { smtpd.gid = config.ids.gids.smtpd; smtpq.gid = config.ids.gids.smtpq; @@ -101,6 +102,14 @@ in { }; }; + security.wrappers.smtpctl = { + group = "smtpq"; + setgid = true; + source = "${cfg.package}/bin/smtpctl"; + }; + + services.mail.sendmailSetuidWrapper = mkIf cfg.setSendmail security.wrappers.smtpctl; + systemd.tmpfiles.rules = [ "d /var/spool/smtpd 711 root - - -" "d /var/spool/smtpd/offline 770 root smtpq - -" @@ -119,7 +128,5 @@ in { serviceConfig.ExecStart = "${cfg.package}/sbin/smtpd -d -f ${conf} ${args}"; environment.OPENSMTPD_PROC_PATH = "${procEnv}/libexec/opensmtpd"; }; - - environment.systemPackages = mkIf cfg.addSendmailToSystemPath [ sendmail ]; }; } diff --git a/nixos/modules/services/misc/freeswitch.nix b/nixos/modules/services/misc/freeswitch.nix index d27dbe220d3c..b42f36e86637 100644 --- a/nixos/modules/services/misc/freeswitch.nix +++ b/nixos/modules/services/misc/freeswitch.nix @@ -95,9 +95,11 @@ in { -conf ${configPath} \\ -base /var/lib/freeswitch"; ExecReload = "${pkg}/bin/fs_cli -x reloadxml"; - Restart = "always"; + Restart = "on-failure"; RestartSec = "5s"; + CPUSchedulingPolicy = "fifo"; }; }; + environment.systemPackages = [ pkg ]; }; } diff --git a/nixos/modules/services/misc/gitlab.nix b/nixos/modules/services/misc/gitlab.nix index 730166b04d20..1ada131bd7ba 100644 --- a/nixos/modules/services/misc/gitlab.nix +++ b/nixos/modules/services/misc/gitlab.nix @@ -43,6 +43,9 @@ let [gitlab-shell] dir = "${cfg.packages.gitlab-shell}" + secret_file = "${cfg.statePath}/gitlab_shell_secret" + gitlab_url = "http+unix://${pathUrlQuote gitlabSocket}" + http_settings = { self_signed_cert = false } ${concatStringsSep "\n" (attrValues (mapAttrs (k: v: '' [[storage]] @@ -129,7 +132,7 @@ let HOME = "${cfg.statePath}/home"; UNICORN_PATH = "${cfg.statePath}/"; GITLAB_PATH = "${cfg.packages.gitlab}/share/gitlab/"; - SCHEMA = "${cfg.statePath}/db/schema.rb"; + SCHEMA = "${cfg.statePath}/db/structure.sql"; GITLAB_UPLOADS_PATH = "${cfg.statePath}/uploads"; GITLAB_LOG_PATH = "${cfg.statePath}/log"; GITLAB_REDIS_CONFIG_FILE = pkgs.writeText "redis.yml" (builtins.toJSON redisConfig); diff --git a/nixos/modules/services/misc/home-assistant.nix b/nixos/modules/services/misc/home-assistant.nix index 86033d02bf3f..8ce2437841b0 100644 --- a/nixos/modules/services/misc/home-assistant.nix +++ b/nixos/modules/services/misc/home-assistant.nix @@ -11,9 +11,9 @@ let (recursiveUpdate defaultConfig cfg.config) else cfg.config)); configFile = pkgs.runCommand "configuration.yaml" { preferLocalBuild = true; } '' ${pkgs.remarshal}/bin/json2yaml -i ${configJSON} -o $out - # Hack to support secrets, that are encoded as custom yaml objects, - # https://www.home-assistant.io/docs/configuration/secrets/ - sed -i -e "s/'\!secret \(.*\)'/\!secret \1/" $out + # Hack to support custom yaml objects, + # i.e. secrets: https://www.home-assistant.io/docs/configuration/secrets/ + sed -i -e "s/'\!\([a-z_]\+\) \(.*\)'/\!\1 \2/;s/^\!\!/\!/;" $out ''; lovelaceConfigJSON = pkgs.writeText "ui-lovelace.json" @@ -120,7 +120,9 @@ in { unit_system = "metric"; time_zone = "UTC"; }; - frontend = { }; + frontend = { + themes = "!include_dir_merge_named themes"; + }; http = { }; feedreader.urls = [ "https://nixos.org/blogs.xml" ]; } diff --git a/nixos/modules/services/misc/matrix-appservice-discord.nix b/nixos/modules/services/misc/matrix-appservice-discord.nix new file mode 100644 index 000000000000..49c41ff637a8 --- /dev/null +++ b/nixos/modules/services/misc/matrix-appservice-discord.nix @@ -0,0 +1,162 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + dataDir = "/var/lib/matrix-appservice-discord"; + registrationFile = "${dataDir}/discord-registration.yaml"; + appDir = "${pkgs.matrix-appservice-discord}/lib/node_modules/matrix-appservice-discord"; + cfg = config.services.matrix-appservice-discord; + # TODO: switch to configGen.json once RFC42 is implemented + settingsFile = pkgs.writeText "matrix-appservice-discord-settings.json" (builtins.toJSON cfg.settings); + +in { + options = { + services.matrix-appservice-discord = { + enable = mkEnableOption "a bridge between Matrix and Discord"; + + settings = mkOption rec { + # TODO: switch to types.config.json as prescribed by RFC42 once it's implemented + type = types.attrs; + apply = recursiveUpdate default; + default = { + database = { + filename = "${dataDir}/discord.db"; + + # TODO: remove those old config keys once the following issues are solved: + # * https://github.com/Half-Shot/matrix-appservice-discord/issues/490 + # * https://github.com/Half-Shot/matrix-appservice-discord/issues/498 + userStorePath = "${dataDir}/user-store.db"; + roomStorePath = "${dataDir}/room-store.db"; + }; + + # empty values necessary for registration file generation + # actual values defined in environmentFile + auth = { + clientID = ""; + botToken = ""; + }; + }; + example = literalExample '' + { + bridge = { + domain = "public-domain.tld"; + homeserverUrl = "http://public-domain.tld:8008"; + }; + } + ''; + description = '' + <filename>config.yaml</filename> configuration as a Nix attribute set. + </para> + + <para> + Configuration options should match those described in + <link xlink:href="https://github.com/Half-Shot/matrix-appservice-discord/blob/master/config/config.sample.yaml"> + config.sample.yaml</link>. + </para> + + <para> + <option>config.bridge.domain</option> and <option>config.bridge.homeserverUrl</option> + should be set to match the public host name of the Matrix homeserver for webhooks and avatars to work. + </para> + + <para> + Secret tokens should be specified using <option>environmentFile</option> + instead of this world-readable attribute set. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + File containing environment variables to be passed to the matrix-appservice-discord service, + in which secret tokens can be specified securely by defining values for + <literal>APPSERVICE_DISCORD_AUTH_CLIENT_I_D</literal> and + <literal>APPSERVICE_DISCORD_AUTH_BOT_TOKEN</literal>. + ''; + }; + + url = mkOption { + type = types.str; + default = "http://localhost:${toString cfg.port}"; + description = '' + The URL where the application service is listening for HS requests. + ''; + }; + + port = mkOption { + type = types.port; + default = 9005; # from https://github.com/Half-Shot/matrix-appservice-discord/blob/master/package.json#L11 + description = '' + Port number on which the bridge should listen for internal communication with the Matrix homeserver. + ''; + }; + + localpart = mkOption { + type = with types; nullOr str; + default = null; + description = '' + The user_id localpart to assign to the AS. + ''; + }; + + serviceDependencies = mkOption { + type = with types; listOf str; + default = optional config.services.matrix-synapse.enable "matrix-synapse.service"; + description = '' + List of Systemd services to require and wait for when starting the application service, + such as the Matrix homeserver if it's running on the same host. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.matrix-appservice-discord = { + description = "A bridge between Matrix and Discord."; + + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ] ++ cfg.serviceDependencies; + after = [ "network-online.target" ] ++ cfg.serviceDependencies; + + preStart = '' + if [ ! -f '${registrationFile}' ]; then + ${pkgs.matrix-appservice-discord}/bin/matrix-appservice-discord \ + --generate-registration \ + --url=${escapeShellArg cfg.url} \ + ${optionalString (cfg.localpart != null) "--localpart=${escapeShellArg cfg.localpart}"} \ + --config='${settingsFile}' \ + --file='${registrationFile}' + fi + ''; + + serviceConfig = { + Type = "simple"; + Restart = "always"; + + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + + DynamicUser = true; + PrivateTmp = true; + WorkingDirectory = appDir; + StateDirectory = baseNameOf dataDir; + UMask = 0027; + EnvironmentFile = cfg.environmentFile; + + ExecStart = '' + ${pkgs.matrix-appservice-discord}/bin/matrix-appservice-discord \ + --file='${registrationFile}' \ + --config='${settingsFile}' \ + --port='${toString cfg.port}' + ''; + }; + }; + }; + + meta.maintainers = with maintainers; [ pacien ]; +} diff --git a/nixos/modules/services/misc/matrix-synapse.nix b/nixos/modules/services/misc/matrix-synapse.nix index 703bc9416f88..e982eb16fa70 100644 --- a/nixos/modules/services/misc/matrix-synapse.nix +++ b/nixos/modules/services/misc/matrix-synapse.nix @@ -9,6 +9,9 @@ let logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig; mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${boolToString r.compress}}''; mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${boolToString l.tls}, x_forwarded: ${boolToString l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}''; + pluginsEnv = cfg.package.python.buildEnv.override { + extraLibs = cfg.plugins; + }; configFile = pkgs.writeText "homeserver.yaml" '' ${optionalString (cfg.tls_certificate_path != null) '' tls_certificate_path: "${cfg.tls_certificate_path}" @@ -125,6 +128,14 @@ in { Overridable attribute of the matrix synapse server package to use. ''; }; + plugins = mkOption { + type = types.listOf types.package; + default = [ ]; + defaultText = "with config.services.matrix-synapse.package.plugins [ matrix-synapse-ldap3 matrix-synapse-pam ]"; + description = '' + List of additional Matrix plugins to make available. + ''; + }; no_tls = mkOption { type = types.bool; default = false; @@ -686,6 +697,7 @@ in { --keys-directory ${cfg.dataDir} \ --generate-keys ''; + environment.PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ]; serviceConfig = { Type = "notify"; User = "matrix-synapse"; @@ -715,5 +727,6 @@ in { ]; meta.doc = ./matrix-synapse.xml; + meta.maintainers = teams.matrix.members; } diff --git a/nixos/modules/services/misc/mautrix-telegram.nix b/nixos/modules/services/misc/mautrix-telegram.nix new file mode 100644 index 000000000000..78a42fbb574b --- /dev/null +++ b/nixos/modules/services/misc/mautrix-telegram.nix @@ -0,0 +1,163 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + dataDir = "/var/lib/mautrix-telegram"; + registrationFile = "${dataDir}/telegram-registration.yaml"; + cfg = config.services.mautrix-telegram; + # TODO: switch to configGen.json once RFC42 is implemented + settingsFile = pkgs.writeText "mautrix-telegram-settings.json" (builtins.toJSON cfg.settings); + +in { + options = { + services.mautrix-telegram = { + enable = mkEnableOption "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge"; + + settings = mkOption rec { + # TODO: switch to types.config.json as prescribed by RFC42 once it's implemented + type = types.attrs; + apply = recursiveUpdate default; + default = { + appservice = rec { + database = "sqlite:///${dataDir}/mautrix-telegram.db"; + hostname = "0.0.0.0"; + port = 8080; + address = "http://localhost:${toString port}"; + }; + + bridge = { + permissions."*" = "relaybot"; + relaybot.whitelist = [ ]; + }; + + logging = { + version = 1; + + formatters.precise.format = "[%(levelname)s@%(name)s] %(message)s"; + + handlers.console = { + class = "logging.StreamHandler"; + formatter = "precise"; + }; + + loggers = { + mau.level = "INFO"; + telethon.level = "INFO"; + + # prevent tokens from leaking in the logs: + # https://github.com/tulir/mautrix-telegram/issues/351 + aiohttp.level = "WARNING"; + }; + + # log to console/systemd instead of file + root = { + level = "INFO"; + handlers = [ "console" ]; + }; + }; + }; + example = literalExample '' + { + homeserver = { + address = "http://localhost:8008"; + domain = "public-domain.tld"; + }; + + appservice.public = { + prefix = "/public"; + external = "https://public-appservice-address/public"; + }; + + bridge.permissions = { + "example.com" = "full"; + "@admin:example.com" = "admin"; + }; + } + ''; + description = '' + <filename>config.yaml</filename> configuration as a Nix attribute set. + Configuration options should match those described in + <link xlink:href="https://github.com/tulir/mautrix-telegram/blob/master/example-config.yaml"> + example-config.yaml</link>. + </para> + + <para> + Secret tokens should be specified using <option>environmentFile</option> + instead of this world-readable attribute set. + ''; + }; + + environmentFile = mkOption { + type = types.nullOr types.path; + default = null; + description = '' + File containing environment variables to be passed to the mautrix-telegram service, + in which secret tokens can be specified securely by defining values for + <literal>MAUTRIX_TELEGRAM_APPSERVICE_AS_TOKEN</literal>, + <literal>MAUTRIX_TELEGRAM_APPSERVICE_HS_TOKEN</literal>, + <literal>MAUTRIX_TELEGRAM_TELEGRAM_API_ID</literal>, + <literal>MAUTRIX_TELEGRAM_TELEGRAM_API_HASH</literal> and optionally + <literal>MAUTRIX_TELEGRAM_TELEGRAM_BOT_TOKEN</literal>. + ''; + }; + + serviceDependencies = mkOption { + type = with types; listOf str; + default = optional config.services.matrix-synapse.enable "matrix-synapse.service"; + description = '' + List of Systemd services to require and wait for when starting the application service. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + systemd.services.mautrix-telegram = { + description = "Mautrix-Telegram, a Matrix-Telegram hybrid puppeting/relaybot bridge."; + + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ] ++ cfg.serviceDependencies; + after = [ "network-online.target" ] ++ cfg.serviceDependencies; + + preStart = '' + # generate the appservice's registration file if absent + if [ ! -f '${registrationFile}' ]; then + ${pkgs.mautrix-telegram}/bin/mautrix-telegram \ + --generate-registration \ + --base-config='${pkgs.mautrix-telegram}/example-config.yaml' \ + --config='${settingsFile}' \ + --registration='${registrationFile}' + fi + + # run automatic database init and migration scripts + ${pkgs.mautrix-telegram.alembic}/bin/alembic -x config='${settingsFile}' upgrade head + ''; + + serviceConfig = { + Type = "simple"; + Restart = "always"; + + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + + DynamicUser = true; + PrivateTmp = true; + WorkingDirectory = pkgs.mautrix-telegram; # necessary for the database migration scripts to be found + StateDirectory = baseNameOf dataDir; + UMask = 0027; + EnvironmentFile = cfg.environmentFile; + + ExecStart = '' + ${pkgs.mautrix-telegram}/bin/mautrix-telegram \ + --config='${settingsFile}' + ''; + }; + }; + }; + + meta.maintainers = with maintainers; [ pacien vskilet ]; +} diff --git a/nixos/modules/services/misc/nix-daemon.nix b/nixos/modules/services/misc/nix-daemon.nix index 2577cb78e96e..0b3d7f3f03c3 100644 --- a/nixos/modules/services/misc/nix-daemon.nix +++ b/nixos/modules/services/misc/nix-daemon.nix @@ -442,6 +442,12 @@ in nix.binaryCachePublicKeys = [ "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY=" ]; nix.binaryCaches = [ "https://cache.nixos.org/" ]; + environment.systemPackages = + [ nix + pkgs.nix-info + ] + ++ optional (config.programs.bash.enableCompletion && !versionAtLeast nixVersion "2.4pre") pkgs.nix-bash-completions; + environment.etc."nix/nix.conf".source = nixConf; environment.etc."nix/registry.json".text = builtins.toJSON { diff --git a/nixos/modules/services/monitoring/prometheus/exporters.nix b/nixos/modules/services/monitoring/prometheus/exporters.nix index f9ad1457fc85..0318acae50f7 100644 --- a/nixos/modules/services/monitoring/prometheus/exporters.nix +++ b/nixos/modules/services/monitoring/prometheus/exporters.nix @@ -21,6 +21,7 @@ let # `serviceOpts.script` or `serviceOpts.serviceConfig.ExecStart` exporterOpts = genAttrs [ + "apcupsd" "bind" "blackbox" "collectd" @@ -28,6 +29,8 @@ let "dovecot" "fritzbox" "json" + "keylight" + "lnd" "mail" "mikrotik" "minio" diff --git a/nixos/modules/services/monitoring/prometheus/exporters/apcupsd.nix b/nixos/modules/services/monitoring/prometheus/exporters/apcupsd.nix new file mode 100644 index 000000000000..57c35a742c5f --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/apcupsd.nix @@ -0,0 +1,38 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.apcupsd; +in +{ + port = 9162; + extraOpts = { + apcupsdAddress = mkOption { + type = types.str; + default = ":3551"; + description = '' + Address of the apcupsd Network Information Server (NIS). + ''; + }; + + apcupsdNetwork = mkOption { + type = types.enum ["tcp" "tcp4" "tcp6"]; + default = "tcp"; + description = '' + Network of the apcupsd Network Information Server (NIS): one of "tcp", "tcp4", or "tcp6". + ''; + }; + }; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-apcupsd-exporter}/bin/apcupsd_exporter \ + -telemetry.addr ${cfg.listenAddress}:${toString cfg.port} \ + -apcupsd.addr ${cfg.apcupsdAddress} \ + -apcupsd.network ${cfg.apcupsdNetwork} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/keylight.nix b/nixos/modules/services/monitoring/prometheus/exporters/keylight.nix new file mode 100644 index 000000000000..dfa56343b871 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/keylight.nix @@ -0,0 +1,19 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.keylight; +in +{ + port = 9288; + serviceOpts = { + serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-keylight-exporter}/bin/keylight_exporter \ + -metrics.addr ${cfg.listenAddress}:${toString cfg.port} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + }; + }; +} diff --git a/nixos/modules/services/monitoring/prometheus/exporters/lnd.nix b/nixos/modules/services/monitoring/prometheus/exporters/lnd.nix new file mode 100644 index 000000000000..35f972020574 --- /dev/null +++ b/nixos/modules/services/monitoring/prometheus/exporters/lnd.nix @@ -0,0 +1,46 @@ +{ config, lib, pkgs, options }: + +with lib; + +let + cfg = config.services.prometheus.exporters.lnd; +in +{ + port = 9092; + extraOpts = { + lndHost = mkOption { + type = types.str; + default = "localhost:10009"; + description = '' + lnd instance gRPC address:port. + ''; + }; + + lndTlsPath = mkOption { + type = types.path; + description = '' + Path to lnd TLS certificate. + ''; + }; + + lndMacaroonDir = mkOption { + type = types.path; + description = '' + Path to lnd macaroons. + ''; + }; + }; + serviceOpts.serviceConfig = { + ExecStart = '' + ${pkgs.prometheus-lnd-exporter}/bin/lndmon \ + --prometheus.listenaddr=${cfg.listenAddress}:${toString cfg.port} \ + --prometheus.logdir=/var/log/prometheus-lnd-exporter \ + --lnd.host=${cfg.lndHost} \ + --lnd.tlspath=${cfg.lndTlsPath} \ + --lnd.macaroondir=${cfg.lndMacaroonDir} \ + ${concatStringsSep " \\\n " cfg.extraFlags} + ''; + LogsDirectory = "prometheus-lnd-exporter"; + ReadOnlyPaths = [ cfg.lndTlsPath cfg.lndMacaroonDir ]; + }; +} diff --git a/nixos/modules/services/network-filesystems/ipfs.nix b/nixos/modules/services/network-filesystems/ipfs.nix index 1f5c14d777d7..a3bd40135d19 100644 --- a/nixos/modules/services/network-filesystems/ipfs.nix +++ b/nixos/modules/services/network-filesystems/ipfs.nix @@ -1,69 +1,17 @@ -{ config, lib, pkgs, ... }: +{ config, lib, pkgs, options, ... }: with lib; let - inherit (pkgs) ipfs runCommand makeWrapper; - cfg = config.services.ipfs; + opt = options.services.ipfs; ipfsFlags = toString ([ (optionalString cfg.autoMount "--mount") - #(optionalString cfg.autoMigrate "--migrate") (optionalString cfg.enableGC "--enable-gc") (optionalString (cfg.serviceFdlimit != null) "--manage-fdlimit=false") (optionalString (cfg.defaultMode == "offline") "--offline") (optionalString (cfg.defaultMode == "norouting") "--routing=none") ] ++ cfg.extraFlags); - defaultDataDir = if versionAtLeast config.system.stateVersion "17.09" then - "/var/lib/ipfs" else - "/var/lib/ipfs/.ipfs"; - - # Wrapping the ipfs binary with the environment variable IPFS_PATH set to dataDir because we can't set it in the user environment - wrapped = runCommand "ipfs" { buildInputs = [ makeWrapper ]; preferLocalBuild = true; } '' - mkdir -p "$out/bin" - makeWrapper "${ipfs}/bin/ipfs" "$out/bin/ipfs" \ - --set IPFS_PATH ${cfg.dataDir} \ - --prefix PATH : /run/wrappers/bin - ''; - - - commonEnv = { - environment.IPFS_PATH = cfg.dataDir; - path = [ wrapped ]; - serviceConfig.User = cfg.user; - serviceConfig.Group = cfg.group; - }; - - baseService = recursiveUpdate commonEnv { - wants = [ "ipfs-init.service" ]; - # NB: migration must be performed prior to pre-start, else we get the failure message! - preStart = optionalString cfg.autoMount '' - ipfs --local config Mounts.FuseAllowOther --json true - ipfs --local config Mounts.IPFS ${cfg.ipfsMountDir} - ipfs --local config Mounts.IPNS ${cfg.ipnsMountDir} - '' + concatStringsSep "\n" (collect - isString - (mapAttrsRecursive - (path: value: - # Using heredoc below so that the value is never improperly quoted - '' - read value <<EOF - ${builtins.toJSON value} - EOF - ipfs --local config --json "${concatStringsSep "." path}" "$value" - '') - ({ Addresses.API = cfg.apiAddress; - Addresses.Gateway = cfg.gatewayAddress; - Addresses.Swarm = cfg.swarmAddress; - } // - cfg.extraConfig)) - ); - serviceConfig = { - ExecStart = "${wrapped}/bin/ipfs daemon ${ipfsFlags}"; - Restart = "on-failure"; - RestartSec = 1; - } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; }; - }; in { ###### interface @@ -88,7 +36,9 @@ in { dataDir = mkOption { type = types.str; - default = defaultDataDir; + default = if versionAtLeast config.system.stateVersion "17.09" + then "/var/lib/ipfs" + else "/var/lib/ipfs/.ipfs"; description = "The data dir for IPFS"; }; @@ -98,18 +48,6 @@ in { description = "systemd service that is enabled by default"; }; - /* - autoMigrate = mkOption { - type = types.bool; - default = false; - description = '' - Whether IPFS should try to migrate the file system automatically. - - The daemon will need to be able to download a binary from https://ipfs.io to perform the migration. - ''; - }; - */ - autoMount = mkOption { type = types.bool; default = false; @@ -199,13 +137,21 @@ in { example = 64*1024; }; + startWhenNeeded = mkOption { + type = types.bool; + default = false; + description = "Whether to use socket activation to start IPFS when needed."; + }; + }; }; ###### implementation config = mkIf cfg.enable { - environment.systemPackages = [ wrapped ]; + environment.systemPackages = [ pkgs.ipfs ]; + environment.variables.IPFS_PATH = cfg.dataDir; + programs.fuse = mkIf cfg.autoMount { userAllowOther = true; }; @@ -234,10 +180,14 @@ in { "d '${cfg.ipnsMountDir}' - ${cfg.user} ${cfg.group} - -" ]; - systemd.services.ipfs-init = recursiveUpdate commonEnv { + systemd.packages = [ pkgs.ipfs ]; + + systemd.services.ipfs-init = { description = "IPFS Initializer"; - before = [ "ipfs.service" "ipfs-offline.service" "ipfs-norouting.service" ]; + environment.IPFS_PATH = cfg.dataDir; + + path = [ pkgs.ipfs ]; script = '' if [[ ! -f ${cfg.dataDir}/config ]]; then @@ -251,34 +201,63 @@ in { fi ''; + wantedBy = [ "default.target" ]; + serviceConfig = { Type = "oneshot"; RemainAfterExit = true; + User = cfg.user; + Group = cfg.group; }; }; - # TODO These 3 definitions possibly be further abstracted through use of a function - # like: mutexServices "ipfs" [ "", "offline", "norouting" ] { ... shared conf here ... } + systemd.services.ipfs = { + path = [ "/run/wrappers" pkgs.ipfs ]; + environment.IPFS_PATH = cfg.dataDir; + + wants = [ "ipfs-init.service" ]; + after = [ "ipfs-init.service" ]; - systemd.services.ipfs = recursiveUpdate baseService { - description = "IPFS Daemon"; - wantedBy = mkIf (cfg.defaultMode == "online") [ "multi-user.target" ]; - after = [ "network.target" "ipfs-init.service" ]; - conflicts = [ "ipfs-offline.service" "ipfs-norouting.service"]; + preStart = optionalString cfg.autoMount '' + ipfs --local config Mounts.FuseAllowOther --json true + ipfs --local config Mounts.IPFS ${cfg.ipfsMountDir} + ipfs --local config Mounts.IPNS ${cfg.ipnsMountDir} + '' + concatStringsSep "\n" (collect + isString + (mapAttrsRecursive + (path: value: + # Using heredoc below so that the value is never improperly quoted + '' + read value <<EOF + ${builtins.toJSON value} + EOF + ipfs --local config --json "${concatStringsSep "." path}" "$value" + '') + ({ Addresses.API = cfg.apiAddress; + Addresses.Gateway = cfg.gatewayAddress; + Addresses.Swarm = cfg.swarmAddress; + } // + cfg.extraConfig)) + ); + serviceConfig = { + ExecStart = ["" "${pkgs.ipfs}/bin/ipfs daemon ${ipfsFlags}"]; + User = cfg.user; + Group = cfg.group; + } // optionalAttrs (cfg.serviceFdlimit != null) { LimitNOFILE = cfg.serviceFdlimit; }; + } // optionalAttrs (!cfg.startWhenNeeded) { + wantedBy = [ "default.target" ]; }; - systemd.services.ipfs-offline = recursiveUpdate baseService { - description = "IPFS Daemon (offline mode)"; - wantedBy = mkIf (cfg.defaultMode == "offline") [ "multi-user.target" ]; - after = [ "ipfs-init.service" ]; - conflicts = [ "ipfs.service" "ipfs-norouting.service"]; + systemd.sockets.ipfs-gateway = { + wantedBy = [ "sockets.target" ]; + socketConfig.ListenStream = [ "" ] + ++ lib.optional (cfg.gatewayAddress == opt.gatewayAddress.default) [ "127.0.0.1:8080" "[::1]:8080" ]; }; - systemd.services.ipfs-norouting = recursiveUpdate baseService { - description = "IPFS Daemon (no routing mode)"; - wantedBy = mkIf (cfg.defaultMode == "norouting") [ "multi-user.target" ]; - after = [ "ipfs-init.service" ]; - conflicts = [ "ipfs.service" "ipfs-offline.service"]; + systemd.sockets.ipfs-api = { + wantedBy = [ "sockets.target" ]; + socketConfig.ListenStream = [ "" "%t/ipfs.sock" ] + ++ lib.optional (cfg.apiAddress == opt.apiAddress.default) [ "127.0.0.1:5001" "[::1]:5001" ]; }; }; diff --git a/nixos/modules/services/networking/corerad.nix b/nixos/modules/services/networking/corerad.nix index 1a2c4aec6651..5d73c0a0d779 100644 --- a/nixos/modules/services/networking/corerad.nix +++ b/nixos/modules/services/networking/corerad.nix @@ -4,14 +4,50 @@ with lib; let cfg = config.services.corerad; + + writeTOML = name: x: + pkgs.runCommandNoCCLocal name { + passAsFile = ["config"]; + config = builtins.toJSON x; + buildInputs = [ pkgs.go-toml ]; + } "jsontoml < $configPath > $out"; + in { - meta = { - maintainers = with maintainers; [ mdlayher ]; - }; + meta.maintainers = with maintainers; [ mdlayher ]; options.services.corerad = { enable = mkEnableOption "CoreRAD IPv6 NDP RA daemon"; + settings = mkOption { + type = types.uniq types.attrs; + example = literalExample '' + { + interfaces = [ + # eth0 is an upstream interface monitoring for IPv6 router advertisements. + { + name = "eth0"; + monitor = true; + } + # eth1 is a downstream interface advertising IPv6 prefixes for SLAAC. + { + name = "eth1"; + advertise = true; + prefix = [{ prefix = "::/64"; }]; + } + ]; + # Optionally enable Prometheus metrics. + debug = { + address = "localhost:9430"; + prometheus = true; + }; + } + ''; + description = '' + Configuration for CoreRAD, see <link xlink:href="https://github.com/mdlayher/corerad/blob/master/internal/config/default.toml"/> + for supported values. Ignored if configFile is set. + ''; + }; + configFile = mkOption { type = types.path; example = literalExample "\"\${pkgs.corerad}/etc/corerad/corerad.toml\""; @@ -27,6 +63,9 @@ in { }; config = mkIf cfg.enable { + # Prefer the config file over settings if both are set. + services.corerad.configFile = mkDefault (writeTOML "corerad.toml" cfg.settings); + systemd.services.corerad = { description = "CoreRAD IPv6 NDP RA daemon"; after = [ "network.target" ]; diff --git a/nixos/modules/services/networking/dnschain.nix b/nixos/modules/services/networking/dnschain.nix deleted file mode 100644 index 003609ea7054..000000000000 --- a/nixos/modules/services/networking/dnschain.nix +++ /dev/null @@ -1,184 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfgs = config.services; - cfg = cfgs.dnschain; - - dataDir = "/var/lib/dnschain"; - username = "dnschain"; - - configFile = pkgs.writeText "dnschain.conf" '' - [log] - level = info - - [dns] - host = ${cfg.dns.address} - port = ${toString cfg.dns.port} - oldDNSMethod = NO_OLD_DNS - externalIP = ${cfg.dns.externalAddress} - - [http] - host = ${cfg.api.hostname} - port = ${toString cfg.api.port} - tlsPort = ${toString cfg.api.tlsPort} - - ${cfg.extraConfig} - ''; - -in - -{ - - ###### interface - - options = { - - services.dnschain = { - - enable = mkEnableOption '' - DNSChain, a blockchain based DNS + HTTP server. - To resolve .bit domains set <literal>services.namecoind.enable = true;</literal> - and an RPC username/password. - ''; - - dns.address = mkOption { - type = types.str; - default = "127.0.0.1"; - description = '' - The IP address the DNSChain resolver will bind to. - Leave this unchanged if you do not wish to directly expose the resolver. - ''; - }; - - dns.externalAddress = mkOption { - type = types.str; - default = cfg.dns.address; - description = '' - The IP address used by clients to reach the resolver and the value of - the <literal>namecoin.dns</literal> record. Set this in case the bind address - is not the actual IP address (e.g. the machine is behind a NAT). - ''; - }; - - dns.port = mkOption { - type = types.int; - default = 5333; - description = '' - The port the DNSChain resolver will bind to. - ''; - }; - - api.hostname = mkOption { - type = types.str; - default = "0.0.0.0"; - description = '' - The hostname (or IP address) the DNSChain API server will bind to. - ''; - }; - - api.port = mkOption { - type = types.int; - default = 8080; - description = '' - The port the DNSChain API server (HTTP) will bind to. - ''; - }; - - api.tlsPort = mkOption { - type = types.int; - default = 4433; - description = '' - The port the DNSChain API server (HTTPS) will bind to. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - example = '' - [log] - level = debug - ''; - description = '' - Additional options that will be appended to the configuration file. - ''; - }; - - }; - - services.dnsmasq.resolveDNSChainQueries = mkOption { - type = types.bool; - default = false; - description = '' - Resolve <literal>.bit</literal> top-level domains using DNSChain and namecoin. - ''; - }; - - services.pdns-recursor.resolveDNSChainQueries = mkOption { - type = types.bool; - default = false; - description = '' - Resolve <literal>.bit</literal> top-level domains using DNSChain and namecoin. - ''; - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - - services.dnsmasq.servers = optionals cfgs.dnsmasq.resolveDNSChainQueries - [ "/.bit/127.0.0.1#${toString cfg.dns.port}" - "/.dns/127.0.0.1#${toString cfg.dns.port}" - ]; - - services.pdns-recursor = mkIf cfgs.pdns-recursor.resolveDNSChainQueries { - forwardZonesRecurse = - { bit = "127.0.0.1:${toString cfg.dns.port}"; - dns = "127.0.0.1:${toString cfg.dns.port}"; - }; - luaConfig ='' - addNTA("bit", "namecoin doesn't support DNSSEC") - addNTA("dns", "namecoin doesn't support DNSSEC") - ''; - }; - - users.users.${username} = { - description = "DNSChain daemon user"; - home = dataDir; - createHome = true; - uid = config.ids.uids.dnschain; - extraGroups = optional cfgs.namecoind.enable "namecoin"; - }; - - systemd.services.dnschain = { - description = "DNSChain daemon"; - after = optional cfgs.namecoind.enable "namecoind.target"; - wantedBy = [ "multi-user.target" ]; - - serviceConfig = { - User = "dnschain"; - Restart = "on-failure"; - ExecStart = "${pkgs.nodePackages.dnschain}/bin/dnschain"; - }; - - preStart = '' - # Link configuration file into dnschain home directory - configPath=${dataDir}/.dnschain/dnschain.conf - mkdir -p ${dataDir}/.dnschain - if [ "$(realpath $configPath)" != "${configFile}" ]; then - rm -f $configPath - ln -s ${configFile} $configPath - fi - ''; - }; - - }; - - meta.maintainers = with lib.maintainers; [ rnhmjoj ]; - -} diff --git a/nixos/modules/services/networking/go-neb.nix b/nixos/modules/services/networking/go-neb.nix new file mode 100644 index 000000000000..991ae38f30a5 --- /dev/null +++ b/nixos/modules/services/networking/go-neb.nix @@ -0,0 +1,53 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.go-neb; + + configFile = pkgs.writeText "config.yml" (builtins.toJSON cfg.config); +in { + options.services.go-neb = { + enable = mkEnableOption "Extensible matrix bot written in Go"; + + bindAddress = mkOption { + type = types.str; + description = "Port (and optionally address) to listen on."; + default = ":4050"; + }; + + baseUrl = mkOption { + type = types.str; + description = "Public-facing endpoint that can receive webhooks."; + }; + + config = mkOption { + type = types.uniq types.attrs; + description = '' + Your <filename>config.yaml</filename> as a Nix attribute set. + See <link xlink:href="https://github.com/matrix-org/go-neb/blob/master/config.sample.yaml">config.sample.yaml</link> + for possible options. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.go-neb = { + description = "Extensible matrix bot written in Go"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = { + BASE_URL = cfg.baseUrl; + BIND_ADDRESS = cfg.bindAddress; + CONFIG_FILE = configFile; + }; + + serviceConfig = { + ExecStart = "${pkgs.go-neb}/bin/go-neb"; + DynamicUser = true; + }; + }; + }; + + meta.maintainers = with maintainers; [ hexa maralorn ]; +} diff --git a/nixos/modules/services/networking/haproxy.nix b/nixos/modules/services/networking/haproxy.nix index 4678829986c6..e9d72b35499d 100644 --- a/nixos/modules/services/networking/haproxy.nix +++ b/nixos/modules/services/networking/haproxy.nix @@ -56,6 +56,9 @@ with lib; message = "You must provide services.haproxy.config."; }]; + # configuration file indirection is needed to support reloading + environment.etc."haproxy.cfg".source = haproxyCfg; + systemd.services.haproxy = { description = "HAProxy"; after = [ "network.target" ]; @@ -64,11 +67,32 @@ with lib; User = cfg.user; Group = cfg.group; Type = "notify"; - # when running the config test, don't be quiet so we can see what goes wrong - ExecStartPre = "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}"; - ExecStart = "${pkgs.haproxy}/sbin/haproxy -Ws -f ${haproxyCfg}"; - Restart = "on-failure"; + ExecStartPre = [ + # when the master process receives USR2, it reloads itself using exec(argv[0]), + # so we create a symlink there and update it before reloading + "${pkgs.coreutils}/bin/ln -sf ${pkgs.haproxy}/sbin/haproxy /run/haproxy/haproxy" + # when running the config test, don't be quiet so we can see what goes wrong + "/run/haproxy/haproxy -c -f ${haproxyCfg}" + ]; + ExecStart = "/run/haproxy/haproxy -Ws -f /etc/haproxy.cfg -p /run/haproxy/haproxy.pid"; + # support reloading + ExecReload = [ + "${pkgs.haproxy}/sbin/haproxy -c -f ${haproxyCfg}" + "${pkgs.coreutils}/bin/ln -sf ${pkgs.haproxy}/sbin/haproxy /run/haproxy/haproxy" + "${pkgs.coreutils}/bin/kill -USR2 $MAINPID" + ]; + KillMode = "mixed"; + SuccessExitStatus = "143"; + Restart = "always"; RuntimeDirectory = "haproxy"; + # upstream hardening options + NoNewPrivileges = true; + ProtectHome = true; + ProtectSystem = "strict"; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + SystemCallFilter= "~@cpu-emulation @keyring @module @obsolete @raw-io @reboot @swap @sync"; # needed in case we bind to port < 1024 AmbientCapabilities = "CAP_NET_BIND_SERVICE"; }; diff --git a/nixos/modules/services/networking/namecoind.nix b/nixos/modules/services/networking/namecoind.nix index ead7f0859434..6ca99e1321bd 100644 --- a/nixos/modules/services/networking/namecoind.nix +++ b/nixos/modules/services/networking/namecoind.nix @@ -149,11 +149,6 @@ in config = mkIf cfg.enable { - services.dnschain.extraConfig = '' - [namecoin] - config = ${configFile} - ''; - users.users.namecoin = { uid = config.ids.uids.namecoin; description = "Namecoin daemon user"; diff --git a/nixos/modules/services/networking/v2ray.nix b/nixos/modules/services/networking/v2ray.nix index a1774cdffbb9..6a924a16449a 100644 --- a/nixos/modules/services/networking/v2ray.nix +++ b/nixos/modules/services/networking/v2ray.nix @@ -58,7 +58,13 @@ with lib; cfg = config.services.v2ray; configFile = if cfg.configFile != null then cfg.configFile - else (pkgs.writeText "v2ray.json" (builtins.toJSON cfg.config)); + else pkgs.writeTextFile { + name = "v2ray.json"; + text = builtins.toJSON cfg.config; + checkPhase = '' + ${pkgs.v2ray}/bin/v2ray -test -config $out + ''; + }; in mkIf cfg.enable { assertions = [ diff --git a/nixos/modules/services/networking/vsftpd.nix b/nixos/modules/services/networking/vsftpd.nix index b3e201844236..c57994533c17 100644 --- a/nixos/modules/services/networking/vsftpd.nix +++ b/nixos/modules/services/networking/vsftpd.nix @@ -116,7 +116,8 @@ let userlist_file=${cfg.userlistFile} ''} background=YES - listen=YES + listen=NO + listen_ipv6=YES nopriv_user=vsftpd secure_chroot_dir=/var/empty ${optionalString (cfg.localRoot != null) '' diff --git a/nixos/modules/services/security/physlock.nix b/nixos/modules/services/security/physlock.nix index 61bcd84f2e64..690eb70079d8 100644 --- a/nixos/modules/services/security/physlock.nix +++ b/nixos/modules/services/security/physlock.nix @@ -107,6 +107,7 @@ in ++ cfg.lockOn.extraTargets; before = optional cfg.lockOn.suspend "systemd-suspend.service" ++ optional cfg.lockOn.hibernate "systemd-hibernate.service" + ++ optional (cfg.lockOn.hibernate || cfg.lockOn.suspend) "systemd-suspend-then-hibernate.service" ++ cfg.lockOn.extraTargets; serviceConfig = { Type = "forking"; diff --git a/nixos/modules/services/system/cgmanager.nix b/nixos/modules/services/system/cgmanager.nix deleted file mode 100644 index d3d57aa76928..000000000000 --- a/nixos/modules/services/system/cgmanager.nix +++ /dev/null @@ -1,26 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.cgmanager; -in { - meta.maintainers = [ maintainers.mic92 ]; - - ###### interface - options.services.cgmanager.enable = mkEnableOption "cgmanager"; - - ###### implementation - config = mkIf cfg.enable { - systemd.services.cgmanager = { - wantedBy = [ "multi-user.target" ]; - description = "Cgroup management daemon"; - restartIfChanged = false; - serviceConfig = { - ExecStart = "${pkgs.cgmanager}/bin/cgmanager -m name=systemd"; - KillMode = "process"; - Restart = "on-failure"; - }; - }; - }; -} diff --git a/nixos/modules/services/system/nscd.conf b/nixos/modules/services/system/nscd.conf index 2b7523a7346d..722b883ba420 100644 --- a/nixos/modules/services/system/nscd.conf +++ b/nixos/modules/services/system/nscd.conf @@ -24,7 +24,7 @@ negative-time-to-live netgroup 0 shared netgroup yes enable-cache hosts yes -positive-time-to-live hosts 600 +positive-time-to-live hosts 0 negative-time-to-live hosts 0 shared hosts yes diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix index e7f5aaed844e..1bfcf2de82f8 100644 --- a/nixos/modules/services/torrent/transmission.nix +++ b/nixos/modules/services/torrent/transmission.nix @@ -179,6 +179,8 @@ in ${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.gcc.cc.lib}/lib/libstdc++.so.* mr, + ${getLib pkgs.gcc.cc.lib}/lib/libgcc_s.so.* mr, @{PROC}/sys/kernel/random/uuid r, @{PROC}/sys/vm/overcommit_memory r, diff --git a/nixos/modules/services/web-apps/nextcloud.nix b/nixos/modules/services/web-apps/nextcloud.nix index f826096bf608..5b9065dec3c5 100644 --- a/nixos/modules/services/web-apps/nextcloud.nix +++ b/nixos/modules/services/web-apps/nextcloud.nix @@ -34,7 +34,7 @@ let cd ${cfg.package} sudo=exec if [[ "$USER" != nextcloud ]]; then - sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR' + sudo='exec /run/wrappers/bin/sudo -u nextcloud --preserve-env=NEXTCLOUD_CONFIG_DIR --preserve-env=OC_PASS' fi export NEXTCLOUD_CONFIG_DIR="${cfg.home}/config" $sudo \ diff --git a/nixos/modules/services/x11/desktop-managers/gnome3.nix b/nixos/modules/services/x11/desktop-managers/gnome3.nix index bbc7feb2d049..69cf98321720 100644 --- a/nixos/modules/services/x11/desktop-managers/gnome3.nix +++ b/nixos/modules/services/x11/desktop-managers/gnome3.nix @@ -37,10 +37,10 @@ let chmod -R a+w $out/share/gsettings-schemas/nixos-gsettings-overrides cat - > $out/share/gsettings-schemas/nixos-gsettings-overrides/glib-2.0/schemas/nixos-defaults.gschema.override <<- EOF [org.gnome.desktop.background] - picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray}/share/artwork/gnome/nix-wallpaper-simple-dark-gray.png' + picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray.gnomeFilePath}' [org.gnome.desktop.screensaver] - picture-uri='file://${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom}/share/artwork/gnome/nix-wallpaper-simple-dark-gray_bottom.png' + 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' ] @@ -320,6 +320,8 @@ in gnome-shell gnome-shell-extensions gnome-themes-extra + pkgs.nixos-artwork.wallpapers.simple-dark-gray + pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom pkgs.gnome-user-docs pkgs.orca pkgs.glib # for gsettings diff --git a/nixos/modules/services/x11/desktop-managers/pantheon.nix b/nixos/modules/services/x11/desktop-managers/pantheon.nix index 5fcc8590232a..6dabca6bf096 100644 --- a/nixos/modules/services/x11/desktop-managers/pantheon.nix +++ b/nixos/modules/services/x11/desktop-managers/pantheon.nix @@ -180,6 +180,7 @@ in gtk3.out hicolor-icon-theme lightlocker + nixos-artwork.wallpapers.simple-dark-gray onboard qgnomeplatform shared-mime-info diff --git a/nixos/modules/services/x11/display-managers/lightdm.nix b/nixos/modules/services/x11/display-managers/lightdm.nix index 479548863b47..678cade44427 100644 --- a/nixos/modules/services/x11/display-managers/lightdm.nix +++ b/nixos/modules/services/x11/display-managers/lightdm.nix @@ -132,8 +132,9 @@ in }; background = mkOption { - type = types.str; - default = "${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom}/share/artwork/gnome/nix-wallpaper-simple-dark-gray_bottom.png"; + type = types.path; + # Manual cannot depend on packages, we are actually setting the default in config below. + defaultText = "pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath"; description = '' The background image or color to use. ''; @@ -212,6 +213,9 @@ in } ]; + # Keep in sync with the defaultText value from the option definition. + services.xserver.displayManager.lightdm.background = mkDefault pkgs.nixos-artwork.wallpapers.simple-dark-gray-bottom.gnomeFilePath; + # Set default session in session chooser to a specified values – basically ignore session history. # Auto-login is already covered by a config value. services.xserver.displayManager.job.preStart = optionalString (!cfg.autoLogin.enable && dmcfg.defaultSession != null) '' diff --git a/nixos/modules/services/x11/xserver.nix b/nixos/modules/services/x11/xserver.nix index 6aec1c0753a2..400173745d3f 100644 --- a/nixos/modules/services/x11/xserver.nix +++ b/nixos/modules/services/x11/xserver.nix @@ -246,7 +246,7 @@ in videoDrivers = mkOption { type = types.listOf types.str; # !!! We'd like "nv" here, but it segfaults the X server. - default = [ "radeon" "cirrus" "vesa" "vmware" "modesetting" ]; + default = [ "radeon" "cirrus" "vesa" "modesetting" ]; example = [ "ati_unfree" "amdgpu" "amdgpu-pro" "nv" "nvidia" "nvidiaLegacy390" "nvidiaLegacy340" "nvidiaLegacy304" diff --git a/nixos/modules/system/boot/kernel_config.nix b/nixos/modules/system/boot/kernel_config.nix index a316782dfc57..85bd420e3044 100644 --- a/nixos/modules/system/boot/kernel_config.nix +++ b/nixos/modules/system/boot/kernel_config.nix @@ -22,7 +22,7 @@ let mergeFalseByDefault = locs: defs: if defs == [] then abort "This case should never happen." - else if any (x: x == false) defs then false + else if any (x: x == false) (getValues defs) then false else true; kernelItem = types.submodule { @@ -55,6 +55,7 @@ let default = false; description = '' Wether option should generate a failure when unused. + Upon merging values, mandatory wins over optional. ''; }; }; @@ -121,7 +122,7 @@ in type = types.attrsOf kernelItem; example = literalExample '' with lib.kernel; { "9P_NET" = yes; - USB = optional yes; + USB = option yes; MMC_BLOCK_MINORS = freeform "32"; }''; description = '' diff --git a/nixos/modules/system/boot/loader/grub/grub.nix b/nixos/modules/system/boot/loader/grub/grub.nix index c775632a4aa0..3975372e15ec 100644 --- a/nixos/modules/system/boot/loader/grub/grub.nix +++ b/nixos/modules/system/boot/loader/grub/grub.nix @@ -60,7 +60,7 @@ let inherit (efi) canTouchEfiVariables; inherit (cfg) version extraConfig extraPerEntryConfig extraEntries forceInstall useOSProber - extraEntriesBeforeNixOS extraPrepareConfig extraInitrd configurationLimit copyKernels + extraEntriesBeforeNixOS extraPrepareConfig configurationLimit copyKernels default fsIdentifier efiSupport efiInstallAsRemovable gfxmodeEfi gfxmodeBios gfxpayloadEfi gfxpayloadBios; path = with pkgs; makeBinPath ( [ coreutils gnused gnugrep findutils diffutils btrfs-progs utillinux mdadm ] @@ -83,7 +83,7 @@ let ] ++ (optional (cfg.fontSize!=null) "--size ${toString cfg.fontSize}"))) ); - defaultSplash = "${pkgs.nixos-artwork.wallpapers.simple-dark-gray-bootloader}/share/artwork/gnome/nix-wallpaper-simple-dark-gray_bootloader.png"; + defaultSplash = pkgs.nixos-artwork.wallpapers.simple-dark-gray-bootloader.gnomeFilePath; in { @@ -292,19 +292,6 @@ in ''; }; - extraInitrd = mkOption { - type = types.nullOr types.path; - default = null; - example = "/boot/extra_initramfs.gz"; - description = '' - The path to a second initramfs to be supplied to the kernel. - This ramfs will not be copied to the store, so that it can - contain secrets such as LUKS keyfiles or ssh keys. - This implies that rolling back to a previous configuration - won't rollback the state of this file. - ''; - }; - useOSProber = mkOption { default = false; type = types.bool; @@ -608,6 +595,8 @@ in { path = "/boot"; inherit (cfg) devices; inherit (efi) efiSysMountPoint; } ]; + boot.loader.supportsInitrdSecrets = true; + system.build.installBootLoader = let install-grub-pl = pkgs.substituteAll { @@ -705,6 +694,24 @@ in (mkRenamedOptionModule [ "boot" "grubDevice" ] [ "boot" "loader" "grub" "device" ]) (mkRenamedOptionModule [ "boot" "bootMount" ] [ "boot" "loader" "grub" "bootDevice" ]) (mkRenamedOptionModule [ "boot" "grubSplashImage" ] [ "boot" "loader" "grub" "splashImage" ]) + (mkRemovedOptionModule [ "boot" "loader" "grub" "extraInitrd" ] '' + This option has been replaced with the bootloader agnostic + boot.initrd.secrets option. To migrate to the initrd secrets system, + extract the extraInitrd archive into your main filesystem: + + # zcat /boot/extra_initramfs.gz | cpio -idvmD /etc/secrets/initrd + /path/to/secret1 + /path/to/secret2 + + then replace boot.loader.grub.extraInitrd with boot.initrd.secrets: + + boot.initrd.secrets = { + "/path/to/secret1" = "/etc/secrets/initrd/path/to/secret1"; + "/path/to/secret2" = "/etc/secrets/initrd/path/to/secret2"; + }; + + See the boot.initrd.secrets option documentation for more information. + '') ]; } diff --git a/nixos/modules/system/boot/loader/grub/install-grub.pl b/nixos/modules/system/boot/loader/grub/install-grub.pl index 8df18cbd9013..e469b18abd09 100644 --- a/nixos/modules/system/boot/loader/grub/install-grub.pl +++ b/nixos/modules/system/boot/loader/grub/install-grub.pl @@ -49,7 +49,6 @@ my $extraPrepareConfig = get("extraPrepareConfig"); my $extraPerEntryConfig = get("extraPerEntryConfig"); my $extraEntries = get("extraEntries"); my $extraEntriesBeforeNixOS = get("extraEntriesBeforeNixOS") eq "true"; -my $extraInitrd = get("extraInitrd"); my $splashImage = get("splashImage"); my $splashMode = get("splashMode"); my $backgroundColor = get("backgroundColor"); @@ -232,13 +231,6 @@ my $grubStore; if ($copyKernels == 0) { $grubStore = GrubFs($storePath); } -my $extraInitrdPath; -if ($extraInitrd) { - if (! -f $extraInitrd) { - print STDERR "Warning: the specified extraInitrd " . $extraInitrd . " doesn't exist. Your system won't boot without it.\n"; - } - $extraInitrdPath = GrubFs($extraInitrd); -} # Generate the header. my $conf .= "# Automatically generated. DO NOT EDIT THIS FILE!\n"; @@ -363,9 +355,30 @@ sub addEntry { my $kernel = copyToKernelsDir(Cwd::abs_path("$path/kernel")); my $initrd = copyToKernelsDir(Cwd::abs_path("$path/initrd")); - if ($extraInitrd) { - $initrd .= " " .$extraInitrdPath->path; + + # Include second initrd with secrets + if (-e -x "$path/append-initrd-secrets") { + my $initrdName = basename($initrd); + my $initrdSecretsPath = "$bootPath/kernels/$initrdName-secrets"; + + mkpath(dirname($initrdSecretsPath), 0, 0755); + my $oldUmask = umask; + # Make sure initrd is not world readable (won't work if /boot is FAT) + umask 0137; + my $initrdSecretsPathTemp = File::Temp::mktemp("$initrdSecretsPath.XXXXXXXX"); + system("$path/append-initrd-secrets", $initrdSecretsPathTemp) == 0 or die "failed to create initrd secrets\n"; + # Check whether any secrets were actually added + if (-e $initrdSecretsPathTemp && ! -z _) { + rename $initrdSecretsPathTemp, $initrdSecretsPath or die "failed to move initrd secrets into place\n"; + $copied{$initrdSecretsPath} = 1; + $initrd .= " " . ($grubBoot->path eq "/" ? "" : $grubBoot->path) . "/kernels/$initrdName-secrets"; + } else { + unlink $initrdSecretsPathTemp; + rmdir dirname($initrdSecretsPathTemp); + } + umask $oldUmask; } + my $xen = -e "$path/xen.gz" ? copyToKernelsDir(Cwd::abs_path("$path/xen.gz")) : undef; # FIXME: $confName @@ -388,9 +401,6 @@ sub addEntry { if ($copyKernels == 0) { $conf .= $grubStore->search . "\n"; } - if ($extraInitrd) { - $conf .= $extraInitrdPath->search . "\n"; - } $conf .= " $extraPerEntryConfig\n" if $extraPerEntryConfig; $conf .= " multiboot $xen $xenParams\n" if $xen; $conf .= " " . ($xen ? "module" : "linux") . " $kernel $kernelParams\n"; diff --git a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py index f48a085ce57a..d8baed65c6df 100644 --- a/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py +++ b/nixos/modules/system/boot/loader/systemd-boot/systemd-boot-builder.py @@ -47,9 +47,9 @@ def write_loader_conf(profile, generation): if "@timeout@" != "": f.write("timeout @timeout@\n") if profile: - f.write("default nixos-%s-generation-%d\n" % (profile, generation)) + f.write("default nixos-%s-generation-%d.conf\n".format(profile, generation)) else: - f.write("default nixos-generation-%d\n" % (generation)) + f.write("default nixos-generation-%d.conf\n".format(generation)) if not @editor@: f.write("editor 0\n"); f.write("console-mode @consoleMode@\n"); @@ -197,6 +197,22 @@ def main(): subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "install"]) else: subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "--no-variables", "install"]) + else: + # Update bootloader to latest if needed + systemd_version = subprocess.check_output(["@systemd@/bin/bootctl", "--version"], universal_newlines=True).split()[1] + sdboot_status = subprocess.check_output(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "status"], universal_newlines=True) + + # See status_binaries() in systemd bootctl.c for code which generates this + m = re.search("^\W+File:.*/EFI/(BOOT|systemd)/.*\.efi \(systemd-boot (\d+)\)$", + sdboot_status, re.IGNORECASE | re.MULTILINE) + if m is None: + print("could not find any previously installed systemd-boot") + else: + sdboot_version = m.group(2) + if systemd_version > sdboot_version: + print("updating systemd-boot from %s to %s" % (sdboot_version, systemd_version)) + subprocess.check_call(["@systemd@/bin/bootctl", "--path=@efiSysMountPoint@", "update"]) + mkdir_p("@efiSysMountPoint@/efi/nixos") mkdir_p("@efiSysMountPoint@/loader/entries") diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index 9b34b12e73a5..b0545363b330 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -1178,14 +1178,22 @@ in users.users.systemd-network.group = "systemd-network"; systemd.additionalUpstreamSystemUnits = [ - "systemd-networkd.service" "systemd-networkd-wait-online.service" + "systemd-networkd-wait-online.service" + "systemd-networkd.service" + "systemd-networkd.socket" ]; systemd.network.units = mapAttrs' (n: v: nameValuePair "${n}.netdev" (netdevToUnit n v)) cfg.netdevs // mapAttrs' (n: v: nameValuePair "${n}.network" (networkToUnit n v)) cfg.networks; + # systemd-networkd is socket-activated by kernel netlink route change + # messages. It is important to have systemd buffer those on behalf of + # networkd. + systemd.sockets.systemd-networkd.wantedBy = [ "sockets.target" ]; + systemd.services.systemd-networkd = { wantedBy = [ "multi-user.target" ]; + aliases = [ "dbus-org.freedesktop.network1.service" ]; restartTriggers = map (x: x.source) (attrValues unitFiles); # prevent race condition with interface renaming (#39069) requires = [ "systemd-udev-settle.service" ]; diff --git a/nixos/modules/system/boot/resolved.nix b/nixos/modules/system/boot/resolved.nix index b7aaef575ac1..b024f9cf5ee9 100644 --- a/nixos/modules/system/boot/resolved.nix +++ b/nixos/modules/system/boot/resolved.nix @@ -148,6 +148,7 @@ in systemd.services.systemd-resolved = { wantedBy = [ "multi-user.target" ]; + aliases = [ "dbus-org.freedesktop.resolve1.service" ]; restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ]; }; diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index dfd158e2d75f..d551466f52eb 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -517,8 +517,7 @@ in }; boot.initrd.secrets = mkOption - { internal = true; - default = {}; + { default = {}; type = types.attrsOf (types.nullOr types.path); description = '' @@ -585,7 +584,7 @@ in { assertion = !config.boot.loader.supportsInitrdSecrets -> all (source: builtins.isPath source || - (builtins.isString source && hasPrefix source builtins.storeDir)) + (builtins.isString source && hasPrefix builtins.storeDir source)) (attrValues config.boot.initrd.secrets); message = '' boot.loader.initrd.secrets values must be unquoted paths when diff --git a/nixos/modules/system/boot/systemd.nix b/nixos/modules/system/boot/systemd.nix index 99892a28115c..a8e51fc09014 100644 --- a/nixos/modules/system/boot/systemd.nix +++ b/nixos/modules/system/boot/systemd.nix @@ -826,8 +826,13 @@ in config = { warnings = concatLists (mapAttrsToList (name: service: - optional (service.serviceConfig.Type or "" == "oneshot" && service.serviceConfig.Restart or "no" != "no") - "Service ‘${name}.service’ with ‘Type=oneshot’ must have ‘Restart=no’") cfg.services); + let + type = service.serviceConfig.Type or ""; + restart = service.serviceConfig.Restart or "no"; + in optional + (type == "oneshot" && (restart == "always" || restart == "on-success")) + "Service '${name}.service' with 'Type=oneshot' cannot have 'Restart=always' or 'Restart=on-success'") + cfg.services); system.build.units = cfg.units; diff --git a/nixos/modules/system/boot/timesyncd.nix b/nixos/modules/system/boot/timesyncd.nix index 9e2f36ca01f8..35fb5578b070 100644 --- a/nixos/modules/system/boot/timesyncd.nix +++ b/nixos/modules/system/boot/timesyncd.nix @@ -41,6 +41,7 @@ with lib; systemd.services.systemd-timesyncd = { wantedBy = [ "sysinit.target" ]; + aliases = [ "dbus-org.freedesktop.timesync1.service" ]; restartTriggers = [ config.environment.etc."systemd/timesyncd.conf".source ]; }; diff --git a/nixos/modules/tasks/network-interfaces-scripted.nix b/nixos/modules/tasks/network-interfaces-scripted.nix index d895c58bab03..2e87197176b6 100644 --- a/nixos/modules/tasks/network-interfaces-scripted.nix +++ b/nixos/modules/tasks/network-interfaces-scripted.nix @@ -232,18 +232,22 @@ let ''; preStop = '' state="/run/nixos/network/routes/${i.name}" - while read cidr; do - echo -n "deleting route $cidr... " - ip route del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" - done < "$state" - rm -f "$state" + if [ -e "$state" ]; then + while read cidr; do + echo -n "deleting route $cidr... " + ip route del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" + done < "$state" + rm -f "$state" + fi state="/run/nixos/network/addresses/${i.name}" - while read cidr; do - echo -n "deleting address $cidr... " - ip addr del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" - done < "$state" - rm -f "$state" + if [ -e "$state" ]; then + while read cidr; do + echo -n "deleting address $cidr... " + ip addr del "$cidr" dev "${i.name}" >/dev/null 2>&1 && echo "done" || echo "failed" + done < "$state" + rm -f "$state" + fi ''; }; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index 12cff6b038f8..78d669669499 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -283,7 +283,7 @@ let default = false; type = types.bool; description = '' - Turn on proxy_arp for this device (and proxy_ndp for ipv6). + Turn on proxy_arp for this device. This is mainly useful for creating pseudo-bridges between a real interface and a virtual network such as VPN or a virtual machine for interfaces that don't support real bridging (most wlan interfaces). @@ -381,7 +381,7 @@ in # syntax). Note: We also allow underscores for compatibility/legacy # reasons (as undocumented feature): type = types.strMatching - "^[[:alpha:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$"; + "^$|^[[:alpha:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$"; description = '' The name of the machine. Leave it empty if you want to obtain it from a DHCP server (if using DHCP). The hostname must be a valid DNS label (see @@ -1065,11 +1065,11 @@ in optionalString hasBonds "options bonding max_bonds=0"; boot.kernel.sysctl = { + "net.ipv4.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); "net.ipv6.conf.all.disable_ipv6" = mkDefault (!cfg.enableIPv6); "net.ipv6.conf.default.disable_ipv6" = mkDefault (!cfg.enableIPv6); - "net.ipv6.conf.all.forwarding" = mkDefault (any (i: i.proxyARP) interfaces); } // listToAttrs (flip concatMap (filter (i: i.proxyARP) interfaces) - (i: forEach [ "4" "6" ] (v: nameValuePair "net.ipv${v}.conf.${replaceChars ["."] ["/"] i.name}.proxy_arp" true))) + (i: [(nameValuePair "net.ipv4.conf.${replaceChars ["."] ["/"] i.name}.proxy_arp" true)])) // listToAttrs (forEach interfaces (i: let opt = i.tempAddress; diff --git a/nixos/modules/virtualisation/kvmgt.nix b/nixos/modules/virtualisation/kvmgt.nix index 0902d2dc2cb0..e08ad3446281 100644 --- a/nixos/modules/virtualisation/kvmgt.nix +++ b/nixos/modules/virtualisation/kvmgt.nix @@ -9,8 +9,8 @@ let vgpuOptions = { uuid = mkOption { - type = types.str; - description = "UUID of VGPU device. You can generate one with <package>libossp_uuid</package>."; + type = with types; listOf str; + description = "UUID(s) of VGPU device. You can generate one with <package>libossp_uuid</package>."; }; }; @@ -36,7 +36,7 @@ in { and find info about device via <command>cat /sys/bus/pci/devices/*/mdev_supported_types/i915-GVTg_V5_4/description</command> ''; example = { - i915-GVTg_V5_8.uuid = "a297db4a-f4c2-11e6-90f6-d3b88d6c9525"; + i915-GVTg_V5_8.uuid = [ "a297db4a-f4c2-11e6-90f6-d3b88d6c9525" ]; }; }; }; @@ -51,31 +51,35 @@ in { boot.kernelModules = [ "kvmgt" ]; boot.kernelParams = [ "i915.enable_gvt=1" ]; - systemd.paths = mapAttrs' (name: value: - nameValuePair "kvmgt-${name}" { - description = "KVMGT VGPU ${name} path"; - wantedBy = [ "multi-user.target" ]; - pathConfig = { - PathExists = "/sys/bus/pci/devices/${cfg.device}/mdev_supported_types/${name}/create"; - }; - } - ) cfg.vgpus; - services.udev.extraRules = '' SUBSYSTEM=="vfio", OWNER="root", GROUP="kvm" ''; - systemd.services = mapAttrs' (name: value: - nameValuePair "kvmgt-${name}" { - description = "KVMGT VGPU ${name}"; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStart = "${pkgs.runtimeShell} -c 'echo ${value.uuid} > /sys/bus/pci/devices/${cfg.device}/mdev_supported_types/${name}/create'"; - ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/bus/pci/devices/${cfg.device}/${value.uuid}/remove'"; - }; - } - ) cfg.vgpus; + systemd = let + vgpus = listToAttrs (flatten (mapAttrsToList + (mdev: opt: map (id: nameValuePair "kvmgt-${id}" { inherit mdev; uuid = id; }) opt.uuid) + cfg.vgpus)); + in { + paths = mapAttrs (_: opt: + { + description = "KVMGT VGPU ${opt.uuid} path"; + wantedBy = [ "multi-user.target" ]; + pathConfig = { + PathExists = "/sys/bus/pci/devices/${cfg.device}/mdev_supported_types/${opt.mdev}/create"; + }; + }) vgpus; + + services = mapAttrs (_: opt: + { + description = "KVMGT VGPU ${opt.uuid}"; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + ExecStart = "${pkgs.runtimeShell} -c 'echo ${opt.uuid} > /sys/bus/pci/devices/${cfg.device}/mdev_supported_types/${opt.mdev}/create'"; + ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/bus/pci/devices/${cfg.device}/${opt.uuid}/remove'"; + }; + }) vgpus; + }; }; meta.maintainers = with maintainers; [ gnidorah ]; diff --git a/nixos/modules/virtualisation/libvirtd.nix b/nixos/modules/virtualisation/libvirtd.nix index f89e5d544b22..43b5fcfa8fae 100644 --- a/nixos/modules/virtualisation/libvirtd.nix +++ b/nixos/modules/virtualisation/libvirtd.nix @@ -114,7 +114,7 @@ in { Specifies the action to be done to / on the guests when the host boots. The "start" option starts all guests that were running prior to shutdown regardless of their autostart settings. The "ignore" option will not - start the formally running guest on boot. However, any guest marked as + start the formerly running guest on boot. However, any guest marked as autostart will still be automatically started by libvirtd. ''; }; diff --git a/nixos/modules/virtualisation/lxd.nix b/nixos/modules/virtualisation/lxd.nix index 53b89a9f55b1..3958fc2c1d7c 100644 --- a/nixos/modules/virtualisation/lxd.nix +++ b/nixos/modules/virtualisation/lxd.nix @@ -15,7 +15,6 @@ in ###### interface options = { - virtualisation.lxd = { enable = mkOption { type = types.bool; @@ -25,12 +24,18 @@ in containers. Users in the "lxd" group can interact with the daemon (e.g. to start or stop containers) using the <command>lxc</command> command line tool, among others. + + Most of the time, you'll also want to start lxcfs, so + that containers can "see" the limits: + <code> + virtualisation.lxc.lxcfs.enable = true; + </code> ''; }; package = mkOption { type = types.package; - default = pkgs.lxd; + default = pkgs.lxd.override { nftablesSupport = config.networking.nftables.enable; }; defaultText = "pkgs.lxd"; description = '' The LXD package to use. @@ -65,6 +70,7 @@ in with nixos. ''; }; + recommendedSysctlSettings = mkOption { type = types.bool; default = false; @@ -83,7 +89,6 @@ in ###### implementation config = mkIf cfg.enable { - environment.systemPackages = [ cfg.package ]; security.apparmor = { @@ -115,6 +120,12 @@ in LimitNOFILE = "1048576"; LimitNPROC = "infinity"; TasksMax = "infinity"; + + # By default, `lxd` loads configuration files from hard-coded + # `/usr/share/lxc/config` - since this is a no-go for us, we have to + # explicitly tell it where the actual configuration files are + Environment = mkIf (config.virtualisation.lxc.lxcfs.enable) + "LXD_LXC_TEMPLATE_CONFIG=${pkgs.lxcfs}/share/lxc/config"; }; }; diff --git a/nixos/modules/virtualisation/qemu-vm.nix b/nixos/modules/virtualisation/qemu-vm.nix index ac86330c098b..be06d6feb11f 100644 --- a/nixos/modules/virtualisation/qemu-vm.nix +++ b/nixos/modules/virtualisation/qemu-vm.nix @@ -441,6 +441,18 @@ in ''; }; + virtualisation.bios = + mkOption { + default = null; + type = types.nullOr types.package; + description = + '' + An alternate BIOS (such as <package>qboot</package>) with which to start the VM. + Should contain a file named <literal>bios.bin</literal>. + If <literal>null</literal>, QEMU's builtin SeaBIOS will be used. + ''; + }; + }; config = { @@ -521,6 +533,9 @@ in (mkIf cfg.useEFIBoot [ "-pflash $TMPDIR/bios.bin" ]) + (mkIf (cfg.bios != null) [ + "-bios ${cfg.bios}/bios.bin" + ]) (mkIf (!cfg.graphics) [ "-nographic" ]) @@ -576,7 +591,7 @@ in "/tmp/xchg" = { device = "xchg"; fsType = "9p"; - options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ]; + options = [ "trans=virtio" "version=9p2000.L" ]; neededForBoot = true; }; "/tmp/shared" = |