nixos/postgresql: improve local peer authentication with default map (#404315)

This commit is contained in:
Wolfgang Walther
2025-05-11 10:09:00 +00:00
committed by GitHub
5 changed files with 63 additions and 8 deletions

View File

@@ -1286,6 +1286,12 @@
"module-services-postgres-initializing-extra-permissions-service-user-oneshot": [
"index.html#module-services-postgres-initializing-extra-permissions-service-user-oneshot"
],
"module-services-postgres-authentication": [
"index.html#module-services-postgres-authentication"
],
"module-services-postgres-authentication-user-mapping": [
"index.html#module-services-postgres-authentication-user-mapping"
],
"module-services-postgres-upgrading": [
"index.html#module-services-postgres-upgrading"
],

View File

@@ -564,16 +564,14 @@ in
services.postgresql.enable = lib.mkIf haveLocalDB true;
services.postgresql.identMap = lib.optionalString haveLocalDB ''
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
hydra hydra hydra
hydra hydra-queue-runner hydra
hydra hydra-www hydra
hydra root hydra
'';
services.postgresql.authentication = lib.optionalString haveLocalDB ''
local hydra all ident map=hydra-users
local all hydra peer map=hydra
'';
};

View File

@@ -170,6 +170,38 @@ are already created.
}
```
## Authentication {#module-services-postgres-authentication}
Local connections are made through unix sockets by default and support [peer authentication](https://www.postgresql.org/docs/current/auth-peer.html).
This allows system users to login with database roles of the same name.
For example, the `postgres` system user is allowed to login with the database role `postgres`.
System users and database roles might not always match.
In this case, to allow access for a service, you can create a [user name map](https://www.postgresql.org/docs/current/auth-username-maps.html) between system roles and an existing database role.
### User Mapping {#module-services-postgres-authentication-user-mapping}
Assume that your app creates a role `admin` and you want the `root` user to be able to login with it.
You can then use [](#opt-services.postgresql.identMap) to define the map and [](#opt-services.postgresql.authentication) to enable it:
```nix
services.postgresql = {
identMap = ''
admin root admin
'';
authentication = ''
local all admin peer map=admin
'';
}
```
::: {.warning}
To avoid conflicts with other modules, you should never apply a map to `all` roles.
Because PostgreSQL will stop on the first matching line in `pg_hba.conf`, a line matching all roles would lock out other services.
Each module should only manage user maps for the database roles that belong to this module.
Best practice is to name the map after the database role it manages to avoid name conflicts.
:::
## Upgrading {#module-services-postgres-upgrading}
::: {.note}

View File

@@ -274,6 +274,14 @@ in
Defines the mapping from system users to database users.
See the [auth doc](https://postgresql.org/docs/current/auth-username-maps.html).
There is a default map "postgres" which is used for local peer authentication
as the postgres superuser role.
For example, to allow the root user to login as the postgres superuser, add:
```
postgres root postgres
```
'';
};
@@ -674,12 +682,20 @@ in
(mkBefore "# Generated file; do not edit!")
(mkAfter ''
# default value of services.postgresql.authentication
local all postgres peer map=postgres
local all all peer
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
'')
];
# The default allows to login with the same database username as the current system user.
# This is the default for peer authentication without a map, but needs to be made explicit
# once a map is used.
services.postgresql.identMap = mkAfter ''
postgres postgres postgres
'';
services.postgresql.systemCallFilter = mkMerge [
(mapAttrs (const mkDefault) {
"@system-service" = true;

View File

@@ -54,6 +54,9 @@ let
services.postgresql = {
inherit package;
enable = true;
identMap = ''
postgres root postgres
'';
# TODO(@Ma27) split this off into its own VM test and move a few other
# extension tests to use postgresqlTestExtension.
extensions = ps: with ps; [ plv8 ];
@@ -73,7 +76,7 @@ let
in
''
def check_count(statement, lines):
return 'test $(sudo -u postgres psql postgres -tAc "{}"|wc -l) -eq {}'.format(
return 'test $(psql -U postgres postgres -tAc "{}"|wc -l) -eq {}'.format(
statement, lines
)