lean4: from rev to tag (#379518)
[NixPkgs.git] / nixos / modules / services / networking / ntp / chrony.nix
blob7f187126cabd0a508b8ff5a3d99908c620b71c28
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
6   cfg = config.services.chrony;
7   chronyPkg = cfg.package;
9   stateDir = cfg.directory;
10   driftFile = "${stateDir}/chrony.drift";
11   keyFile = "${stateDir}/chrony.keys";
12   rtcFile = "${stateDir}/chrony.rtc";
14   configFile = pkgs.writeText "chrony.conf" ''
15     ${concatMapStringsSep "\n" (server: "server " + server + " " + cfg.serverOption + optionalString (cfg.enableNTS) " nts") cfg.servers}
17     ${optionalString
18       (cfg.initstepslew.enabled && (cfg.servers != []))
19       "initstepslew ${toString cfg.initstepslew.threshold} ${concatStringsSep " " cfg.servers}"
20     }
22     driftfile ${driftFile}
23     keyfile ${keyFile}
24     ${optionalString (cfg.enableRTCTrimming) "rtcfile ${rtcFile}"}
25     ${optionalString (cfg.enableNTS) "ntsdumpdir ${stateDir}"}
27     ${optionalString (cfg.enableRTCTrimming) "rtcautotrim ${builtins.toString cfg.autotrimThreshold}"}
28     ${optionalString (!config.time.hardwareClockInLocalTime) "rtconutc"}
30     ${cfg.extraConfig}
31   '';
33   chronyFlags =
34     [ "-n" "-u" "chrony" "-f" "${configFile}" ]
35     ++ optional cfg.enableMemoryLocking "-m"
36     ++ cfg.extraFlags;
39   options = {
40     services.chrony = {
41       enable = mkOption {
42         type = types.bool;
43         default = false;
44         description = ''
45           Whether to synchronise your machine's time using chrony.
46           Make sure you disable NTP if you enable this service.
47         '';
48       };
50       package = mkPackageOption pkgs "chrony" { };
52       servers = mkOption {
53         default = config.networking.timeServers;
54         defaultText = literalExpression "config.networking.timeServers";
55         type = types.listOf types.str;
56         description = ''
57           The set of NTP servers from which to synchronise.
58         '';
59       };
61       serverOption = mkOption {
62         default = "iburst";
63         type = types.enum [ "iburst" "offline" ];
64         description = ''
65           Set option for server directives.
67           Use "iburst" to rapidly poll on startup. Recommended if your machine
68           is consistently online.
70           Use "offline" to prevent polling on startup. Recommended if your
71           machine boots offline or is otherwise frequently offline.
72         '';
73       };
75       enableMemoryLocking = mkOption {
76         type = types.bool;
77         default = config.environment.memoryAllocator.provider != "graphene-hardened" && config.environment.memoryAllocator.provider != "graphene-hardened-light";
78         defaultText = ''config.environment.memoryAllocator.provider != "graphene-hardened" && config.environment.memoryAllocator.provider != "graphene-hardened-light"'';
79         description = ''
80           Whether to add the `-m` flag to lock memory.
81         '';
82       };
84       enableRTCTrimming = mkOption {
85         type = types.bool;
86         default = true;
87         description = ''
88           Enable tracking of the RTC offset to the system clock and automatic trimming.
89           See also [](#opt-services.chrony.autotrimThreshold)
91           ::: {.note}
92           This is not compatible with the `rtcsync` directive, which naively syncs the RTC time every 11 minutes.
94           Tracking the RTC drift will allow more precise timekeeping,
95           especially on intermittently running devices, where the RTC is very relevant.
96           :::
97         '';
98       };
100       autotrimThreshold = mkOption {
101         type = types.ints.positive;
102         default = 30;
103         example = 10;
104         description = ''
105           Maximum estimated error threshold for the `rtcautotrim` command.
106           When reached, the RTC will be trimmed.
107           Only used when [](#opt-services.chrony.enableRTCTrimming) is enabled.
108         '';
109       };
111       enableNTS = mkOption {
112         type = types.bool;
113         default = false;
114         description = ''
115           Whether to enable Network Time Security authentication.
116           Make sure it is supported by your selected NTP server(s).
117         '';
118       };
120       initstepslew = {
121         enabled = mkOption {
122           type = types.bool;
123           default = true;
124           description = ''
125             Allow chronyd to make a rapid measurement of the system clock error
126             at boot time, and to correct the system clock by stepping before
127             normal operation begins.
128           '';
129         };
131         threshold = mkOption {
132           type = types.either types.float types.int;
133           default = 1000; # by default, same threshold as 'ntpd -g' (1000s)
134           description = ''
135             The threshold of system clock error (in seconds) above which the
136             clock will be stepped. If the correction required is less than the
137             threshold, a slew is used instead.
138           '';
139         };
140       };
142       directory = mkOption {
143         type = types.str;
144         default = "/var/lib/chrony";
145         description = "Directory where chrony state is stored.";
146       };
148       extraConfig = mkOption {
149         type = types.lines;
150         default = "";
151         description = ''
152           Extra configuration directives that should be added to
153           `chrony.conf`
154         '';
155       };
157       extraFlags = mkOption {
158         default = [ ];
159         example = [ "-s" ];
160         type = types.listOf types.str;
161         description = "Extra flags passed to the chronyd command.";
162       };
163     };
164   };
166   config = mkIf cfg.enable {
167     meta.maintainers = with lib.maintainers; [ thoughtpolice vifino ];
169     environment.systemPackages = [ chronyPkg ];
171     users.groups.chrony.gid = config.ids.gids.chrony;
173     users.users.chrony =
174       {
175         uid = config.ids.uids.chrony;
176         group = "chrony";
177         description = "chrony daemon user";
178         home = stateDir;
179       };
181     services.timesyncd.enable = mkForce false;
183     # If chrony controls and tracks the RTC, writing it externally causes clock error.
184     systemd.services.save-hwclock = lib.mkIf cfg.enableRTCTrimming {
185       enable = lib.mkForce false;
186     };
188     systemd.services.systemd-timedated.environment = { SYSTEMD_TIMEDATED_NTP_SERVICES = "chronyd.service"; };
190     systemd.tmpfiles.rules = [
191       "d ${stateDir} 0750 chrony chrony - -"
192       "f ${driftFile} 0640 chrony chrony - -"
193       "f ${keyFile} 0640 chrony chrony - -"
194     ] ++ lib.optionals cfg.enableRTCTrimming [
195       "f ${rtcFile} 0640 chrony chrony - -"
196     ];
198     systemd.services.chronyd =
199       {
200         description = "chrony NTP daemon";
202         wantedBy = [ "multi-user.target" ];
203         wants = [ "time-sync.target" ];
204         before = [ "time-sync.target" ];
205         after = [ "network.target" "nss-lookup.target" ];
206         conflicts = [ "ntpd.service" "systemd-timesyncd.service" ];
208         path = [ chronyPkg ];
210         unitConfig.ConditionCapability = "CAP_SYS_TIME";
211         serviceConfig = {
212           Type = "simple";
213           ExecStart = "${chronyPkg}/bin/chronyd ${builtins.toString chronyFlags}";
215           # Proc filesystem
216           ProcSubset = "pid";
217           ProtectProc = "invisible";
218           # Access write directories
219           ReadWritePaths = [ "${stateDir}" ];
220           UMask = "0027";
221           # Capabilities
222           CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_DAC_OVERRIDE" "CAP_NET_BIND_SERVICE" "CAP_SETGID" "CAP_SETUID" "CAP_SYS_RESOURCE" "CAP_SYS_TIME" ];
223           # Device Access
224           DeviceAllow = [ "char-pps rw" "char-ptp rw" "char-rtc rw" ];
225           DevicePolicy = "closed";
226           # Security
227           NoNewPrivileges = true;
228           # Sandboxing
229           ProtectSystem = "full";
230           ProtectHome = true;
231           PrivateTmp = true;
232           PrivateDevices = false;
233           PrivateUsers = false;
234           ProtectHostname = true;
235           ProtectClock = false;
236           ProtectKernelTunables = true;
237           ProtectKernelModules = true;
238           ProtectKernelLogs = true;
239           ProtectControlGroups = true;
240           RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
241           RestrictNamespaces = true;
242           LockPersonality = true;
243           MemoryDenyWriteExecute = true;
244           RestrictRealtime = true;
245           RestrictSUIDSGID = true;
246           RemoveIPC = true;
247           PrivateMounts = true;
248           # System Call Filtering
249           SystemCallArchitectures = "native";
250           SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @resources" "@clock" "@setuid" "capset" "@chown" ];
251         };
252       };
254     assertions = [
255       {
256         assertion = !(cfg.enableRTCTrimming && builtins.any (line: (builtins.match "^ *rtcsync" line) != null) (lib.strings.splitString "\n" cfg.extraConfig));
257         message = ''
258           The chrony module now configures `rtcfile` and `rtcautotrim` for you.
259           These options conflict with `rtcsync` and cause chrony to crash.
260           Unless you are very sure the former isn't what you want, please remove
261           `rtcsync` from `services.chrony.extraConfig`.
262           Alternatively, disable this behaviour by `services.chrony.enableRTCTrimming = false;`
263         '';
264       }
265     ];
266   };