Skip to content

adapter: Add privileges to objects#18700

Merged
jkosh44 merged 12 commits into
MaterializeInc:mainfrom
jkosh44:add-object-privileges
Apr 17, 2023
Merged

adapter: Add privileges to objects#18700
jkosh44 merged 12 commits into
MaterializeInc:mainfrom
jkosh44:add-object-privileges

Conversation

@jkosh44
Copy link
Copy Markdown
Contributor

@jkosh44 jkosh44 commented Apr 10, 2023

This commit adds privileges to the following objects:

  • tables
  • views
  • materialized views
  • sources
  • types
  • secrets
  • connections
  • secrets
  • clusters
  • databases
  • schemas

This commit updates the on-disk stash representation and the catalog
tables/views that present this information to users.

Currently, privileges cannot be modified, and they are not looked at
when executing statements. These features will be implemented in a
future commit.

Part of MaterializeInc/database-issues#3380

Motivation

This PR adds a known-desirable feature.

Checklist

  • This PR has adequate test coverage / QA involvement has been duly considered.
  • This PR has an associated up-to-date design doc, is a design doc (template), or is sufficiently small to not require a design.
  • This PR evolves an existing $T ⇔ Proto$T mapping (possibly in a backwards-incompatible way) and therefore is tagged with a T-proto label.
  • If this PR will require changes to cloud orchestration, there is a companion cloud PR to account for those changes that is tagged with the release-blocker label (example).
  • This PR includes the following user-facing behavior changes:
    • This release adds default privileges to database objects. The privileges cannot be modified and they do not affect database behavior. Those features will be added in a later commit.

@jkosh44 jkosh44 force-pushed the add-object-privileges branch 6 times, most recently from 44c9ca6 to e1238ad Compare April 11, 2023 17:02
@jkosh44 jkosh44 changed the title WIP: Add object privileges adapter: Add privileges to objects Apr 11, 2023
This commit adds privileges to the following objects:

  - tables
  - views
  - materialized views
  - sources
  - types
  - secrets
  - connections
  - secrets
  - clusters
  - databases
  - schemas

This commit updates the on-disk stash representation and the catalog
tables/views that present this information to users.

Currently, privileges cannot be modified, and they are not looked at
when executing statements. These features will be implemented in a
future commit.

Part of #11579
@jkosh44 jkosh44 force-pushed the add-object-privileges branch from e1238ad to 877f5a0 Compare April 11, 2023 17:27
@jkosh44 jkosh44 requested a review from def- April 11, 2023 17:38
@jkosh44 jkosh44 marked this pull request as ready for review April 11, 2023 18:02
@jkosh44 jkosh44 requested review from a team as code owners April 11, 2023 18:02
Copy link
Copy Markdown
Contributor

@def- def- left a comment

Choose a reason for hiding this comment

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

Thanks for extending slt. I'll check for platform-checks.

@def-
Copy link
Copy Markdown
Contributor

def- commented Apr 12, 2023

Is it intentional that indexes have owners, but no privileges? I guess so since you can drop indexes, but can't insert into them directly?

@def-
Copy link
Copy Markdown
Contributor

def- commented Apr 12, 2023

I also guess it's intentional that for types the privileges look like this?

materialize=> create type foo AS LIST (ELEMENT TYPE = text);
CREATE TYPE
materialize=> select * from mz_types where name = 'foo';
 id |  oid  | schema_id | name | category | owner_id |   privileges
----+-------+-----------+------+----------+----------+-----------------
 u1 | 20426 | 3         | foo  | list     | u2       | {u2=U/u2,=U/u2}

@jkosh44
Copy link
Copy Markdown
Contributor Author

jkosh44 commented Apr 12, 2023

Is it intentional that indexes have owners, but no privileges? I guess so since you can drop indexes, but can't insert into them directly?

Yes, the same goes for sinks.

@jkosh44
Copy link
Copy Markdown
Contributor Author

jkosh44 commented Apr 12, 2023

I also guess it's intentional that for types the privileges look like this?

materialize=> create type foo AS LIST (ELEMENT TYPE = text);
CREATE TYPE
materialize=> select * from mz_types where name = 'foo';
 id |  oid  | schema_id | name | category | owner_id |   privileges
----+-------+-----------+------+----------+----------+-----------------
 u1 | 20426 | 3         | foo  | list     | u2       | {u2=U/u2,=U/u2}

Yes, everyone get's Usage privileges on all types by default.

Copy link
Copy Markdown
Contributor

@madelynnblue madelynnblue left a comment

Choose a reason for hiding this comment

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

Not done reading this whole thing yet, but wanted to get these comments out.

Comment thread src/adapter/src/catalog/builtin_table_updates.rs Outdated
Comment thread src/adapter/src/rbac.rs Outdated
ObjectType::Index => AclMode::empty(),
ObjectType::Type => AclMode::USAGE,
ObjectType::Role => AclMode::empty(),
ObjectType::Cluster => AclMode::USAGE.union(AclMode::CREATE),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it worth making USAGE union CREATE some rust const or Lazy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

union is a const function, so USAGE.union(CREATE) should be completely evaluated at compile time.

@parker-timmerman does that sound right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I also just pushed a commit to switch other uses of bitor to union to take advantage of the const.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I believe in this case we'll only evaluate USAGE.union(CREATE) at compile time, if all_object_privileges is itself called in a const context, e.g. const X: AclMode = all_object_privileges(...). If it's called as part of a non-const function, then it will not. For example, in this playground we should fail to compile, if we were evaluating the const at compile time, but we're panicking at runtime, which indicates we're not.

If it's important that we're evaluating the union at compile time, then at the top of this function I'd add something like:

const USAGE_UNION_CREATE: AclMode = USAGE.union(CREATE);

which will for sure get evaluated at compile time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I would have thought that the Rust compiler has all the information it needs to rewrite the implementation of all_object_privileges to replace all occurrences of AclMode::USAGE.union(AclMode::CREATE) with it's result.

For example, we know at compile time that AclMode::USAGE.union(AclMode::CREATE) is equivalent to (1 << 8 | 1 << 9) which can be fully evaluated at compile time. So it would make sense for the compiler to make this replacement during compilation.

I tried making a dummy example and looking at the compiled ASM, and this doesn't seem to be what's happening: https://godbolt.org/z/aKjcr8Ydr

However if I add a const variable in the function and then use that, it is replaced during compile time: https://godbolt.org/z/zMb5szj1x

So I made the separate consts and used those.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yeah ideally the compiler would be able to do what you're describing, it has all the info it needs, but unfortunately const eval in Rust is still very much MVP.

Comment thread src/adapter/src/catalog/storage.rs Outdated
MzAclItem {
grantee: RoleId::Public,
grantor: MZ_SYSTEM_ROLE_ID,
acl_mode: AclMode::USAGE.bitor(AclMode::CREATE),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should PUBLIC get CREATE in this? (See schema comment below.)

Comment thread src/adapter/src/catalog/storage.rs Outdated
MzAclItem {
grantee: RoleId::Public,
grantor: MZ_SYSTEM_ROLE_ID,
acl_mode: AclMode::USAGE.bitor(AclMode::CREATE),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Postgres 15 had a notable release note to

Remove PUBLIC creation permission on the public schema

Should we follow suit? If not, it should probably have a pretty strong reason. Cockroach has been getting requests to do the same as pg15, for example.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think we definitely want to follow the latest PostgreSQL behavior for this. I've pushed an update so that the public schema created for all new databases are only created with USAGE for the public role.

I'm still thinking about the default database, schema, and cluster though. I think without CREATE privileges those aren't that useful. Additionally I think it may be nice to provide a default database and cluster that users can treat as a playground to do whatever they want in, then when they are ready they can create their own databases and clusters with stricter permissions.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@mjibson Any thoughts on this? I keep flip-flopping.

On the one hand it's better to default to higher security and let users opt into lower security by modifying the privileges. On the other hand it might be annoying if the first thing every customer has to do with a new Materialize deployment is modify the privileges on the default cluster, DB, and schema.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think we should follow the recommended usage patterns:

first ensure that no schemas have public CREATE privileges
for every user needing to create non-temporary objects, create a schema with the same name as that user

This would also require us to:

  • implement $user in schema_path, which is probably easy
  • tell customers that they have to explicitly create schemas for non-superusers or explicitly GRANT access to existing schemas

I kinda think this is the point of RBAC? Non-superusers can't create anything until explicitly GRANTd access to an existing thing, or given their own place to make things in (CREATE SCHEMA alice AUTHORIZATION alice; although I'm not sure we support that AUTHORIZATION keyword yet?).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is a good point, I've removed the public create privilege from the "materialize" database, "public" schema, and "default" cluster.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

although I'm not sure we support that AUTHORIZATION keyword yet?

We do not, and it wasn't planned as part of this initial RBAC project.

Comment thread src/adapter/src/catalog/storage.rs Outdated
MzAclItem {
grantee: RoleId::Public,
grantor: MZ_SYSTEM_ROLE_ID,
acl_mode: AclMode::USAGE.bitor(AclMode::CREATE),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same public concern maybe? Unclear.

@def-
Copy link
Copy Markdown
Contributor

def- commented Apr 13, 2023

Do we also want \dp to work to check privileges?

materialize=> \dp
ERROR:  column "c.relacl" does not exist

@def-
Copy link
Copy Markdown
Contributor

def- commented Apr 13, 2023

Is it intentional that indexes have owners, but no privileges? I guess so since you can drop indexes, but can't insert into them directly?

Yes, the same goes for sinks.

I'm not seeing a privileges column at all for sinks:

materialize=> select * from mz_sinks;
 id | oid | schema_id | name | type | connection_id | size | envelope_type | cluster_id | owner_id
----+-----+-----------+------+------+---------------+------+---------------+------------+----------
(0 rows)

@jkosh44
Copy link
Copy Markdown
Contributor Author

jkosh44 commented Apr 13, 2023

Do we also want \dp to work to check privileges?

materialize=> \dp
ERROR:  column "c.relacl" does not exist

Eventually it would be nice if that worked, but it's not expected to work after this PR.

@jkosh44
Copy link
Copy Markdown
Contributor Author

jkosh44 commented Apr 13, 2023

Is it intentional that indexes have owners, but no privileges? I guess so since you can drop indexes, but can't insert into them directly?

Yes, the same goes for sinks.

I'm not seeing a privileges column at all for sinks:

materialize=> select * from mz_sinks;
 id | oid | schema_id | name | type | connection_id | size | envelope_type | cluster_id | owner_id
----+-----+-----------+------+------+---------------+------+---------------+------------+----------
(0 rows)

I decided not to add it to mz_sinks or mz_index since it would always be empty. Do you think we should have it there?

@def-
Copy link
Copy Markdown
Contributor

def- commented Apr 13, 2023

Ok, fine for me.

Copy link
Copy Markdown
Contributor

@tr0njavolta tr0njavolta left a comment

Choose a reason for hiding this comment

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

Docs changes 👍

…-object-privileges

# Conflicts:
#	src/adapter/src/catalog.rs
#	src/adapter/src/catalog/storage.rs
@jkosh44 jkosh44 enabled auto-merge (squash) April 17, 2023 14:24
@jkosh44 jkosh44 merged commit eafcb25 into MaterializeInc:main Apr 17, 2023
@jkosh44 jkosh44 deleted the add-object-privileges branch April 17, 2023 15:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants