1{ config, lib, pkgs, ... }: with lib;
2let
3 cfg = config.services.promtail;
4
5 prettyJSON = conf: pkgs.runCommandLocal "promtail-config.json" {} ''
6 echo '${builtins.toJSON conf}' | ${pkgs.buildPackages.jq}/bin/jq 'del(._module)' > $out
7 '';
8
9 allowSystemdJournal = cfg.configuration ? scrape_configs && lib.any (v: v ? journal) cfg.configuration.scrape_configs;
10in {
11 options.services.promtail = with types; {
12 enable = mkEnableOption "the Promtail ingresser";
13
14
15 configuration = mkOption {
16 type = (pkgs.formats.json {}).type;
17 description = ''
18 Specify the configuration for Promtail in Nix.
19 '';
20 };
21
22 extraFlags = mkOption {
23 type = listOf str;
24 default = [];
25 example = [ "--server.http-listen-port=3101" ];
26 description = ''
27 Specify a list of additional command line flags,
28 which get escaped and are then passed to Loki.
29 '';
30 };
31 };
32
33 config = mkIf cfg.enable {
34 services.promtail.configuration.positions.filename = mkDefault "/var/cache/promtail/positions.yaml";
35
36 systemd.services.promtail = {
37 description = "Promtail log ingress";
38 wantedBy = [ "multi-user.target" ];
39 stopIfChanged = false;
40
41 serviceConfig = {
42 Restart = "on-failure";
43 TimeoutStopSec = 10;
44
45 ExecStart = "${pkgs.grafana-loki}/bin/promtail -config.file=${prettyJSON cfg.configuration} ${escapeShellArgs cfg.extraFlags}";
46
47 ProtectSystem = "strict";
48 ProtectHome = true;
49 PrivateTmp = true;
50 PrivateDevices = true;
51 ProtectKernelTunables = true;
52 ProtectControlGroups = true;
53 RestrictSUIDSGID = true;
54 PrivateMounts = true;
55 CacheDirectory = "promtail";
56
57 User = "promtail";
58 Group = "promtail";
59
60 CapabilityBoundingSet = "";
61 NoNewPrivileges = true;
62
63 ProtectKernelModules = true;
64 SystemCallArchitectures = "native";
65 ProtectKernelLogs = true;
66 ProtectClock = true;
67
68 LockPersonality = true;
69 ProtectHostname = true;
70 RestrictRealtime = true;
71 MemoryDenyWriteExecute = true;
72 PrivateUsers = true;
73
74 SupplementaryGroups = lib.optional (allowSystemdJournal) "systemd-journal";
75 } // (optionalAttrs (!pkgs.stdenv.isAarch64) { # FIXME: figure out why this breaks on aarch64
76 SystemCallFilter = "@system-service";
77 });
78 };
79
80 users.groups.promtail = {};
81 users.users.promtail = {
82 description = "Promtail service user";
83 isSystemUser = true;
84 group = "promtail";
85 };
86 };
87}