From 6fcc19f0a2d02f6d5f6525ab303bab916f319977 Mon Sep 17 00:00:00 2001 From: h7x4 Date: Fri, 22 May 2026 09:22:23 +0900 Subject: [PATCH] base/fluentbit: init --- base/default.nix | 1 + base/services/fluentbit.nix | 135 ++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 base/services/fluentbit.nix diff --git a/base/default.nix b/base/default.nix index 82bad7d..56cbf75 100644 --- a/base/default.nix +++ b/base/default.nix @@ -23,6 +23,7 @@ ./services/acme.nix ./services/auto-upgrade.nix ./services/dbus.nix + ./services/fluentbit.nix ./services/fwupd.nix ./services/irqbalance.nix ./services/journald-upload.nix diff --git a/base/services/fluentbit.nix b/base/services/fluentbit.nix new file mode 100644 index 0000000..caf865c --- /dev/null +++ b/base/services/fluentbit.nix @@ -0,0 +1,135 @@ +{ config, lib, ... }: +let + cfg = config.services.fluent-bit; +in +{ + services.fluent-bit = { + enable = lib.mkDefault true; + settings = { + service = { + flush = 1; + log_level = "warn"; + + http_server = "on"; + http_listen = "127.0.0.1"; + http_port = 28183; + + # filesystem-backed buffering so logs survives potential outages. + "storage.path" = "/var/lib/fluent-bit/storage"; + "storage.sync" = "normal"; + "storage.max_chunks_up" = 64; + "storage.backlog.mem_limit" = "16M"; + }; + + pipeline = { + inputs = [{ + name = "systemd"; + tag = "journal.*"; + + db = "/var/lib/fluent-bit/journal.db"; + read_from_tail = true; + strip_underscores = true; + lowercase = true; + max_entries = 1000; + "storage.type" = "filesystem"; + }]; + + filters = [{ + name = "modify"; + match = "journal.*"; + rename = [ + "hostname host" + "priority level" + "systemd_unit unit" + ]; + }] ++ (lib.mapAttrsToList (k: v: { + name = "modify"; + match = "journal.*"; + condition = "Key_value_equals level ${k}"; + set = "level ${v}"; + }) { + "7" = "debug"; + "6" = "info"; + "5" = "notice"; + "4" = "warning"; + "3" = "error"; + "2" = "crit"; + "1" = "alert"; + "0" = "emergency"; + }); + + outputs = [{ + name = "loki"; + match = "*"; + + host = "ildkule.pvv.ntnu.no"; + port = 3100; + uri = "/loki/api/v1/push"; + compress = "gzip"; + + labels = lib.concatStringsSep ", " [ + "job=systemd-journal" + ]; + label_keys = lib.concatMapStringsSep "," (k: "$" + k) [ + "host" + "unit" + "level" + ]; + + # JSON is probably fine for now, then we just extract the keys we want with the grafana web ui + # line_format = "key_value"; + # drop_single_key = true; + + "storage.total_limit_size" = "256M"; + }]; + }; + }; + }; + + systemd.services.fluent-bit = lib.mkIf cfg.enable { + serviceConfig = { + StateDirectory = "fluent-bit"; + + # NOTE: This hardening might be way too strong for general purpose use, don't upstream this. + AmbientCapabilities = [ "" ]; + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + # Lua JIT, maybe other things + MemoryDenyWriteExecute = false; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateTmp = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + UMask = "0077"; + + BindReadOnlyPaths = [ + "/run/systemd/journal" + ]; + }; + }; +}