Unverified Commit 797c149b authored by Wolfgang Walther's avatar Wolfgang Walther Committed by GitHub
Browse files

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

parents 4d7ffdf2 3d29b7d3
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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"
  ],
+5 −7
Original line number Diff line number Diff line
@@ -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
    '';

  };
+32 −0
Original line number Diff line number Diff line
@@ -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}
+16 −0
Original line number Diff line number Diff line
@@ -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;
+4 −1
Original line number Diff line number Diff line
@@ -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
              )