Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

services.postgresql: Allow configuration of user roles in ensureUser #200724

Merged
merged 4 commits into from
Dec 17, 2022

Conversation

JonathanLorimer
Copy link
Contributor

Description of changes

This adds an attribute to the ensureUsers option on the services.postgresql module. The attribute allows you to set a list of roles that you want to applied to the user when the postgresql service starts up.

Things done
  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandbox = true set in nix.conf? (See Nix manual)
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 22.11 Release Notes (or backporting 22.05 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
    • (Release notes changes) Ran nixos/doc/manual/md-to-db.sh to update generated release notes
  • Fits CONTRIBUTING.md.

@JonathanLorimer JonathanLorimer changed the title Allow configuration of postgres roles Allow configuration of postgres user roles Nov 11, 2022
@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Nov 11, 2022
@JonathanLorimer JonathanLorimer changed the title Allow configuration of postgres user roles services.postgresql: Allow configuration of user roles in ensureUser Nov 11, 2022
@ofborg ofborg bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10 labels Nov 11, 2022
@JonathanLorimer JonathanLorimer requested review from jtojnar and removed request for thoughtpolice November 11, 2022 19:23
default = [ ];
description = lib.mdDoc ''
A list of roles to grant to the user. Under the hood this uses the
[ALTER USER syntax](https://www.postgresql.org/docs/current/sql-alteruser.html) for each role in the list:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Double space in "each role in". (Hehe, it seems github removes double space in these comments.)

@JonathanLorimer JonathanLorimer requested review from bjornfor and removed request for jtojnar November 13, 2022 15:52
@JonathanLorimer JonathanLorimer requested review from jtojnar and removed request for bjornfor November 14, 2022 15:12
@jtojnar
Copy link
Member

jtojnar commented Nov 14, 2022

Note that there is some uncertainty whether the database modules should have ensure* options, see e.g. #107342

Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a couple of suggestions, and this should be tested. You could extend nixos/tests/postgresql.nix for this purpose.

@@ -168,6 +168,18 @@ in
}
'';
};
ensureRoles = mkOption {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Roles and Users are synonymous in PostgreSQL.

The linked page calls them options. This page calls them clauses. That seems like an even better name.

description = lib.mdDoc ''
A list of roles to grant to the user. Under the hood this uses the
[ALTER USER syntax](https://www.postgresql.org/docs/current/sql-alteruser.html) for each role in the list:
`ALTER USER user.name WITH role`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can clauses be removed? We don't seem to have enough knowledge to remove unmentioned roles.

The linked page lists negatives as well: NOSUPERUSER, etc. Could those be used for this purpose?
A better option representation would be types.attrsOf types.bool. (or even individual options, to restrict it to known-valid attribute names; not sure if that's better)

With this infrastructure in place, we can also provide an option (off by default, not to break configs) for fully declarative user permissions; a matter of conditionally assigning some lib.mkDefault defaults to those options, so that they cover all possible clauses.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion. I will try to find some time this weekend to do this, as well as adding tests.

@JonathanLorimer JonathanLorimer requested review from roberth and removed request for jtojnar November 20, 2022 15:49
assert clauses['rolreplication'], 'expected user with clauses to have replication clause'
assert clauses['rolbypassrls'], 'expected user with clauses to have bypassrls clause'

with subtest("All user permissions default to false when ensureClauses is not provided"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the default for NixOS admins who are unaware of this new feature, so it'd be a breaking change to remove all clauses. I think the bool types need to be nullOr bool, to represent "leave as is" with null.
Then change the defaults to null, or perhaps add a new option so the defaults can be if config.services.postgresql.declarativeRoleClauses then false else null?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah, great point. I will try to get to this next week when I have some time. Thanks for all the direction on this.

@jtojnar
Copy link
Member

jtojnar commented Nov 25, 2022

Thinking about it a bit more, maybe it would be better to move all these ensure options into a separate module (accessible under e.g. services.postgresql.provision to follow what Grafana does). That way it would be clearer that this is something extra.

@roberth
Copy link
Member

roberth commented Nov 25, 2022

move all these ensure options into a separate module (accessible under e.g. services.postgresql.provision to follow what Grafana does).

Sounds ok to me, though I wouldn't rush it because it seems that we need to solve some declarativeness problems that need interface changes. It'd be nicer for users to do one migration than to do a rename and then a migration. Also if we rename options first, then options with the old semantics may collide with the names we want to use after making things more declarative.

That way it would be clearer that this is something extra.

Moving it to a separate module isn't trivial, because it needs to run as part of postStart, which isn't something that the postgres module exposes for extension. I suppose it could, or perhaps it's ok for other modules to add extra definitions to the ExecStartPost? Though I think not, because it's not a great idea to make assumptions about the ordering of those lines.
I'd be slightly more at ease doing those things after something like #154123, although that doesn't implement an explicit ordering relation between scripts either.
For now it's definitely easier to have the script in a single place, rather than broken up into modules.


clauseSqlStatements = attrValues (mapAttrs (n: v: if v then n else "no${n}") filteredClauses);

alterClause = role: ''$PSQL -tAc 'ALTER USER "${user.name}" WITH ${role}' '';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to set all clauses in one $PSQL invocation?
It seems that that would save some latency, especially when you have multiple users and the connection isn't local and uses TLS.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, just pushed a fix.

Copy link
Member

@roberth roberth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some nitpicks. Otherwise LGTM

nixos/tests/postgresql.nix Show resolved Hide resolved

More information on postgres roles can be found [here](https://www.postgresql.org/docs/current/role-attributes.html)
'';
default = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

null was underdocumented. Could you do the following? And maybe create a let binding for it, so you don't have to copy paste.

                    defaultText = lib.literalMD ''
                      `null`: do not set. For newly created roles, use PostgreSQL's default. For existing roles, do not touch this clause.
                    '';

@roberth
Copy link
Member

roberth commented Nov 27, 2022

Then change the defaults to null, or perhaps add a new option so the defaults can be if config.services.postgresql.declarativeRoleClauses then false else null?

I don't know. This might be a bit out of place if we don't make the other things more declarative. Can be done in a follow up PR if desired.

The PR contains many commits, which should be squashed. I doesn't look like there's an intermediate change that would warrant having more than one commit. @JonathanLorimer could you squash them?

remove trailing whitespace

switch docs to markdown

use mdDoc

remove trailing whitespace

get rid of double space

add tests and update options to use submodule

remove whitespace

remove whitespace

use mdDoc

remove whitespace

make default a no-op

make ALTER ROLE a single sql statement

document null case
@JonathanLorimer JonathanLorimer force-pushed the allow-configuration-of-roles branch from 67e3912 to 193aa6f Compare November 28, 2022 14:45
@RaitoBezarius
Copy link
Member

There might be features conflicts with #203474 ?

@roberth
Copy link
Member

roberth commented Dec 2, 2022

@ofborg test postgresql

@roberth
Copy link
Member

roberth commented Dec 3, 2022

LGTM.
Deferring to postgres maintainers @thoughtpolice @danbst @globin @marsam or @ivan for review/approval.

@JonathanLorimer
Copy link
Contributor Author

There might be features conflicts with #203474 ?

I think we could make what I have work with that PR.

@roberth
Copy link
Member

roberth commented Dec 17, 2022

LGTM. Deferring to postgres maintainers @thoughtpolice @danbst @globin @marsam or @ivan for review/approval.

2 weeks have passed, or 10 maintainer*weeks, without any response.

Still LGTM.

@roberth roberth merged commit cf150c5 into NixOS:master Dec 17, 2022
@roberth
Copy link
Member

roberth commented Dec 17, 2022

Probably the maintainers are only interested in the package. Next time I'll cc them but not ask for anything.

@Janik-Haag Janik-Haag added the 12. first-time contribution This PR is the author's first one; please be gentle! label Jun 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10 12. first-time contribution This PR is the author's first one; please be gentle!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants