infra/services/postgres/default.nix
raito 92560708b8 feat: multi-tenant secrets
Lix may have its own secrets and we want to maintain a certain
generalization level on the NixOS modules, so we can decorrelate which
secret we select dynamically by having a simple tenancy hierarchy
system.

This unfortunately requires to rewrite all call sites with a floral
prefix until we migrate them to the simple internal secret module which
is aware of this.

Signed-off-by: Raito Bezarius <masterancpp@gmail.com>
2024-10-06 08:10:44 +00:00

106 lines
3 KiB
Nix

{ 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/floral/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/floral/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 <pg-username>" >&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"
'')
];
};
}