adapter: Add privileges to objects#18700
Conversation
44c9ca6 to
e1238ad
Compare
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
e1238ad to
877f5a0
Compare
def-
left a comment
There was a problem hiding this comment.
Thanks for extending slt. I'll check for platform-checks.
|
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? |
|
I also guess it's intentional that for types the privileges look like this? |
Yes, the same goes for sinks. |
Yes, everyone get's Usage privileges on all types by default. |
madelynnblue
left a comment
There was a problem hiding this comment.
Not done reading this whole thing yet, but wanted to get these comments out.
| ObjectType::Index => AclMode::empty(), | ||
| ObjectType::Type => AclMode::USAGE, | ||
| ObjectType::Role => AclMode::empty(), | ||
| ObjectType::Cluster => AclMode::USAGE.union(AclMode::CREATE), |
There was a problem hiding this comment.
Is it worth making USAGE union CREATE some rust const or Lazy?
There was a problem hiding this comment.
union is a const function, so USAGE.union(CREATE) should be completely evaluated at compile time.
@parker-timmerman does that sound right?
There was a problem hiding this comment.
I also just pushed a commit to switch other uses of bitor to union to take advantage of the const.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
| MzAclItem { | ||
| grantee: RoleId::Public, | ||
| grantor: MZ_SYSTEM_ROLE_ID, | ||
| acl_mode: AclMode::USAGE.bitor(AclMode::CREATE), |
There was a problem hiding this comment.
Should PUBLIC get CREATE in this? (See schema comment below.)
| MzAclItem { | ||
| grantee: RoleId::Public, | ||
| grantor: MZ_SYSTEM_ROLE_ID, | ||
| acl_mode: AclMode::USAGE.bitor(AclMode::CREATE), |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
@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.
There was a problem hiding this comment.
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
$userin 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?).
There was a problem hiding this comment.
This is a good point, I've removed the public create privilege from the "materialize" database, "public" schema, and "default" cluster.
There was a problem hiding this comment.
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.
| MzAclItem { | ||
| grantee: RoleId::Public, | ||
| grantor: MZ_SYSTEM_ROLE_ID, | ||
| acl_mode: AclMode::USAGE.bitor(AclMode::CREATE), |
There was a problem hiding this comment.
Same public concern maybe? Unclear.
|
Do we also want \dp to work to check privileges? |
I'm not seeing a privileges column at all for sinks: |
Eventually it would be nice if that worked, but it's not expected to work after this PR. |
I decided not to add it to |
|
Ok, fine for me. |
…-object-privileges # Conflicts: # src/adapter/src/catalog.rs # src/adapter/src/catalog/storage.rs
This commit adds privileges to the following objects:
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
$T ⇔ Proto$Tmapping (possibly in a backwards-incompatible way) and therefore is tagged with aT-protolabel.