{ config, lib, pkgs, ... }: let cfg = config.bagel.services.postgres; dataDir = "/var/db/postgresql/16"; in { options.bagel.services.postgres = with lib; { enable = mkEnableOption "PostgreSQL server"; }; config = lib.mkIf cfg.enable { age.secrets.postgresql-tls-priv.owner = "postgres"; age.secrets.postgresql-tls-priv.file = ../../secrets/postgres-tls-priv.age; systemd.tmpfiles.rules = [ "d /var/db 0755 root root - -" "d /var/db/postgresql 0750 postgres postgres - -" "d ${dataDir} 0750 postgres postgres - -" ]; services.postgresql = { enable = true; package = pkgs.postgresql_16; dataDir = dataDir; enableTCPIP = true; # TODO: Where to put this to properly couple things? It doesn't belong # here, but using it in services/hydra would require running on # localhost. Probably needs to be replaced with some different way of # ensuring the DB/user exist. ensureDatabases = [ "hydra" ]; ensureUsers = [ { name = "hydra"; ensureDBOwnership = true; } ]; identMap = '' hydra-users hydra hydra hydra-users hydra-queue-runner hydra hydra-users hydra-www hydra hydra-users root hydra # The postgres user is used to create the pg_trgm extension for the hydra database hydra-users postgres postgres ''; authentication = '' local hydra all peer map=hydra-users # Allow any connection over TLS with a valid client certificate: signed # by our CA, and with username = cert CN. hostssl all all all cert clientcert=verify-full ''; settings = { max_connections = 500; ssl = true; ssl_ca_file = "${./ca.crt}"; ssl_cert_file = "${./server.crt}"; ssl_key_file = config.age.secrets.postgresql-tls-priv.path; }; }; networking.firewall.allowedTCPPorts = [ config.services.postgresql.settings.port ]; # Provisioned on the server so that CA operations can be done there. age.secrets.postgresql-ca-priv.owner = "postgres"; age.secrets.postgresql-ca-priv.file = ../../secrets/postgres-ca-priv.age; users.users.postgres.packages = [ (pkgs.writeShellScriptBin "postgres-mint-new-client" '' #! ${pkgs.runtimeShell} set -eo pipefail if [ $# -eq 0 ]; then echo "usage: $0 " >&2 exit 1 fi user=$1 step=${pkgs.lib.getExe pkgs.step-cli} tmpdir=$(mktemp -d) trap "rm -rf $tmpdir" EXIT $step certificate create "$user" "$tmpdir/client.crt" "$tmpdir/client.key" \ --profile leaf \ --ca ${./ca.crt} \ --ca-key ${config.age.secrets.postgresql-ca-priv.path} \ --not-after 87660h \ --no-password --insecure echo "Client certificate:" cat "$tmpdir/client.crt" echo echo "Client private key:" cat "$tmpdir/client.key" '') ]; }; }