nixos/postgresql: improve local peer authentication with default map

This allows to easily map allowed database roles to system users.

Changed files
+58 -1
nixos
doc
modules
services
tests
postgresql
+6
nixos/doc/manual/redirects.json
···
"module-services-postgres-initializing-extra-permissions-service-user-oneshot": [
"index.html#module-services-postgres-initializing-extra-permissions-service-user-oneshot"
],
"module-services-postgres-upgrading": [
"index.html#module-services-postgres-upgrading"
],
···
"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"
],
+32
nixos/modules/services/databases/postgresql.md
···
}
```
## Upgrading {#module-services-postgres-upgrading}
::: {.note}
···
}
```
+
## 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}
+16
nixos/modules/services/databases/postgresql.nix
···
Defines the mapping from system users to database users.
See the [auth doc](https://postgresql.org/docs/current/auth-username-maps.html).
'';
};
···
(mkBefore "# Generated file; do not edit!")
(mkAfter ''
# default value of services.postgresql.authentication
local all all peer
host all all 127.0.0.1/32 md5
host all all ::1/128 md5
'')
];
services.postgresql.systemCallFilter = mkMerge [
(mapAttrs (const mkDefault) {
···
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
+
```
'';
};
···
(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) {
+4 -1
nixos/tests/postgresql/postgresql.nix
···
services.postgresql = {
inherit package;
enable = true;
# 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 ];
···
in
''
def check_count(statement, lines):
-
return 'test $(sudo -u postgres psql postgres -tAc "{}"|wc -l) -eq {}'.format(
statement, lines
)
···
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 ];
···
in
''
def check_count(statement, lines):
+
return 'test $(psql -U postgres postgres -tAc "{}"|wc -l) -eq {}'.format(
statement, lines
)