nixos: update-locatedb - harden via systemd (#7220)

Also, use systemd timers.

Most of the work is by @thoughtpolice but I changed enough of it to warrant changing commit author.

Changed files
+105 -94
nixos
doc
manual
development
modules
misc
+40 -34
nixos/doc/manual/development/writing-modules.xml
···
by other modules (typically the user’s
<filename>configuration.nix</filename>):
<option>services.locate.enable</option> (whether the database should
-
be updated) and <option>services.locate.period</option> (when the
update should be done). It implements its functionality by defining
two options declared by other modules:
<option>systemd.services</option> (the set of all systemd services)
-
and <option>services.cron.systemCronJobs</option> (the list of
-
commands to be executed periodically by <command>cron</command>).</para>
<example xml:id='locate-example'><title>NixOS Module for the “locate” Service</title>
<programlisting>
···
with lib;
-
let locatedb = "/var/cache/locatedb"; in
-
{
-
options = {
-
-
services.locate = {
-
-
enable = mkOption {
-
type = types.bool;
-
default = false;
-
description = ''
-
If enabled, NixOS will periodically update the database of
-
files used by the <command>locate</command> command.
-
'';
-
};
-
-
period = mkOption {
-
type = types.str;
-
default = "15 02 * * *";
-
description = ''
-
This option defines (in the format used by cron) when the
-
locate database is updated. The default is to update at
-
02:15 at night every day.
-
'';
-
};
};
};
config = {
-
systemd.services.update-locatedb =
{ description = "Update Locate Database";
path = [ pkgs.su ];
script =
''
-
mkdir -m 0755 -p $(dirname ${locatedb})
-
exec updatedb --localuser=nobody --output=${locatedb} --prunepaths='/tmp /var/tmp /run'
'';
};
-
services.cron.systemCronJobs = optional config.services.locate.enable
-
"${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service";
-
};
-
}</programlisting>
</example>
<xi:include href="option-declarations.xml" />
···
by other modules (typically the user’s
<filename>configuration.nix</filename>):
<option>services.locate.enable</option> (whether the database should
+
be updated) and <option>services.locate.interval</option> (when the
update should be done). It implements its functionality by defining
two options declared by other modules:
<option>systemd.services</option> (the set of all systemd services)
+
and <option>systemd.timers</option> (the list of commands to be
+
executed periodically by <command>systemd</command>).</para>
<example xml:id='locate-example'><title>NixOS Module for the “locate” Service</title>
<programlisting>
···
with lib;
+
let
+
cfg = config.services.locate;
+
in {
+
options.services.locate = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
If enabled, NixOS will periodically update the database of
+
files used by the <command>locate</command> command.
+
'';
+
};
+
interval = mkOption {
+
type = types.str;
+
default = "02:15";
+
example = "hourly";
+
description = ''
+
Update the locate database at this interval. Updates by
+
default at 2:15 AM every day.
+
The format is described in
+
<citerefentry><refentrytitle>systemd.time</refentrytitle>
+
<manvolnum>7</manvolnum></citerefentry>.
+
'';
};
+
# Other options omitted for documentation
};
config = {
systemd.services.update-locatedb =
{ description = "Update Locate Database";
path = [ pkgs.su ];
script =
''
+
mkdir -m 0755 -p $(dirname ${toString cfg.output})
+
exec updatedb \
+
--localuser=${cfg.localuser} \
+
${optionalString (!cfg.includeStore) "--prunepaths='/nix/store'"} \
+
--output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags}
'';
};
+
systemd.timers.update-locatedb = mkIf cfg.enable
+
{ description = "Update timer for locate database";
+
partOf = [ "update-locatedb.service" ];
+
wantedBy = [ "timers.target" ];
+
timerConfig.OnCalendar = cfg.interval;
+
};
};
+
}
+
</programlisting>
</example>
<xi:include href="option-declarations.xml" />
+65 -60
nixos/modules/misc/locate.nix
···
-
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.locate;
in {
-
###### interface
-
options = {
-
services.locate = {
-
enable = mkOption {
-
type = types.bool;
-
default = false;
-
description = ''
-
If enabled, NixOS will periodically update the database of
-
files used by the <command>locate</command> command.
-
'';
-
};
-
period = mkOption {
-
type = types.str;
-
default = "15 02 * * *";
-
description = ''
-
This option defines (in the format used by cron) when the
-
locate database is updated.
-
The default is to update at 02:15 at night every day.
-
'';
-
};
-
extraFlags = mkOption {
-
type = types.listOf types.str;
-
default = [ ];
-
description = ''
-
Extra flags to pass to <command>updatedb</command>.
-
'';
-
};
-
-
output = mkOption {
-
type = types.path;
-
default = "/var/cache/locatedb";
-
description = ''
-
The database file to build.
-
'';
-
};
-
-
localuser = mkOption {
-
type = types.str;
-
default = "nobody";
-
description = ''
-
The user to search non-network directories as, using
-
<command>su</command>.
-
'';
-
};
-
-
includeStore = mkOption {
-
type = types.bool;
-
default = false;
-
description = ''
-
Whether to include <filename>/nix/store</filename> in the locate database.
-
'';
-
};
-
};
};
-
###### implementation
-
config = {
systemd.services.update-locatedb =
{ description = "Update Locate Database";
path = [ pkgs.su ];
···
'';
serviceConfig.Nice = 19;
serviceConfig.IOSchedulingClass = "idle";
};
-
services.cron.systemCronJobs = optional config.services.locate.enable
-
"${config.services.locate.period} root ${config.systemd.package}/bin/systemctl start update-locatedb.service";
-
};
-
}
···
+
{ config, options, lib, pkgs, ... }:
with lib;
let
cfg = config.services.locate;
in {
+
options.services.locate = {
+
enable = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
If enabled, NixOS will periodically update the database of
+
files used by the <command>locate</command> command.
+
'';
+
};
+
interval = mkOption {
+
type = types.str;
+
default = "02:15";
+
example = "hourly";
+
description = ''
+
Update the locate database at this interval. Updates by
+
default at 2:15 AM every day.
+
The format is described in
+
<citerefentry><refentrytitle>systemd.time</refentrytitle>
+
<manvolnum>7</manvolnum></citerefentry>.
+
'';
+
};
+
# This is no longer supported, but we keep it to give a better warning below
+
period = mkOption { visible = false; };
+
extraFlags = mkOption {
+
type = types.listOf types.str;
+
default = [ ];
+
description = ''
+
Extra flags to pass to <command>updatedb</command>.
+
'';
+
};
+
output = mkOption {
+
type = types.path;
+
default = "/var/cache/locatedb";
+
description = ''
+
The database file to build.
+
'';
+
};
+
localuser = mkOption {
+
type = types.str;
+
default = "nobody";
+
description = ''
+
The user to search non-network directories as, using
+
<command>su</command>.
+
'';
};
+
includeStore = mkOption {
+
type = types.bool;
+
default = false;
+
description = ''
+
Whether to include <filename>/nix/store</filename> in the locate database.
+
'';
+
};
};
config = {
+
warnings = let opt = options.services.locate.period; in optional opt.isDefined "The `period` definition in ${showFiles opt.files} has been removed; please replace it with `interval`, using the new systemd.time interval specifier.";
+
systemd.services.update-locatedb =
{ description = "Update Locate Database";
path = [ pkgs.su ];
···
'';
serviceConfig.Nice = 19;
serviceConfig.IOSchedulingClass = "idle";
+
serviceConfig.PrivateTmp = "yes";
+
serviceConfig.PrivateNetwork = "yes";
+
serviceConfig.NoNewPrivileges = "yes";
+
serviceConfig.ReadOnlyDirectories = "/";
+
serviceConfig.ReadWriteDirectories = cfg.output;
};
+
systemd.timers.update-locatedb = mkIf cfg.enable
+
{ description = "Update timer for locate database";
+
partOf = [ "update-locatedb.service" ];
+
wantedBy = [ "timers.target" ];
+
timerConfig.OnCalendar = cfg.interval;
+
};
};
}