prod-pins/modules/server.nix
Alois 123205c97d
Some checks failed
action.yml / Centralize Tensamin packages modules and release automation (push) Failing after 0s
Canary release / release (push) Failing after 21s
Centralize Tensamin packages modules and release automation
2026-10-04 19:19:56 +02:00

199 lines
6.5 KiB
Nix

{ self, name }:
{
config,
lib,
pkgs,
...
}:
let
cfg = config.tensamin.${name};
isOmikron = name == "omikron";
inherit (lib) mkOption types;
cert = if cfg.acmeCertDir != null then "${cfg.acmeCertDir}/fullchain.pem" else cfg.certFile;
key = if cfg.acmeCertDir != null then "${cfg.acmeCertDir}/key.pem" else cfg.keyFile;
setup = pkgs.writeShellScript "${name}-setup" ''
set -eu
umask 077
install -d -m 0750 -o ${name} -g ${name} ${lib.escapeShellArg cfg.stateDir}
cd ${lib.escapeShellArg cfg.stateDir}
install -d -m 0700 -o ${name} -g ${name} certs
install -m 0644 -o ${name} -g ${name} ${
lib.escapeShellArg (if cert == null then "" else cert)
} certs/cert.pem
${pkgs.openssl}/bin/openssl pkcs8 -topk8 -nocrypt \
-in ${lib.escapeShellArg (if key == null then "" else key)} -out certs/key.pem
chown ${name}:${name} certs/key.pem
chmod 0600 certs/key.pem
${lib.optionalString isOmikron ''
install -m 0644 -o ${name} -g ${name} ${lib.escapeShellArg cfg.omegaTrustFile} omega.mpkb
''}
${lib.optionalString (cfg.identityFile != null) ''
install -m 0600 -o ${name} -g ${name} ${lib.escapeShellArg cfg.identityFile} ${name}.mk
''}
${lib.optionalString (cfg.publicIdentityFile != null) ''
install -m 0644 -o ${name} -g ${name} ${lib.escapeShellArg cfg.publicIdentityFile} ${name}.mpkb
''}
'';
in
{
options.tensamin.${name} = {
enable = lib.mkEnableOption "Tensamin ${name}";
package = mkOption {
type = types.package;
default = self.packages.${pkgs.stdenv.hostPlatform.system}.${name};
description = "Central ${name} package, or an explicit replacement.";
};
stateDir = mkOption {
type = types.str;
default = "/var/lib/${name}";
description = "Persistent working directory, including identities and certificates.";
};
bindAddress = mkOption {
type = types.str;
default = "0.0.0.0";
};
port = mkOption {
type = types.port;
default = 443;
};
openFirewall = mkOption {
type = types.bool;
default = true;
};
certFile = mkOption {
type = types.nullOr types.str;
default = null;
description = "Runtime TLS certificate path. Set together with keyFile.";
};
keyFile = mkOption {
type = types.nullOr types.str;
default = null;
description = "Runtime TLS private key path. Never copied into the Nix store.";
};
acmeCertDir = mkOption {
type = types.nullOr types.str;
default = null;
description = "Runtime directory containing fullchain.pem and key.pem. Restart the service after renewal.";
};
identityFile = mkOption {
type = types.nullOr types.str;
default = null;
description = "Existing private keyring to install at startup, or null to retain or generate state.";
};
publicIdentityFile = mkOption {
type = types.nullOr types.str;
default = null;
description = "Matching public key bundle to install at startup.";
};
environment = mkOption {
type = types.attrsOf types.str;
default = { };
description = "Additional non-secret runtime settings. Listener options take precedence.";
};
environmentFiles = mkOption {
type = types.listOf types.str;
default = [ ];
description =
if isOmikron then
"Runtime environment files, including optional LiveKit credentials."
else
"Runtime environment files. Supply DB_URL here; identities are file-based.";
};
}
// lib.optionalAttrs isOmikron {
id = mkOption {
type = types.ints.positive;
description = "Omikron ID assigned by Omega.";
};
omegaHost = mkOption {
type = types.str;
default = "tensamin.net";
};
omegaPort = mkOption {
type = types.port;
default = 9187;
};
omegaTrustFile = mkOption {
type = types.str;
description = "Runtime path to Omega's trusted public key bundle.";
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion =
(cfg.acmeCertDir != null && cfg.certFile == null && cfg.keyFile == null)
|| (cfg.acmeCertDir == null && cfg.certFile != null && cfg.keyFile != null);
message = "tensamin.${name}: set either acmeCertDir or both certFile and keyFile.";
}
{
assertion = (cfg.identityFile == null) == (cfg.publicIdentityFile == null);
message = "tensamin.${name}: identityFile and publicIdentityFile must be supplied together.";
}
{
assertion = lib.hasPrefix "/" cfg.stateDir;
message = "tensamin.${name}.stateDir must be absolute.";
}
];
users.users.${name} = {
isSystemUser = true;
group = name;
home = cfg.stateDir;
};
users.groups.${name} = { };
systemd.tmpfiles.rules = [ "d ${cfg.stateDir} 0750 ${name} ${name} -" ];
systemd.services.${name} = {
description = "Tensamin ${name}";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [ "network-online.target" ];
environment =
cfg.environment
// {
BIND_ADDRESS = cfg.bindAddress;
}
// (
if isOmikron then
{
RHO_PORT = toString cfg.port;
OMEGA_HOST = cfg.omegaHost;
OMEGA_PORT = toString cfg.omegaPort;
ID = toString cfg.id;
}
else
{ PORT = toString cfg.port; }
);
serviceConfig = {
Type = "simple";
User = name;
Group = name;
WorkingDirectory = cfg.stateDir;
ExecStart = "${cfg.package}/bin/${name}";
ExecStartPre = [ "+${setup}" ];
EnvironmentFile = cfg.environmentFiles;
Restart = "always";
RestartSec = "5s";
UMask = "0077";
AmbientCapabilities = lib.optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE";
CapabilityBoundingSet = lib.optional (cfg.port < 1024) "CAP_NET_BIND_SERVICE";
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
NoNewPrivileges = true;
ReadWritePaths = [ cfg.stateDir ];
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
};
};
networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ];
allowedUDPPorts = [ cfg.port ];
};
};
}