lol

nixos/postgresql: document psql 15 changes (#267238)

* nixos/postgresql: document psql 15 changes

* nixos/postgresql: manual heading ids

* nixos/postgresql: reword warning against initialScript

Co-authored-by: Ryan Lahfa <masterancpp@gmail.com>

* nixos/postgresql: wording PERMISSIONS -> PRIVILEGES

Co-authored-by: Ryan Lahfa <masterancpp@gmail.com>

* nixos/postgresql: document intermediate oneshot / service user method

* nixos/postgresql/docs: clarify security benefits of `ensureDBOwnership`

* nixos/postgresql/docs: service type -> serviceConfig.Type

---------

Co-authored-by: Ryan Lahfa <masterancpp@gmail.com>

authored by

Herwig Hochleitner
Ryan Lahfa
and committed by
GitHub
e7c7d971 c7f0bbcf

+119
+119
nixos/modules/services/databases/postgresql.md
··· 39 39 services.postgresql.dataDir = "/data/postgresql"; 40 40 ``` 41 41 42 + ## Initializing {#module-services-postgres-initializing} 43 + 44 + As of NixOS 23.11, 45 + `services.postgresql.ensureUsers.*.ensurePermissions` has been 46 + deprecated, after a change to default permissions in PostgreSQL 15 47 + invalidated most of its previous use cases: 48 + 49 + - In psql < 15, `ALL PRIVILEGES` used to include `CREATE TABLE`, where 50 + in psql >= 15 that would be a separate permission 51 + - psql >= 15 instead gives only the database owner create permissions 52 + - Even on psql < 15 (or databases migrated to >= 15), it is 53 + recommended to manually assign permissions along these lines 54 + - https://www.postgresql.org/docs/release/15.0/ 55 + - https://www.postgresql.org/docs/15/ddl-schemas.html#DDL-SCHEMAS-PRIV 56 + 57 + ### Assigning ownership {#module-services-postgres-initializing-ownership} 58 + 59 + Usually, the database owner should be a database user of the same 60 + name. This can be done with 61 + `services.postgresql.ensureUsers.*.ensureDBOwnership = true;`. 62 + 63 + If the database user name equals the connecting system user name, 64 + postgres by default will accept a passwordless connection via unix 65 + domain socket. This makes it possible to run many postgres-backed 66 + services without creating any database secrets at all 67 + 68 + ### Assigning extra permissions {#module-services-postgres-initializing-extra-permissions} 69 + 70 + For many cases, it will be enough to have the database user be the 71 + owner. Until `services.postgresql.ensureUsers.*.ensurePermissions` has 72 + been re-thought, if more users need access to the database, please use 73 + one of the following approaches: 74 + 75 + **WARNING:** `services.postgresql.initialScript` is not recommended 76 + for `ensurePermissions` replacement, as that is *only run on first 77 + start of PostgreSQL*. 78 + 79 + **NOTE:** all of these methods may be obsoleted, when `ensure*` is 80 + reworked, but it is expected that they will stay viable for running 81 + database migrations. 82 + 83 + **NOTE:** please make sure that any added migrations are idempotent (re-runnable). 84 + 85 + #### as superuser {#module-services-postgres-initializing-extra-permissions-superuser} 86 + 87 + **Advantage:** compatible with postgres < 15, because it's run 88 + as the database superuser `postgres`. 89 + 90 + ##### in database `postStart` {#module-services-postgres-initializing-extra-permissions-superuser-post-start} 91 + 92 + **Disadvantage:** need to take care of ordering yourself. In this 93 + example, `mkAfter` ensures that permissions are assigned after any 94 + databases from `ensureDatabases` and `extraUser1` from `ensureUsers` 95 + are already created. 96 + 97 + ```nix 98 + systemd.services.postgresql.postStart = lib.mkAfter '' 99 + $PSQL service1 -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 100 + $PSQL service1 -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 101 + # .... 102 + ''; 103 + ``` 104 + 105 + ##### in intermediate oneshot service {#module-services-postgres-initializing-extra-permissions-superuser-oneshot} 106 + 107 + ```nix 108 + systemd.services."migrate-service1-db1" = { 109 + serviceConfig.Type = "oneshot"; 110 + requiredBy = "service1.service"; 111 + before = "service1.service"; 112 + after = "postgresql.service"; 113 + serviceConfig.User = "postgres"; 114 + environment.PSQL = "psql --port=${toString services.postgresql.port}"; 115 + path = [ postgresql ]; 116 + script = '' 117 + $PSQL service1 -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 118 + $PSQL service1 -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 119 + # .... 120 + ''; 121 + }; 122 + ``` 123 + 124 + #### as service user {#module-services-postgres-initializing-extra-permissions-service-user} 125 + 126 + **Advantage:** re-uses systemd's dependency ordering; 127 + 128 + **Disadvantage:** relies on service user having grant permission. To be combined with `ensureDBOwnership`. 129 + 130 + ##### in service `preStart` {#module-services-postgres-initializing-extra-permissions-service-user-pre-start} 131 + 132 + ```nix 133 + environment.PSQL = "psql --port=${toString services.postgresql.port}"; 134 + path = [ postgresql ]; 135 + systemd.services."service1".preStart = '' 136 + $PSQL -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 137 + $PSQL -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 138 + # .... 139 + ''; 140 + ``` 141 + 142 + ##### in intermediate oneshot service {#module-services-postgres-initializing-extra-permissions-service-user-oneshot} 143 + 144 + ```nix 145 + systemd.services."migrate-service1-db1" = { 146 + serviceConfig.Type = "oneshot"; 147 + requiredBy = "service1.service"; 148 + before = "service1.service"; 149 + after = "postgresql.service"; 150 + serviceConfig.User = "service1"; 151 + environment.PSQL = "psql --port=${toString services.postgresql.port}"; 152 + path = [ postgresql ]; 153 + script = '' 154 + $PSQL -c 'GRANT SELECT ON ALL TABLES IN SCHEMA public TO "extraUser1"' 155 + $PSQL -c 'GRANT SELECT ON ALL SEQUENCES IN SCHEMA public TO "extraUser1"' 156 + # .... 157 + ''; 158 + }; 159 + ``` 160 + 42 161 ## Upgrading {#module-services-postgres-upgrading} 43 162 44 163 ::: {.note}