Files
nix-stuff/triple-dezert/database.nix
2025-02-21 16:10:34 -08:00

126 lines
4.2 KiB
Nix

{
config,
lib,
pkgs,
...
}:
# networking.firewall.extraCommands = ''
# iptables -t filter -I nixos-fw -i ve-awesome-service-name -p tcp -m tcp --dport 5432 -j nixos-fw-accept
# '';
# networking.firewall.extraStopCommands = ''
# iptables -t filter -D nixos-fw -i ve-awesome-service-name -p tcp -m tcp --dport 5432 -j nixos-fw-accept || true
# '';
let
inherit (lib) flip types mkOption;
cfg = config.vacu;
databases = lib.attrValues cfg.databases;
mapLines = lib.concatMapStringsSep "\n";
authText = flip mapLines databases (
d:
if d.authByIp != null then
# host database user address auth-method [auth-options]
''host "${d.name}" "${d.user}" ${d.authByIp}/32 trust''
else
# local database user auth-method [auth-options]
''local "${d.name}" "${d.user}" peer''
);
firewallDatabases = lib.filter (d: d.fromContainer != null) databases;
firewallCommands = flip mapLines firewallDatabases (
d:
"iptables -t filter -I nixos-fw -i ve-${d.fromContainer} -p tcp -m tcp --dport 5432 -j nixos-fw-accept"
);
firewallStopCommands = flip mapLines firewallDatabases (
d:
"iptables -t filter -D nixos-fw -i ve-${d.fromContainer} -p tcp -m tcp --dport 5432 -j nixos-fw-accept || true"
);
in
{
options.vacu.databases = mkOption {
default = { };
description = "Databases that should be created and how they should be accessed";
type = types.attrsOf (
types.submodule (
let
outer_config = config;
in
{ name, config, ... }:
{
options = {
name = mkOption {
type = types.str;
default = name;
description = "name of the database to create";
};
user = mkOption {
type = types.str;
default = name;
description = "username of the user created to access/own the database";
};
authByIp = mkOption {
type = types.nullOr types.str;
default = null;
description = "If set, user is authenticated based on connecting from the given ip address";
};
authByUser = mkOption {
type = types.bool;
default = false;
description = "If true, user is authenticated based on connecting to the unix socket from a process running as the user";
};
fromContainer = mkOption {
type = types.nullOr types.str;
default = null;
};
};
config = lib.mkIf (config.fromContainer != null) {
authByIp = outer_config.containers.${config.fromContainer}.localAddress;
};
}
)
);
};
config = {
vacu.assertions = map (d: {
assertion = (isNull d.authByIp) == d.authByUser;
# assertion = lib.debug.traceVal ((lib.debug.traceVal (isNull d.authByIp)) != (lib.debug.traceVal d.authByUser));
message = "either set authByIp non-null or authByUser true, but not both for database ${d.name}.";
}) databases;
networking.firewall.extraCommands = firewallCommands;
networking.firewall.extraStopCommands = firewallStopCommands;
services.postgresql = rec {
enable = true;
package = pkgs.postgresql_16;
dataDir = "/var/postgres/data/${package.psqlSchema}";
enableJIT = true;
initdbArgs = [ "--waldir=/var/postgres/wal/${package.psqlSchema}" ];
ensureUsers = [
{
name = "root";
ensureDBOwnership = true;
ensureClauses.superuser = true;
}
] ++ map (d: { name = d.user; }) databases;
ensureDatabases = [ "root" ] ++ map (d: d.name) databases;
settings.listen_addresses = lib.mkForce "0.0.0.0";
authentication = lib.mkForce ''
local all root peer
local all "${config.users.users.postgres.name}" peer
${authText}
'';
};
systemd.services.postgresql.postStart =
''
#START stuff from database.nix
''
+ (mapLines (d: ''$PSQL -tAc 'ALTER DATABASE "${d.name}" OWNER TO "${d.user}";' '') databases)
+ ''
#END stuff from database.nix
'';
systemd.services.postgresql.serviceConfig.ReadWritePaths = "/var/postgres";
};
}