This commit is contained in:
Jonas Heinrich 2026-04-17 11:13:04 +02:00
parent 12d8d4cd8e
commit 3689dedd75
2 changed files with 75 additions and 207 deletions

View file

@ -1,5 +1,5 @@
{ {
description = "mail-quota-warning package and service"; description = "stalwart-tlsa-cloudflare service and timer";
inputs.nixpkgs.url = "nixpkgs/nixos-25.11"; inputs.nixpkgs.url = "nixpkgs/nixos-25.11";
@ -15,45 +15,7 @@
} }
); );
in { in {
overlay = final: prev: { # stalwart-tlsa-cloudflare-update service module
mail-quota-warning = with final; python3Packages.buildPythonApplication {
pname = "mail-quota-warning";
version = "0.0.1";
format = "other";
src = self;
dependencies = with python3Packages; [
python
pyyaml
imaplib2
];
installPhase = ''
install -Dm755 ${./mail-quota-warning.py} $out/bin/mail-quota-warning
'';
meta.mainProgram = "mail-quota-warning";
};
};
packages = forAllSystems (system: {
inherit (nixpkgsFor.${system}) mail-quota-warning;
});
defaultPackage = forAllSystems (system: self.packages.${system}.mail-quota-warning);
devShells = forAllSystems (system: let
pkgs = import nixpkgs { inherit system; overlays = [ self.overlay ]; };
in pkgs.mkShell {
buildInputs = with pkgs; with python3Packages; [
python
requests
beautifulsoup4
];
});
# mail-quota-warning service module
nixosModule = (import ./module.nix); nixosModule = (import ./module.nix);
}; };
} }

View file

@ -6,53 +6,29 @@
}: }:
let let
cfg = config.services.mail-quota-warning; cfg = config.services.stalwart-tlsa-cloudflare-update;
in in
{ {
options = { options = {
services.mail-quota-warning = { services.stalwart-tlsa-cloudflare-update = {
enable = lib.mkOption { enable = lib.mkOption {
type = lib.types.bool; type = lib.types.bool;
default = false; default = false;
description = '' description = ''
Enable mail-quota-warning daemon. Enable stalwart-tlsa-cloudflare-update daemon.
''; '';
}; };
settings = lib.mkOption { settings = lib.mkOption {
type = lib.types.submodule { type = lib.types.submodule {
freeformType = with lib.types; attrsOf anything; freeformType = with lib.types; attrsOf anything;
options = {
CHECK_INTERVAL_DAYS = lib.mkOption {
default = 7;
type = lib.types.int;
description = ''
Interval of days in which a warning message will be
delivered.
'';
};
QUOTA_WARNING_THRESHOLD_PERCENT = lib.mkOption {
default = 80;
type = lib.types.int;
description = ''
Threshold of used mailbox space in percent after which
a warning message will be delivered.
'';
};
};
}; };
default = { }; default = { };
description = '' description = ''
Extra options which should be used by the mailbox quota warning script. Extra options which should be used by the stalwart-tlsa-cloudflare-update script.
'';
example = lib.literalExpression ''
{
CHECK_INTERVAL_DAYS = 7;
QUOTA_WARNING_THRESHOLD_PERCENT = 80;
}
''; '';
}; };
@ -62,10 +38,9 @@ in
absolute = true; absolute = true;
}); });
default = null; default = null;
example = "/run/keys/mail-quota-warning-secrets"; example = "/run/keys/cloudflare-api-key";
description = '' description = ''
A YAML file containing secrets, see example config file Secret file containing cloudflare api key
in the repository.
''; '';
}; };
@ -85,8 +60,6 @@ in
config = lib.mkIf cfg.enable { config = lib.mkIf cfg.enable {
# FIXME maybe move this to an external module
systemd.services.tlsa-cloudflare-update = { systemd.services.tlsa-cloudflare-update = {
description = "Check and update TLSA/DANE record for mx1 from Stalwart ACME Cert"; description = "Check and update TLSA/DANE record for mx1 from Stalwart ACME Cert";
@ -97,16 +70,11 @@ in
Type = "oneshot"; Type = "oneshot";
User = "stalwart-mail"; User = "stalwart-mail";
Group = "stalwart-mail"; Group = "stalwart-mail";
EnvironmentFile = config.age.secrets.gotlsaflare-cloudflare-token.path; EnvironmentFile = cfg.secretFile;
RuntimeDirectory = "stalwart-tlsa"; RuntimeDirectory = "stalwart-tlsa";
}; };
environment = { environment = lib.mapAttrs (_: v: toString v) cfg.settings;
DOMAIN = "project-insanity.org";
SUBDOMAIN = "mx1";
PORT = "25";
ACME_PROVIDER_ID = "cloudflare3";
};
path = with pkgs; [ path = with pkgs; [
bash bash
@ -159,77 +127,15 @@ in
''; '';
}; };
systemd.timers.tlsa-cloudflare-update = { systemd.timers.stalwart-tlsa-cloudflare-update = {
description = "Run TLSA check and update every 15 minutes"; description = "Run TLSA check and update";
wantedBy = [ "timers.target" ]; wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = "2m";
OnUnitActiveSec = "15m";
Unit = "tlsa-cloudflare-update.service";
};
};
systemd.services."mail-quota-warning" = {
description = "mail-quota-warning script";
after = [ "network.target" ];
wants = [ "network-online.target" ];
environment = {
PYTHONUNBUFFERED = "1";
}
// lib.mapAttrs (_: v: toString v) cfg.settings;
serviceConfig = {
Type = "simple";
LoadCredential = lib.optionalString (cfg.secretFile != null) "secrets.yaml:${cfg.secretFile}";
ExecStart = "${lib.getExe pkgs.mail-quota-warning} --config \${CREDENTIALS_DIRECTORY}/secrets.yaml";
WorkingDirectory = "%S/mail-quota-warning";
StateDirectory = "mail-quota-warning";
# hardening
AmbientCapabilities = "";
CapabilityBoundingSet = "";
DevicePolicy = "closed";
DynamicUser = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RemoveIPC = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
];
UMask = "0077";
};
};
systemd.timers.mail-quota-warning = {
timerConfig = { timerConfig = {
OnCalendar = [ OnCalendar = [
"" ""
cfg.interval cfg.interval
]; ];
}; };
wantedBy = [ "timers.target" ];
}; };
}; };