-
Notifications
You must be signed in to change notification settings - Fork 42
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
add built-in users to the database #486
Conversation
/// Converts a Diesel pool error to an external error for a case where we do not | ||
/// expect the query to fail and the error cannot be easily summarized for an | ||
/// end user | ||
pub fn public_error_from_diesel_pool_shouldnt_fail( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@smklein FYI I refactored the functions here a bit so I could handle things a bit differently during Nexus startup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, this eliminates the need for specifying the resource type. I know I'm late here, but I think there are a handful of spots that could use this for internal operations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think you're right!
common/src/sql/dbinit.sql
Outdated
time_modified | ||
) VALUES ( | ||
/* NOTE: this uuid and name are duplicated in nexus::authn. */ | ||
'001de000-05e4-0000-0000-000000000001', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this UUID isn't strictly valid, though I don't think it's likely to bite us unless a UUID lib is trying to interpret the value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, all of the built-in users have made-up uuids described in the comment in authn.rs. I believe they all parse with uuid::Uuid::from_str
, though. When you say it's not strictly valid, did you mean that it's not consistent with any of the v1-v4 specs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, and it's in the legacy variant 0 (NCS) space, which has its own subfields
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, that's true. How about I change all the built-in user uuids to v4 variant 1 (but otherwise keep their structure the same)? Another option would be to stick with variant 0 (which appears obsolete) or maybe variant 2 (which appears irrelevant to us), but I don't think there's any particular reason to do that. When I wrote up this scheme, I was definitely thinking of them as v4 ones.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 539e538.
nexus/src/db/datastore.rs
Outdated
name: &Name, | ||
) -> LookupResult<UserBuiltin> { | ||
use db::schema::user_builtin::dsl; | ||
opctx.authorize(authz::Action::ListChildren, authz::FLEET)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be Action::Read?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so? Check out
omicron/nexus/src/authz/omicron.polar
Lines 41 to 80 in 038dbd0
# | |
# Permissions and predefined roles | |
# | |
# For now, we define the following permissions for most resources in the system: | |
# | |
# - "create_child": required to create child resources. | |
# | |
# - "list_children": required to list children (of all types) of a resources | |
# | |
# - "modify": required to modify or delete a resource or any of its children | |
# | |
# - "read": required to read a resource | |
# | |
# We define the following predefined roles for only a few high-level resources: | |
# | |
# - "admin": has all permissions on the resource | |
# | |
# - "collaborator": has "list_children" and "create_$child" for all children. | |
# They'll inherit the "admin" role for any resources that they create. | |
# | |
# - "viewer": has "read" and "list_children" on a resource | |
# | |
# Below the project level, permissions are granted at the Project level. For | |
# example, for someone to be able to create, modify, or delete any Instances, | |
# they must be granted project.collaborator, which means they can create, | |
# modify, or delete _all_ resources in the Project. | |
# | |
# The complete set of predefined roles: | |
# | |
# - fleet.admin (superuser for the whole system) | |
# - fleet.collaborator (can create and own orgs) | |
# - organization.admin (complete control over an organization) | |
# - organization.collaborator (can create, modify, and delete projects) | |
# - project.admin (complete control over a project) | |
# - project.collaborator (can create, modify, and delete all resources within | |
# the project, but cannot modify or delete the project | |
# itself) | |
# - project.viewer (can see everything in the project, but cannot modify | |
# anything) | |
# |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From these descriptions it still sounds like Read
to me? Unless we consider resolving a single object by name to be a listing operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see your point.
What resource would the "read" action be applied to? I assumed at first that you meant that we'd create a new Polar resource for UserBuiltin as a child of Fleet. That's totally reasonable. I elected not do that only because it's a bunch more plumbing and it wasn't clear to me that it was useful to be able to assign permissions on builtin users. Admittedly, it's kind of implicit to piggy-back on the fleet-level list-children permission.
The policy currently doesn't say anything about most system-wide resources, including built-in users and all the hardware resources that we'll eventually have. Until we have reason to think that people are going to want to split these up, I'd propose treating these similar to ProjectResource
today: we could create one Polar type for SystemResource
with no roles of its own, but permissions granted based on one's roles on the Fleet. It's a little hollow because unlike ProjectResource
, there's only one possible parent (so there would be no state in a SystemResource
struct). But it might be more explicit. What do you think?
Another option is to keep the resource in this check as Fleet
, treating the users and other system-wide information as part of the Fleet itself. I think that's not great because I can imagine even pretty unprivileged users getting "read" permission on the Fleet to be able to view system-wide configuration or something, but that doesn't mean they should be able to see all system-wide resources.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the middle ground of creating one SystemResource
for all these things to share. I agree with Tess than using a list children permission to read a single thing is weird.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 9f562e9 -- let me know what you think.
&*authn::USER_TEST_PRIVILEGED, | ||
&*authn::USER_TEST_UNPRIVILEGED, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to conditionally include these?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're right that at some point, we'll want to leave them out of some configurations. But right now, USER_TEST_PRIVILEGED is necessary to do anything useful with oxapi_demo or the console, even if you're not in #[cfg(test)]
. Once we add authz to the rest of the endpoints, you really won't be able to do anything useful with Nexus without these. We will need to revisit this as part of initial rack setup, I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On console we use a DB seeding script for local dev and for the QA instance deployed to GCP. Maybe these users could eventually move into something like that rather than a #[cfg(test)]
. Or both, actually. #[cfg(test)]
for the tests and a script for local dev.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might make sense to add a comment/create an appropriately tagged issue to track that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@teisenbe Sure thing. I had a TODO-security for this (which I'm hoping we'll audit before we ship...but we don't track that either), but it got moved around and no longer really covers it. Moved and clarified in af85c83.
@david-crespo Longer-term, another option would be to officially support local users and add "create" endpoints for them. Maybe these would be better modeled as service accounts? Then we'd just have the test suite create the ones it wants. For developers playing around, they could create one with oxapi_demo. But...with what creds would they create one? Anyway I'd definitely like to move that discussion to a follow-on PR.
Thanks for taking a look @teisenbe! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks great!
"privileged" => Some(TEST_USER_UUID_PRIVILEGED.parse().unwrap()), | ||
"unprivileged" => Some(TEST_USER_UUID_UNPRIVILEGED.parse().unwrap()), | ||
"privileged" => Some(USER_TEST_PRIVILEGED.id), | ||
"unprivileged" => Some(USER_TEST_UNPRIVILEGED.id), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was easy
See #419 for background. This change takes the predefined users that we use in the test suite and elsewhere and moves them into the database. This doesn't change much practically but it makes the built-in users look more like we expect things to look once we've integrated with some identity provider.