0
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-07-14 14:10:33 +03:00
nixpkgs/nixos/modules/services/databases/postgres-websockets.nix
Wolfgang Walther 41c5662cbe
nixos/postgresql: move postStart into separate unit
This avoids restarting the postgresql server, when only ensureDatabases
or ensureUsers have been changed. It will also allow to properly wait
for recovery to finish later.

To wait for "postgresql is ready" in other services, we now provide a
postgresql.target.

Resolves #400018

Co-authored-by: Marcel <me@m4rc3l.de>
2025-06-24 15:26:47 +02:00

221 lines
6.4 KiB
Nix

{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.postgres-websockets;
# Turns an attrset of libpq connection params:
# {
# dbname = "postgres";
# user = "authenticator";
# }
# into a libpq connection string:
# dbname=postgres user=authenticator
PGWS_DB_URI = lib.pipe cfg.environment.PGWS_DB_URI [
(lib.filterAttrs (_: v: v != null))
(lib.mapAttrsToList (k: v: "${k}='${lib.escape [ "'" "\\" ] v}'"))
(lib.concatStringsSep " ")
];
in
{
meta = {
maintainers = with lib.maintainers; [ wolfgangwalther ];
};
options.services.postgres-websockets = {
enable = lib.mkEnableOption "postgres-websockets";
pgpassFile = lib.mkOption {
type =
with lib.types;
nullOr (pathWith {
inStore = false;
absolute = true;
});
default = null;
example = "/run/keys/db_password";
description = ''
The password to authenticate to PostgreSQL with.
Not needed for peer or trust based authentication.
The file must be a valid `.pgpass` file as described in:
<https://www.postgresql.org/docs/current/libpq-pgpass.html>
In most cases, the following will be enough:
```
*:*:*:*:<password>
```
'';
};
jwtSecretFile = lib.mkOption {
type =
with lib.types;
nullOr (pathWith {
inStore = false;
absolute = true;
});
example = "/run/keys/jwt_secret";
description = ''
Secret used to sign JWT tokens used to open communications channels.
'';
};
environment = lib.mkOption {
type = lib.types.submodule {
freeformType = with lib.types; attrsOf str;
options = {
PGWS_DB_URI = lib.mkOption {
type = lib.types.submodule {
freeformType = with lib.types; attrsOf str;
# This should not be used; use pgpassFile instead.
options.password = lib.mkOption {
default = null;
readOnly = true;
internal = true;
};
# This should not be used; use pgpassFile instead.
options.passfile = lib.mkOption {
default = null;
readOnly = true;
internal = true;
};
};
default = { };
description = ''
libpq connection parameters as documented in:
<https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS>
::: {.note}
The `environment.PGWS_DB_URI.password` and `environment.PGWS_DB_URI.passfile` options are blocked.
Use [`pgpassFile`](#opt-services.postgres-websockets.pgpassFile) instead.
:::
'';
example = lib.literalExpression ''
{
host = "localhost";
dbname = "postgres";
}
'';
};
# This should not be used; use jwtSecretFile instead.
PGWS_JWT_SECRET = lib.mkOption {
default = null;
readOnly = true;
internal = true;
};
PGWS_HOST = lib.mkOption {
type = with lib.types; nullOr str;
default = "127.0.0.1";
description = ''
Address the server will listen for websocket connections.
'';
};
};
};
default = { };
description = ''
postgres-websockets configuration as defined in:
<https://github.com/diogob/postgres-websockets/blob/master/src/PostgresWebsockets/Config.hs#L71-L87>
`PGWS_DB_URI` is represented as an attribute set, see [`environment.PGWS_DB_URI`](#opt-services.postgres-websockets.environment.PGWS_DB_URI)
::: {.note}
The `environment.PGWS_JWT_SECRET` option is blocked.
Use [`jwtSecretFile`](#opt-services.postgres-websockets.jwtSecretFile) instead.
:::
'';
example = lib.literalExpression ''
{
PGWS_LISTEN_CHANNEL = "my_channel";
PGWS_DB_URI.dbname = "postgres";
}
'';
};
};
config = lib.mkIf cfg.enable {
services.postgres-websockets.environment.PGWS_DB_URI.application_name =
with pkgs.postgres-websockets;
"${pname} ${version}";
systemd.services.postgres-websockets = {
description = "postgres-websockets";
wantedBy = [ "multi-user.target" ];
wants = [ "network-online.target" ];
after = [
"network-online.target"
"postgresql.target"
];
environment =
cfg.environment
// {
inherit PGWS_DB_URI;
PGWS_JWT_SECRET = "@%d/jwt_secret";
}
// lib.optionalAttrs (cfg.pgpassFile != null) {
PGPASSFILE = "%C/postgres-websockets/pgpass";
};
serviceConfig = {
CacheDirectory = "postgres-websockets";
CacheDirectoryMode = "0700";
LoadCredential = [
"jwt_secret:${cfg.jwtSecretFile}"
] ++ lib.optional (cfg.pgpassFile != null) "pgpass:${cfg.pgpassFile}";
Restart = "always";
User = "postgres-websockets";
# Hardening
CapabilityBoundingSet = [ "" ];
DevicePolicy = "closed";
DynamicUser = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateIPC = true;
PrivateMounts = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_UNIX"
];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "" ];
UMask = "0077";
};
# Copy the pgpass file to different location, to have it report mode 0400.
# Fixes: https://github.com/systemd/systemd/issues/29435
script = ''
if [ -f "$CREDENTIALS_DIRECTORY/pgpass" ]; then
cp -f "$CREDENTIALS_DIRECTORY/pgpass" "$CACHE_DIRECTORY/pgpass"
fi
exec ${lib.getExe pkgs.postgres-websockets}
'';
};
};
}