config/roles/postgres.nix

103 lines
3.2 KiB
Nix

{
name = "PostgreSQL";
description = ''
Runs a PostgreSQL database server on this host.
Other roles can use this role to create the required databases on this host through the
`postgres` attribute.
'';
nixosModule =
{
lib,
pkgs,
config,
...
}:
with lib;
{
options.postgres = {
databases = mkOption {
type = types.listOf types.str;
default = [ ];
};
};
config =
let
cfg = config.postgres;
in
{
# Create the postgresql service
services.postgresql = {
enable = true;
enableTCPIP = true;
ensureDatabases = map (db: db) cfg.databases;
ensureUsers = map (db: {
name = db;
ensureDBOwnership = true;
ensureClauses.login = true;
}) cfg.databases;
identMap = ''
# ArbitraryMapName systemUser DBUser
superuser_map root postgres
superuser_map postgres postgres
'';
authentication = pkgs.lib.mkOverride 10 ''
# Allow local users to log into the database user with the same name
local sameuser postgres peer map=superuser_map
# Allow "md5" (password) authentication
local all all md5
host all all 0.0.0.0/0 md5
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
'';
};
networking.firewall.allowedTCPPorts = [
5432
];
# Persist the database contents across reboots
# TODO: This should be automatically backed up daily into the CEPH
# cluster storage. It can't be on the cluster all the time, since
# CEPH doesn't perform great with databases (according to people
# online).
environment.persistence."/persistent" = {
directories = [
{
directory = "/var/lib/postgresql";
user = "postgres";
mode = "0700";
}
];
};
# Create the required secret files
sops.secrets = listToAttrs (
map (db: {
name = "postgres/${db}";
value = {
owner = "postgres";
};
}) cfg.databases
);
# Use the secret files from sops to set database user passwords
systemd.services.postgresql.postStart = concatMapStrings (db: ''
$PSQL -tA <<'EOF'
DO $$
DECLARE username TEXT;
DECLARE password TEXT;
BEGIN
username := trim(both from replace('${db}', E'\n', '''));
password := trim(both from replace(pg_read_file('${
(attrsets.getAttrFromPath [ "postgres/${db}" ] config.sops.secrets).path
}'), E'\n', '''));
EXECUTE format('ALTER ROLE %s WITH PASSWORD '''%s''';', username, password);
END $$;
EOF
'') cfg.databases;
};
};
}