{ 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; }; }; }