nixpkgs/nixos/modules/services/mail/tlsrpt.nix
Martin Weinelt e030814446
nixos/tlsrpt: configure explicit http_script
Make sure we get curl into the system, since when the tlsrpt rua is an
HTTP URL we need to be able to deliver to that.
2025-07-29 06:16:36 +02:00

357 lines
9.8 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkEnableOption
mkIf
mkOption
mkPackageOption
types
;
cfg = config.services.tlsrpt;
format = pkgs.formats.ini { };
dropNullValues = lib.filterAttrsRecursive (_: value: value != null);
commonServiceSettings = {
DynamicUser = true;
User = "tlsrpt";
Restart = "always";
StateDirectory = "tlsrpt";
StateDirectoryMode = "0700";
# Hardening
CapabilityBoundingSet = [ "" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
PrivateDevices = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectControlGroups = true;
ProtectClock = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "noaccess";
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged @resources"
];
};
collectdConfigFile = format.generate "tlsrpt-collectd.cfg" {
tlsrpt_collectd = dropNullValues cfg.collectd.settings;
};
fetcherConfigFile = format.generate "tlsrpt-fetcher.cfg" {
tlsrpt_fetcher = dropNullValues cfg.fetcher.settings;
};
reportdConfigFile = format.generate "tlsrpt-reportd.cfg" {
tlsrpt_reportd = dropNullValues cfg.reportd.settings;
};
withPostfix = config.services.postfix.enable && cfg.configurePostfix;
in
{
options.services.tlsrpt = {
enable = mkEnableOption "the TLSRPT services";
package = mkPackageOption pkgs "tlsrpt-reporter" { };
collectd = {
settings = mkOption {
type = types.submodule {
freeformType = format.type;
options = {
storage = mkOption {
type = types.str;
default = "sqlite:///var/lib/tlsrpt/collectd.sqlite";
description = ''
Storage backend definition.
'';
};
socketname = mkOption {
type = types.path;
default = "/run/tlsrpt/collectd.sock";
description = ''
Path at which the UNIX socket will be created.
'';
};
socketmode = mkOption {
type = types.str;
default = "0220";
description = ''
Permissions on the UNIX socket.
'';
};
log_level = mkOption {
type = types.enum [
"debug"
"info"
"warning"
"error"
"critical"
];
default = "info";
description = ''
Level of log messages to emit.
'';
};
};
};
default = { };
description = ''
Flags from {manpage}`tlsrpt-collectd(1)` as key-value pairs.
'';
};
extraFlags = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
List of extra flags to pass to the tlsrpt-reportd executable.
See {manpage}`tlsrpt-collectd(1)` for possible flags.
'';
};
};
fetcher = {
settings = mkOption {
type = types.submodule {
freeformType = format.type;
options = {
storage = mkOption {
type = types.str;
default = config.services.tlsrpt.collectd.settings.storage;
defaultText = lib.literalExpression ''
config.services.tlsrpt.collectd.settings.storage
'';
description = ''
Path to the collectd sqlite database.
'';
};
log_level = mkOption {
type = types.enum [
"debug"
"info"
"warning"
"error"
"critical"
];
default = "info";
description = ''
Level of log messages to emit.
'';
};
};
};
default = { };
description = ''
Flags from {manpage}`tlsrpt-fetcher(1)` as key-value pairs.
'';
};
};
reportd = {
settings = mkOption {
type = types.submodule {
freeformType = format.type;
options = {
dbname = mkOption {
type = types.str;
default = "/var/lib/tlsrpt/reportd.sqlite";
description = ''
Path to the sqlite database.
'';
};
fetchers = mkOption {
type = types.str;
default = lib.getExe' cfg.package "tlsrpt-fetcher";
defaultText = lib.literalExpression ''
lib.getExe' cfg.package "tlsrpt-fetcher"
'';
description = ''
Comma-separated list of fetcher programs that retrieve collectd data.
'';
};
log_level = mkOption {
type = types.enum [
"debug"
"info"
"warning"
"error"
"critical"
];
default = "info";
description = ''
Level of log messages to emit.
'';
};
organization_name = mkOption {
type = types.str;
example = "ACME Corp.";
description = ''
Name of the organization sending out the reports.
'';
};
contact_info = mkOption {
type = types.str;
example = "smtp-tls-reporting@example.com";
description = ''
Contact information embedded into the reports.
'';
};
http_script = mkOption {
type = with types; nullOr str;
default = "${lib.getExe pkgs.curl} --silent --header 'Content-Type: application/tlsrpt+gzip' --data-binary @-";
defaultText = lib.literalExpression ''
''${lib.getExe pkgs.curl} --silent --header 'Content-Type: application/tlsrpt+gzip' --data-binary @-
'';
description = ''
Call to an HTTPS client, that accepts the URL on the commandline and the request body from stdin.
'';
};
sender_address = mkOption {
type = types.str;
example = "noreply@example.com";
description = ''
Sender address used for reports.
'';
};
sendmail_script = mkOption {
type = with types; nullOr str;
default =
if config.services.postfix.enable && config.services.postfix.setSendmail then
"/run/wrappers/bin/sendmail -i -t"
else
null;
defaultText = lib.literalExpression ''
if config.services.postfix.enable && config.services.postfix.setSendmail then
"/run/wrappers/bin/sendmail -i -t"
else
null
'';
description = ''
Path to a sendmail-compatible executable for delivery reports.
'';
};
};
};
default = { };
description = ''
Flags from {manpage}`tlsrpt-reportd(1)` as key-value pairs.
'';
};
extraFlags = mkOption {
type = with types; listOf str;
default = [ ];
description = ''
List of extra flags to pass to the tlsrpt-reportd executable.
See {manpage}`tlsrpt-report(1)` for possible flags.
'';
};
};
configurePostfix = mkOption {
type = types.bool;
default = true;
description = ''
Whether to configure permissions to allow integration with Postfix.
'';
};
};
config = mkIf cfg.enable {
environment.etc = {
"tlsrpt/collectd.cfg".source = collectdConfigFile;
"tlsrpt/fetcher.cfg".source = fetcherConfigFile;
"tlsrpt/reportd.cfg".source = reportdConfigFile;
};
users.users.tlsrpt = {
isSystemUser = true;
group = "tlsrpt";
};
users.groups.tlsrpt = { };
users.users.postfix.extraGroups = lib.mkIf withPostfix [
"tlsrpt"
];
systemd.services.tlsrpt-collectd = {
description = "TLSRPT datagram collector";
documentation = [ "man:tlsrpt-collectd(1)" ];
wantedBy = [ "multi-user.target" ];
restartTriggers = [ collectdConfigFile ];
serviceConfig = commonServiceSettings // {
ExecStart = toString (
[
(lib.getExe' cfg.package "tlsrpt-collectd")
]
++ cfg.collectd.extraFlags
);
IPAddressDeny = "any";
PrivateNetwork = true;
RestrictAddressFamilies = [ "AF_UNIX" ];
RuntimeDirectory = "tlsrpt";
RuntimeDirectoryMode = "0750";
UMask = "0157";
};
};
systemd.services.tlsrpt-reportd = {
description = "TLSRPT report generator";
documentation = [ "man:tlsrpt-reportd(1)" ];
wantedBy = [ "multi-user.target" ];
restartTriggers = [ reportdConfigFile ];
serviceConfig = commonServiceSettings // {
ExecStart = toString (
[
(lib.getExe' cfg.package "tlsrpt-reportd")
]
++ cfg.reportd.extraFlags
);
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
ReadWritePaths = lib.optionals withPostfix [ "/var/lib/postfix/queue/maildrop" ];
SupplementaryGroups = lib.optionals withPostfix [ "postdrop" ];
UMask = "0077";
};
};
};
}