diff options
Diffstat (limited to 'nixos/modules/services/system')
-rw-r--r-- | nixos/modules/services/system/cachix-agent/default.nix | 57 | ||||
-rw-r--r-- | nixos/modules/services/system/cloud-init.nix | 194 | ||||
-rw-r--r-- | nixos/modules/services/system/dbus.nix | 139 | ||||
-rw-r--r-- | nixos/modules/services/system/earlyoom.nix | 104 | ||||
-rw-r--r-- | nixos/modules/services/system/kerberos/default.nix | 75 | ||||
-rw-r--r-- | nixos/modules/services/system/kerberos/heimdal.nix | 68 | ||||
-rw-r--r-- | nixos/modules/services/system/kerberos/mit.nix | 68 | ||||
-rw-r--r-- | nixos/modules/services/system/localtime.nix | 49 | ||||
-rw-r--r-- | nixos/modules/services/system/nscd.conf | 34 | ||||
-rw-r--r-- | nixos/modules/services/system/nscd.nix | 87 | ||||
-rw-r--r-- | nixos/modules/services/system/saslauthd.nix | 62 | ||||
-rw-r--r-- | nixos/modules/services/system/self-deploy.nix | 173 | ||||
-rw-r--r-- | nixos/modules/services/system/systembus-notify.nix | 27 | ||||
-rw-r--r-- | nixos/modules/services/system/uptimed.nix | 60 |
14 files changed, 1197 insertions, 0 deletions
diff --git a/nixos/modules/services/system/cachix-agent/default.nix b/nixos/modules/services/system/cachix-agent/default.nix new file mode 100644 index 00000000000..496e0b90355 --- /dev/null +++ b/nixos/modules/services/system/cachix-agent/default.nix @@ -0,0 +1,57 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.cachix-agent; +in { + meta.maintainers = [ lib.maintainers.domenkozar ]; + + options.services.cachix-agent = { + enable = mkEnableOption "Cachix Deploy Agent: https://docs.cachix.org/deploy/"; + + name = mkOption { + type = types.str; + description = "Agent name, usually same as the hostname"; + default = config.networking.hostName; + defaultText = "config.networking.hostName"; + }; + + profile = mkOption { + type = types.nullOr types.str; + default = null; + description = "Profile name, defaults to 'system' (NixOS)."; + }; + + package = mkOption { + type = types.package; + default = pkgs.cachix; + defaultText = literalExpression "pkgs.cachix"; + description = "Cachix Client package to use."; + }; + + credentialsFile = mkOption { + type = types.path; + default = "/etc/cachix-agent.token"; + description = '' + Required file that needs to contain CACHIX_AGENT_TOKEN=... + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.cachix-agent = { + description = "Cachix Deploy Agent"; + after = ["network-online.target"]; + path = [ config.nix.package ]; + wantedBy = [ "multi-user.target" ]; + # don't restart while changing + reloadIfChanged = true; + serviceConfig = { + Restart = "on-failure"; + EnvironmentFile = cfg.credentialsFile; + ExecStart = "${cfg.package}/bin/cachix deploy agent ${cfg.name} ${if cfg.profile != null then profile else ""}"; + }; + }; + }; +} diff --git a/nixos/modules/services/system/cloud-init.nix b/nixos/modules/services/system/cloud-init.nix new file mode 100644 index 00000000000..8c6a6e294eb --- /dev/null +++ b/nixos/modules/services/system/cloud-init.nix @@ -0,0 +1,194 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let cfg = config.services.cloud-init; + path = with pkgs; [ + cloud-init + iproute2 + nettools + openssh + shadow + util-linux + ] ++ optional cfg.btrfs.enable btrfs-progs + ++ optional cfg.ext4.enable e2fsprogs + ; +in +{ + options = { + services.cloud-init = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable the cloud-init service. This services reads + configuration metadata in a cloud environment and configures + the machine according to this metadata. + + This configuration is not completely compatible with the + NixOS way of doing configuration, as configuration done by + cloud-init might be overriden by a subsequent nixos-rebuild + call. However, some parts of cloud-init fall outside of + NixOS's responsibility, like filesystem resizing and ssh + public key provisioning, and cloud-init is useful for that + parts. Thus, be wary that using cloud-init in NixOS might + come as some cost. + ''; + }; + + btrfs.enable = mkOption { + type = types.bool; + default = false; + description = '' + Allow the cloud-init service to operate `btrfs` filesystem. + ''; + }; + + ext4.enable = mkOption { + type = types.bool; + default = true; + description = '' + Allow the cloud-init service to operate `ext4` filesystem. + ''; + }; + + network.enable = mkOption { + type = types.bool; + default = false; + description = '' + Allow the cloud-init service to configure network interfaces + through systemd-networkd. + ''; + }; + + config = mkOption { + type = types.str; + default = '' + system_info: + distro: nixos + network: + renderers: [ 'networkd' ] + users: + - root + + disable_root: false + preserve_hostname: false + + cloud_init_modules: + - migrator + - seed_random + - bootcmd + - write-files + - growpart + - resizefs + - update_etc_hosts + - ca-certs + - rsyslog + - users-groups + + cloud_config_modules: + - disk_setup + - mounts + - ssh-import-id + - set-passwords + - timezone + - disable-ec2-metadata + - runcmd + - ssh + + cloud_final_modules: + - rightscale_userdata + - scripts-vendor + - scripts-per-once + - scripts-per-boot + - scripts-per-instance + - scripts-user + - ssh-authkey-fingerprints + - keys-to-console + - phone-home + - final-message + - power-state-change + ''; + description = "cloud-init configuration."; + }; + + }; + + }; + + config = mkIf cfg.enable { + + environment.etc."cloud/cloud.cfg".text = cfg.config; + + systemd.network.enable = cfg.network.enable; + + systemd.services.cloud-init-local = + { description = "Initial cloud-init job (pre-networking)"; + wantedBy = [ "multi-user.target" ]; + before = ["systemd-networkd.service"]; + path = path; + serviceConfig = + { Type = "oneshot"; + ExecStart = "${pkgs.cloud-init}/bin/cloud-init init --local"; + RemainAfterExit = "yes"; + TimeoutSec = "infinity"; + StandardOutput = "journal+console"; + }; + }; + + systemd.services.cloud-init = + { description = "Initial cloud-init job (metadata service crawler)"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" "cloud-init-local.service" + "sshd.service" "sshd-keygen.service" ]; + after = [ "network-online.target" "cloud-init-local.service" ]; + before = [ "sshd.service" "sshd-keygen.service" ]; + requires = [ "network.target"]; + path = path; + serviceConfig = + { Type = "oneshot"; + ExecStart = "${pkgs.cloud-init}/bin/cloud-init init"; + RemainAfterExit = "yes"; + TimeoutSec = "infinity"; + StandardOutput = "journal+console"; + }; + }; + + systemd.services.cloud-config = + { description = "Apply the settings specified in cloud-config"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" "syslog.target" "cloud-config.target" ]; + + path = path; + serviceConfig = + { Type = "oneshot"; + ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=config"; + RemainAfterExit = "yes"; + TimeoutSec = "infinity"; + StandardOutput = "journal+console"; + }; + }; + + systemd.services.cloud-final = + { description = "Execute cloud user/final scripts"; + wantedBy = [ "multi-user.target" ]; + wants = [ "network-online.target" ]; + after = [ "network-online.target" "syslog.target" "cloud-config.service" "rc-local.service" ]; + requires = [ "cloud-config.target" ]; + path = path; + serviceConfig = + { Type = "oneshot"; + ExecStart = "${pkgs.cloud-init}/bin/cloud-init modules --mode=final"; + RemainAfterExit = "yes"; + TimeoutSec = "infinity"; + StandardOutput = "journal+console"; + }; + }; + + systemd.targets.cloud-config = + { description = "Cloud-config availability"; + requires = [ "cloud-init-local.service" "cloud-init.service" ]; + }; + }; +} diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix new file mode 100644 index 00000000000..d4cacb85694 --- /dev/null +++ b/nixos/modules/services/system/dbus.nix @@ -0,0 +1,139 @@ +# D-Bus configuration and system bus daemon. + +{ config, lib, options, pkgs, ... }: + +with lib; + +let + + cfg = config.services.dbus; + + homeDir = "/run/dbus"; + + configDir = pkgs.makeDBusConf { + inherit (cfg) apparmor; + suidHelper = "${config.security.wrapperDir}/dbus-daemon-launch-helper"; + serviceDirectories = cfg.packages; + }; + +in + +{ + ###### interface + + options = { + + services.dbus = { + + enable = mkOption { + type = types.bool; + default = false; + internal = true; + description = '' + Whether to start the D-Bus message bus daemon, which is + required by many other system services and applications. + ''; + }; + + packages = mkOption { + type = types.listOf types.path; + default = [ ]; + description = '' + Packages whose D-Bus configuration files should be included in + the configuration of the D-Bus system-wide or session-wide + message bus. Specifically, files in the following directories + will be included into their respective DBus configuration paths: + <filename><replaceable>pkg</replaceable>/etc/dbus-1/system.d</filename> + <filename><replaceable>pkg</replaceable>/share/dbus-1/system.d</filename> + <filename><replaceable>pkg</replaceable>/share/dbus-1/system-services</filename> + <filename><replaceable>pkg</replaceable>/etc/dbus-1/session.d</filename> + <filename><replaceable>pkg</replaceable>/share/dbus-1/session.d</filename> + <filename><replaceable>pkg</replaceable>/share/dbus-1/services</filename> + ''; + }; + + apparmor = mkOption { + type = types.enum [ "enabled" "disabled" "required" ]; + description = '' + AppArmor mode for dbus. + + <literal>enabled</literal> enables mediation when it's + supported in the kernel, <literal>disabled</literal> + always disables AppArmor even with kernel support, and + <literal>required</literal> fails when AppArmor was not found + in the kernel. + ''; + default = "disabled"; + }; + + socketActivated = mkOption { + type = types.nullOr types.bool; + default = null; + visible = false; + description = '' + Removed option, do not use. + ''; + }; + }; + }; + + ###### implementation + + config = mkIf cfg.enable { + warnings = optional (cfg.socketActivated != null) ( + let + files = showFiles options.services.dbus.socketActivated.files; + in + "The option 'services.dbus.socketActivated' in ${files} no longer has" + + " any effect and can be safely removed: the user D-Bus session is" + + " now always socket activated." + ); + + environment.systemPackages = [ pkgs.dbus.daemon pkgs.dbus ]; + + environment.etc."dbus-1".source = configDir; + + users.users.messagebus = { + uid = config.ids.uids.messagebus; + description = "D-Bus system message bus daemon user"; + home = homeDir; + group = "messagebus"; + }; + + users.groups.messagebus.gid = config.ids.gids.messagebus; + + systemd.packages = [ pkgs.dbus.daemon ]; + + security.wrappers.dbus-daemon-launch-helper = { + source = "${pkgs.dbus.daemon}/libexec/dbus-daemon-launch-helper"; + owner = "root"; + group = "messagebus"; + setuid = true; + setgid = false; + permissions = "u+rx,g+rx,o-rx"; + }; + + services.dbus.packages = [ + pkgs.dbus.out + config.system.path + ]; + + systemd.services.dbus = { + # Don't restart dbus-daemon. Bad things tend to happen if we do. + reloadIfChanged = true; + restartTriggers = [ configDir ]; + environment = { LD_LIBRARY_PATH = config.system.nssModules.path; }; + }; + + systemd.user = { + services.dbus = { + # Don't restart dbus-daemon. Bad things tend to happen if we do. + reloadIfChanged = true; + restartTriggers = [ configDir ]; + }; + sockets.dbus.wantedBy = [ "sockets.target" ]; + }; + + environment.pathsToLink = [ "/etc/dbus-1" "/share/dbus-1" ]; + }; +} diff --git a/nixos/modules/services/system/earlyoom.nix b/nixos/modules/services/system/earlyoom.nix new file mode 100644 index 00000000000..ddd5bcebcdd --- /dev/null +++ b/nixos/modules/services/system/earlyoom.nix @@ -0,0 +1,104 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.earlyoom; + + inherit (lib) + mkDefault mkEnableOption mkIf mkOption types + mkRemovedOptionModule + concatStringsSep optional; + +in +{ + options.services.earlyoom = { + enable = mkEnableOption "Early out of memory killing"; + + freeMemThreshold = mkOption { + type = types.ints.between 1 100; + default = 10; + description = '' + Minimum of availabe memory (in percent). + If the free memory falls below this threshold and the analog is true for + <option>services.earlyoom.freeSwapThreshold</option> + the killing begins. + ''; + }; + + freeSwapThreshold = mkOption { + type = types.ints.between 1 100; + default = 10; + description = '' + Minimum of availabe swap space (in percent). + If the available swap space falls below this threshold and the analog + is true for <option>services.earlyoom.freeMemThreshold</option> + the killing begins. + ''; + }; + + # TODO: remove or warn after 1.7 (https://github.com/rfjakob/earlyoom/commit/7ebc4554) + ignoreOOMScoreAdjust = mkOption { + type = types.bool; + default = false; + description = '' + Ignore oom_score_adjust values of processes. + ''; + }; + + enableDebugInfo = mkOption { + type = types.bool; + default = false; + description = '' + Enable debugging messages. + ''; + }; + + enableNotifications = mkOption { + type = types.bool; + default = false; + description = '' + Send notifications about killed processes via the system d-bus. + + WARNING: enabling this option (while convenient) should *not* be done on a + machine where you do not trust the other users as it allows any other + local user to DoS your session by spamming notifications. + + To actually see the notifications in your GUI session, you need to have + <literal>systembus-notify</literal> running as your user which this + option handles. + + See <link xlink:href="https://github.com/rfjakob/earlyoom#notifications">README</link> for details. + ''; + }; + }; + + imports = [ + (mkRemovedOptionModule [ "services" "earlyoom" "useKernelOOMKiller" ] '' + This option is deprecated and ignored by earlyoom since 1.2. + '') + (mkRemovedOptionModule [ "services" "earlyoom" "notificationsCommand" ] '' + This option is deprecated and ignored by earlyoom since 1.6. + '') + ]; + + config = mkIf cfg.enable { + services.systembus-notify.enable = mkDefault cfg.enableNotifications; + + systemd.services.earlyoom = { + description = "Early OOM Daemon for Linux"; + wantedBy = [ "multi-user.target" ]; + path = optional cfg.enableNotifications pkgs.dbus; + serviceConfig = { + StandardError = "journal"; + ExecStart = concatStringsSep " " ([ + "${pkgs.earlyoom}/bin/earlyoom" + "-m ${toString cfg.freeMemThreshold}" + "-s ${toString cfg.freeSwapThreshold}" + ] + ++ optional cfg.ignoreOOMScoreAdjust "-i" + ++ optional cfg.enableDebugInfo "-d" + ++ optional cfg.enableNotifications "-n" + ); + }; + }; + }; +} diff --git a/nixos/modules/services/system/kerberos/default.nix b/nixos/modules/services/system/kerberos/default.nix new file mode 100644 index 00000000000..9a1e6739901 --- /dev/null +++ b/nixos/modules/services/system/kerberos/default.nix @@ -0,0 +1,75 @@ +{config, lib, ...}: + +let + inherit (lib) mkOption mkIf types length attrNames; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + + aclEntry = { + options = { + principal = mkOption { + type = types.str; + description = "Which principal the rule applies to"; + }; + access = mkOption { + type = types.either + (types.listOf (types.enum ["add" "cpw" "delete" "get" "list" "modify"])) + (types.enum ["all"]); + default = "all"; + description = "The changes the principal is allowed to make."; + }; + target = mkOption { + type = types.str; + default = "*"; + description = "The principals that 'access' applies to."; + }; + }; + }; + + realm = { + options = { + acl = mkOption { + type = types.listOf (types.submodule aclEntry); + default = [ + { principal = "*/admin"; access = "all"; } + { principal = "admin"; access = "all"; } + ]; + description = '' + The privileges granted to a user. + ''; + }; + }; + }; +in + +{ + imports = [ + ./mit.nix + ./heimdal.nix + ]; + + ###### interface + options = { + services.kerberos_server = { + enable = lib.mkEnableOption "the kerberos authentification server"; + + realms = mkOption { + type = types.attrsOf (types.submodule realm); + description = '' + The realm(s) to serve keys for. + ''; + }; + }; + }; + + + ###### implementation + + config = mkIf cfg.enable { + environment.systemPackages = [ kerberos ]; + assertions = [{ + assertion = length (attrNames cfg.realms) <= 1; + message = "Only one realm per server is currently supported."; + }]; + }; +} diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix new file mode 100644 index 00000000000..837c59caa56 --- /dev/null +++ b/nixos/modules/services/system/kerberos/heimdal.nix @@ -0,0 +1,68 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mkIf concatStringsSep concatMapStrings toList mapAttrs + mapAttrsToList; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + stateDir = "/var/heimdal"; + aclFiles = mapAttrs + (name: {acl, ...}: pkgs.writeText "${name}.acl" (concatMapStrings (( + {principal, access, target, ...} : + "${principal}\t${concatStringsSep "," (toList access)}\t${target}\n" + )) acl)) cfg.realms; + + kdcConfigs = mapAttrsToList (name: value: '' + database = { + dbname = ${stateDir}/heimdal + acl_file = ${value} + } + '') aclFiles; + kdcConfFile = pkgs.writeText "kdc.conf" '' + [kdc] + ${concatStringsSep "\n" kdcConfigs} + ''; +in + +{ + # No documentation about correct triggers, so guessing at them. + + config = mkIf (cfg.enable && kerberos == pkgs.heimdal) { + systemd.services.kadmind = { + description = "Kerberos Administration Daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = + "${kerberos}/libexec/heimdal/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; + restartTriggers = [ kdcConfFile ]; + }; + + systemd.services.kdc = { + description = "Key Distribution Center daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = + "${kerberos}/libexec/heimdal/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; + restartTriggers = [ kdcConfFile ]; + }; + + systemd.services.kpasswdd = { + description = "Kerberos Password Changing daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = "${kerberos}/libexec/heimdal/kpasswdd"; + restartTriggers = [ kdcConfFile ]; + }; + + environment.etc = { + # Can be set via the --config-file option to KDC + "heimdal-kdc/kdc.conf".source = kdcConfFile; + }; + }; +} diff --git a/nixos/modules/services/system/kerberos/mit.nix b/nixos/modules/services/system/kerberos/mit.nix new file mode 100644 index 00000000000..25d7d51e808 --- /dev/null +++ b/nixos/modules/services/system/kerberos/mit.nix @@ -0,0 +1,68 @@ +{ pkgs, config, lib, ... } : + +let + inherit (lib) mkIf concatStrings concatStringsSep concatMapStrings toList + mapAttrs mapAttrsToList; + cfg = config.services.kerberos_server; + kerberos = config.krb5.kerberos; + stateDir = "/var/lib/krb5kdc"; + PIDFile = "/run/kdc.pid"; + aclMap = { + add = "a"; cpw = "c"; delete = "d"; get = "i"; list = "l"; modify = "m"; + all = "*"; + }; + aclFiles = mapAttrs + (name: {acl, ...}: (pkgs.writeText "${name}.acl" (concatMapStrings ( + {principal, access, target, ...} : + let access_code = map (a: aclMap.${a}) (toList access); in + "${principal} ${concatStrings access_code} ${target}\n" + ) acl))) cfg.realms; + kdcConfigs = mapAttrsToList (name: value: '' + ${name} = { + acl_file = ${value} + } + '') aclFiles; + kdcConfFile = pkgs.writeText "kdc.conf" '' + [realms] + ${concatStringsSep "\n" kdcConfigs} + ''; + env = { + # What Debian uses, could possibly link directly to Nix store? + KRB5_KDC_PROFILE = "/etc/krb5kdc/kdc.conf"; + }; +in + +{ + config = mkIf (cfg.enable && kerberos == pkgs.krb5Full) { + systemd.services.kadmind = { + description = "Kerberos Administration Daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig.ExecStart = "${kerberos}/bin/kadmind -nofork"; + restartTriggers = [ kdcConfFile ]; + environment = env; + }; + + systemd.services.kdc = { + description = "Key Distribution Center daemon"; + wantedBy = [ "multi-user.target" ]; + preStart = '' + mkdir -m 0755 -p ${stateDir} + ''; + serviceConfig = { + Type = "forking"; + PIDFile = PIDFile; + ExecStart = "${kerberos}/bin/krb5kdc -P ${PIDFile}"; + }; + restartTriggers = [ kdcConfFile ]; + environment = env; + }; + + environment.etc = { + "krb5kdc/kdc.conf".source = kdcConfFile; + }; + environment.variables = env; + }; +} diff --git a/nixos/modules/services/system/localtime.nix b/nixos/modules/services/system/localtime.nix new file mode 100644 index 00000000000..8f23454af9d --- /dev/null +++ b/nixos/modules/services/system/localtime.nix @@ -0,0 +1,49 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.localtime; +in { + options = { + services.localtime = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable <literal>localtime</literal>, simple daemon for keeping the system + timezone up-to-date based on the current location. It uses geoclue2 to + determine the current location and systemd-timedated to actually set + the timezone. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + services.geoclue2 = { + enable = true; + appConfig.localtime = { + isAllowed = true; + isSystem = true; + }; + }; + + # Install the polkit rules. + environment.systemPackages = [ pkgs.localtime ]; + # Install the systemd unit. + systemd.packages = [ pkgs.localtime ]; + + users.users.localtimed = { + description = "localtime daemon"; + isSystemUser = true; + group = "localtimed"; + }; + users.groups.localtimed = {}; + + systemd.services.localtime = { + wantedBy = [ "multi-user.target" ]; + serviceConfig.Restart = "on-failure"; + }; + }; +} diff --git a/nixos/modules/services/system/nscd.conf b/nixos/modules/services/system/nscd.conf new file mode 100644 index 00000000000..722b883ba42 --- /dev/null +++ b/nixos/modules/services/system/nscd.conf @@ -0,0 +1,34 @@ +# We basically use nscd as a proxy for forwarding nss requests to appropriate +# nss modules, as we run nscd with LD_LIBRARY_PATH set to the directory +# containing all such modules +# Note that we can not use `enable-cache no` As this will actually cause nscd +# to just reject the nss requests it receives, which then causes glibc to +# fallback to trying to handle the request by itself. Which won't work as glibc +# is not aware of the path in which the nss modules live. As a workaround, we +# have `enable-cache yes` with an explicit ttl of 0 +server-user nscd + +enable-cache passwd yes +positive-time-to-live passwd 0 +negative-time-to-live passwd 0 +shared passwd yes + +enable-cache group yes +positive-time-to-live group 0 +negative-time-to-live group 0 +shared group yes + +enable-cache netgroup yes +positive-time-to-live netgroup 0 +negative-time-to-live netgroup 0 +shared netgroup yes + +enable-cache hosts yes +positive-time-to-live hosts 0 +negative-time-to-live hosts 0 +shared hosts yes + +enable-cache services yes +positive-time-to-live services 0 +negative-time-to-live services 0 +shared services yes diff --git a/nixos/modules/services/system/nscd.nix b/nixos/modules/services/system/nscd.nix new file mode 100644 index 00000000000..00a87e788dc --- /dev/null +++ b/nixos/modules/services/system/nscd.nix @@ -0,0 +1,87 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + nssModulesPath = config.system.nssModules.path; + cfg = config.services.nscd; + + nscd = if pkgs.stdenv.hostPlatform.libc == "glibc" + then pkgs.stdenv.cc.libc.bin + else pkgs.glibc.bin; + +in + +{ + + ###### interface + + options = { + + services.nscd = { + + enable = mkOption { + type = types.bool; + default = true; + description = '' + Whether to enable the Name Service Cache Daemon. + Disabling this is strongly discouraged, as this effectively disables NSS Lookups + from all non-glibc NSS modules, including the ones provided by systemd. + ''; + }; + + config = mkOption { + type = types.lines; + default = builtins.readFile ./nscd.conf; + description = "Configuration to use for Name Service Cache Daemon."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + environment.etc."nscd.conf".text = cfg.config; + + systemd.services.nscd = + { description = "Name Service Cache Daemon"; + + before = [ "nss-lookup.target" "nss-user-lookup.target" ]; + wants = [ "nss-lookup.target" "nss-user-lookup.target" ]; + wantedBy = [ "multi-user.target" ]; + + environment = { LD_LIBRARY_PATH = nssModulesPath; }; + + restartTriggers = [ + config.environment.etc.hosts.source + config.environment.etc."nsswitch.conf".source + config.environment.etc."nscd.conf".source + ]; + + # We use DynamicUser because in default configurations nscd doesn't + # create any files that need to survive restarts. However, in some + # configurations, nscd needs to be started as root; it will drop + # privileges after all the NSS modules have read their configuration + # files. So prefix the ExecStart command with "!" to prevent systemd + # from dropping privileges early. See ExecStart in systemd.service(5). + serviceConfig = + { ExecStart = "!@${nscd}/sbin/nscd nscd"; + Type = "forking"; + DynamicUser = true; + RuntimeDirectory = "nscd"; + PIDFile = "/run/nscd/nscd.pid"; + Restart = "always"; + ExecReload = + [ "${nscd}/sbin/nscd --invalidate passwd" + "${nscd}/sbin/nscd --invalidate group" + "${nscd}/sbin/nscd --invalidate hosts" + ]; + }; + }; + + }; +} diff --git a/nixos/modules/services/system/saslauthd.nix b/nixos/modules/services/system/saslauthd.nix new file mode 100644 index 00000000000..466b0ca60a7 --- /dev/null +++ b/nixos/modules/services/system/saslauthd.nix @@ -0,0 +1,62 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.saslauthd; + +in + +{ + + ###### interface + + options = { + + services.saslauthd = { + + enable = mkEnableOption "saslauthd, the Cyrus SASL authentication daemon"; + + package = mkOption { + default = pkgs.cyrus_sasl.bin; + defaultText = literalExpression "pkgs.cyrus_sasl.bin"; + type = types.package; + description = "Cyrus SASL package to use."; + }; + + mechanism = mkOption { + type = types.str; + default = "pam"; + description = "Auth mechanism to use"; + }; + + config = mkOption { + type = types.lines; + default = ""; + description = "Configuration to use for Cyrus SASL authentication daemon."; + }; + + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + systemd.services.saslauthd = { + description = "Cyrus SASL authentication daemon"; + + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + ExecStart = "@${cfg.package}/sbin/saslauthd saslauthd -a ${cfg.mechanism} -O ${pkgs.writeText "saslauthd.conf" cfg.config}"; + Type = "forking"; + PIDFile = "/run/saslauthd/saslauthd.pid"; + Restart = "always"; + }; + }; + }; +} diff --git a/nixos/modules/services/system/self-deploy.nix b/nixos/modules/services/system/self-deploy.nix new file mode 100644 index 00000000000..d7130a13c73 --- /dev/null +++ b/nixos/modules/services/system/self-deploy.nix @@ -0,0 +1,173 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.self-deploy; + + workingDirectory = "/var/lib/nixos-self-deploy"; + repositoryDirectory = "${workingDirectory}/repo"; + outPath = "${workingDirectory}/system"; + + gitWithRepo = "git -C ${repositoryDirectory}"; + + renderNixArgs = args: + let + toArg = key: value: + if builtins.isString value + then " --argstr ${lib.escapeShellArg key} ${lib.escapeShellArg value}" + else " --arg ${lib.escapeShellArg key} ${lib.escapeShellArg (toString value)}"; + in + lib.concatStrings (lib.mapAttrsToList toArg args); + + isPathType = x: lib.strings.isCoercibleToString x && builtins.substring 0 1 (toString x) == "/"; + +in +{ + options.services.self-deploy = { + enable = lib.mkEnableOption "self-deploy"; + + nixFile = lib.mkOption { + type = lib.types.path; + + default = "/default.nix"; + + description = '' + Path to nix file in repository. Leading '/' refers to root of + git repository. + ''; + }; + + nixAttribute = lib.mkOption { + type = with lib.types; nullOr str; + + default = null; + + description = '' + Attribute of `nixFile` that builds the current system. + ''; + }; + + nixArgs = lib.mkOption { + type = lib.types.attrs; + + default = { }; + + description = '' + Arguments to `nix-build` passed as `--argstr` or `--arg` depending on + the type. + ''; + }; + + switchCommand = lib.mkOption { + type = lib.types.enum [ "boot" "switch" "dry-activate" "test" ]; + + default = "switch"; + + description = '' + The `switch-to-configuration` subcommand used. + ''; + }; + + repository = lib.mkOption { + type = with lib.types; oneOf [ path str ]; + + description = '' + The repository to fetch from. Must be properly formatted for git. + + If this value is set to a path (must begin with `/`) then it's + assumed that the repository is local and the resulting service + won't wait for the network to be up. + + If the repository will be fetched over SSH, you must add an + entry to `programs.ssh.knownHosts` for the SSH host for the fetch + to be successful. + ''; + }; + + sshKeyFile = lib.mkOption { + type = with lib.types; nullOr path; + + default = null; + + description = '' + Path to SSH private key used to fetch private repositories over + SSH. + ''; + }; + + branch = lib.mkOption { + type = lib.types.str; + + default = "master"; + + description = '' + Branch to track + + Technically speaking any ref can be specified here, as this is + passed directly to a `git fetch`, but for the use-case of + continuous deployment you're likely to want to specify a branch. + ''; + }; + + startAt = lib.mkOption { + type = with lib.types; either str (listOf str); + + default = "hourly"; + + description = '' + The schedule on which to run the `self-deploy` service. Format + specified by `systemd.time 7`. + + This value can also be a list of `systemd.time 7` formatted + strings, in which case the service will be started on multiple + schedules. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.self-deploy = { + inherit (cfg) startAt; + + wantedBy = [ "multi-user.target" ]; + + requires = lib.mkIf (!(isPathType cfg.repository)) [ "network-online.target" ]; + + environment.GIT_SSH_COMMAND = lib.mkIf (!(isNull cfg.sshKeyFile)) + "${pkgs.openssh}/bin/ssh -i ${lib.escapeShellArg cfg.sshKeyFile}"; + + restartIfChanged = false; + + path = with pkgs; [ + git + nix + ] ++ lib.optionals (cfg.switchCommand == "boot") [ systemd ]; + + script = '' + if [ ! -e ${repositoryDirectory} ]; then + mkdir --parents ${repositoryDirectory} + git init ${repositoryDirectory} + fi + + ${gitWithRepo} fetch ${lib.escapeShellArg cfg.repository} ${lib.escapeShellArg cfg.branch} + + ${gitWithRepo} checkout FETCH_HEAD + + nix-build${renderNixArgs cfg.nixArgs} ${lib.cli.toGNUCommandLineShell { } { + attr = cfg.nixAttribute; + out-link = outPath; + }} ${lib.escapeShellArg "${repositoryDirectory}${cfg.nixFile}"} + + ${lib.optionalString (cfg.switchCommand != "test") + "nix-env --profile /nix/var/nix/profiles/system --set ${outPath}"} + + ${outPath}/bin/switch-to-configuration ${cfg.switchCommand} + + rm ${outPath} + + ${gitWithRepo} gc --prune=all + + ${lib.optionalString (cfg.switchCommand == "boot") "systemctl reboot"} + ''; + }; + }; +} diff --git a/nixos/modules/services/system/systembus-notify.nix b/nixos/modules/services/system/systembus-notify.nix new file mode 100644 index 00000000000..e918bc552ec --- /dev/null +++ b/nixos/modules/services/system/systembus-notify.nix @@ -0,0 +1,27 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.services.systembus-notify; + + inherit (lib) mkEnableOption mkIf; + +in +{ + options.services.systembus-notify = { + enable = mkEnableOption '' + System bus notification support + + WARNING: enabling this option (while convenient) should *not* be done on a + machine where you do not trust the other users as it allows any other + local user to DoS your session by spamming notifications. + ''; + }; + + config = mkIf cfg.enable { + systemd = { + packages = with pkgs; [ systembus-notify ]; + + user.services.systembus-notify.wantedBy = [ "graphical-session.target" ]; + }; + }; +} diff --git a/nixos/modules/services/system/uptimed.nix b/nixos/modules/services/system/uptimed.nix new file mode 100644 index 00000000000..67a03876e19 --- /dev/null +++ b/nixos/modules/services/system/uptimed.nix @@ -0,0 +1,60 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.uptimed; + stateDir = "/var/lib/uptimed"; +in +{ + options = { + services.uptimed = { + enable = mkOption { + type = types.bool; + default = false; + description = '' + Enable <literal>uptimed</literal>, allowing you to track + your highest uptimes. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.uptimed ]; + + users.users.uptimed = { + description = "Uptimed daemon user"; + home = stateDir; + uid = config.ids.uids.uptimed; + group = "uptimed"; + }; + users.groups.uptimed = {}; + + systemd.services.uptimed = { + unitConfig.Documentation = "man:uptimed(8) man:uprecords(1)"; + description = "uptimed service"; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Restart = "on-failure"; + User = "uptimed"; + Nice = 19; + IOSchedulingClass = "idle"; + PrivateTmp = "yes"; + PrivateNetwork = "yes"; + NoNewPrivileges = "yes"; + StateDirectory = [ "uptimed" ]; + InaccessibleDirectories = "/home"; + ExecStart = "${pkgs.uptimed}/sbin/uptimed -f -p ${stateDir}/pid"; + }; + + preStart = '' + if ! test -f ${stateDir}/bootid ; then + ${pkgs.uptimed}/sbin/uptimed -b + fi + ''; + }; + }; +} |