nixpkgs/nixos/tests/postgresql/postgresql-tls-client-cert.nix
Maximilian Bosch eb96c8dc5b
postgresql: refactor postgresqlVersions attribute & tests
Every postgresql testcase essentially does the following things:

* Filter `postgresqlVersions` for server packages
* Filter postgresql server packages for suitable ones (i.e. extensions
  must support the given version)
* Generate an attribute-set of testcases

The first item became necessary in
7ab1e88833 given that
`postgresql/default.nix` now exposes JIT and non-JIT servers AND a
`libpq` that is not suitable for the tests here.

This changes restructures this a little bit, i.e.:

* Having an attribute-set that contains a bunch of postgresql servers
  and a single client package seems odd (and the sole consumer of
  `postgresqlVersions` in nixpkgs, the test suite, has to take that into
  account). Hence, postgresql's default.nix now provides `libpq` (the client)
  and a `postgresqlVersions` attribute with all supported JIT and non-JIT
  variants of postgresql.

* Each test-case gets a third argument, a function called `genTests`:
  this function sets `recurseForDerivations = true;` and generates an
  attribute-set of tests for each postgresql version given a function
  that returns a testcase or multiple test-cases (`makeTestFor`). The
  argument to `makeTestFor` is a postgresql server package.

  This function also accepts a filter predicate that is passed against
  `filterAttrs` to remove postgresql server packages that are not
  suitable for the test (e.g. because the version isn't supported by the
  extension to test).

I checked by making sure that the `.drv` doesn't change on staging with
this change on top for postgresq, postgresql-jit,
postgresql-wal-receiver, postgresql-tls-client-cert, anonymizer, pgjwt,
pgvecto-rs, timescaledb, tsja and wal2json.
2025-01-26 21:58:57 +01:00

133 lines
4.0 KiB
Nix

{
pkgs,
makeTest,
genTests,
}:
let
inherit (pkgs) lib;
runWithOpenSSL =
file: cmd:
pkgs.runCommand file {
buildInputs = [ pkgs.openssl ];
} cmd;
caKey = runWithOpenSSL "ca.key" "openssl ecparam -name prime256v1 -genkey -noout -out $out";
caCert = runWithOpenSSL "ca.crt" ''
openssl req -new -x509 -sha256 -key ${caKey} -out $out -subj "/CN=test.example" -days 36500
'';
serverKey = runWithOpenSSL "server.key" "openssl ecparam -name prime256v1 -genkey -noout -out $out";
serverKeyPath = "/var/lib/postgresql";
serverCert = runWithOpenSSL "server.crt" ''
openssl req -new -sha256 -key ${serverKey} -out server.csr -subj "/CN=db.test.example"
openssl x509 -req -in server.csr -CA ${caCert} -CAkey ${caKey} \
-CAcreateserial -out $out -days 36500 -sha256
'';
clientKey = runWithOpenSSL "client.key" "openssl ecparam -name prime256v1 -genkey -noout -out $out";
clientCert = runWithOpenSSL "client.crt" ''
openssl req -new -sha256 -key ${clientKey} -out client.csr -subj "/CN=test"
openssl x509 -req -in client.csr -CA ${caCert} -CAkey ${caKey} \
-CAcreateserial -out $out -days 36500 -sha256
'';
clientKeyPath = "/root";
makeTestFor =
package:
makeTest {
name = "postgresql-tls-client-cert-${package.name}";
meta.maintainers = with lib.maintainers; [ erictapen ];
nodes.server =
{ ... }:
{
system.activationScripts = {
keyPlacement.text = ''
mkdir -p '${serverKeyPath}'
cp '${serverKey}' '${serverKeyPath}/server.key'
chown postgres:postgres '${serverKeyPath}/server.key'
chmod 600 '${serverKeyPath}/server.key'
'';
};
services.postgresql = {
inherit package;
enable = true;
enableJIT = lib.hasInfix "-jit-" package.name;
enableTCPIP = true;
ensureUsers = [
{
name = "test";
ensureDBOwnership = true;
}
];
ensureDatabases = [ "test" ];
settings = {
ssl = "on";
ssl_ca_file = toString caCert;
ssl_cert_file = toString serverCert;
ssl_key_file = "${serverKeyPath}/server.key";
};
authentication = ''
hostssl test test ::/0 cert clientcert=verify-full
'';
};
networking = {
interfaces.eth1 = {
ipv6.addresses = [
{
address = "fc00::1";
prefixLength = 120;
}
];
};
firewall.allowedTCPPorts = [ 5432 ];
};
};
nodes.client =
{ ... }:
{
system.activationScripts = {
keyPlacement.text = ''
mkdir -p '${clientKeyPath}'
cp '${clientKey}' '${clientKeyPath}/client.key'
chown root:root '${clientKeyPath}/client.key'
chmod 600 '${clientKeyPath}/client.key'
'';
};
environment = {
variables = {
PGHOST = "db.test.example";
PGPORT = "5432";
PGDATABASE = "test";
PGUSER = "test";
PGSSLMODE = "verify-full";
PGSSLCERT = clientCert;
PGSSLKEY = "${clientKeyPath}/client.key";
PGSSLROOTCERT = caCert;
};
systemPackages = [ package ];
};
networking = {
interfaces.eth1 = {
ipv6.addresses = [
{
address = "fc00::2";
prefixLength = 120;
}
];
};
hosts = {
"fc00::1" = [ "db.test.example" ];
};
};
};
testScript = ''
server.wait_for_unit("multi-user.target")
client.wait_for_unit("multi-user.target")
client.succeed("psql -c \"SELECT 1;\"")
'';
};
in
genTests { inherit makeTestFor; }