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

Restrict profile_list options depending on the user #589

Open
1 task
choldgraf opened this issue Mar 14, 2022 · 13 comments
Open
1 task

Restrict profile_list options depending on the user #589

choldgraf opened this issue Mar 14, 2022 · 13 comments

Comments

@choldgraf
Copy link
Member

choldgraf commented Mar 14, 2022

Context

Our profile_list config lets us define a subset of "configuration over-rides" that change the behavior of the user environment with launch.

For hubs that have different groups of users, they may want to allow only a subset of user profiles to be accessible to certain groups of users. For example:

  • all-users: have access to a basic 2 GB RAM environment with a base image
  • power-users: are those trusted not to accidentally generate high costs, and have access to a 32GB RAM environment with a machine learning image

Proposed change

We should make it possible for a hub's profile_list to specify groups of users that have access to different subsets of profiles. A user's membership in a group would determine the profiles that are available to choose from when they hit the profile_list selection page.

Suggest a solution

I am not sure on this, but perhaps the upcoming RBAC functionality in JupyterHub could be used to define the user groups, and this could be mapped on to a given subset of profiles?

For example, we could add a user_groups flag to the profile_list config, e.g.:

c.KubeSpawner.profile_list = [
    {
        'display_name': 'Training Env - Python',
        'slug': 'training-python',
        'user_groups': ['all-users'],
        'default': True,
        'kubespawner_override': {
            'image': 'training/python:label',
            'cpu_limit': 1,
            'mem_limit': '512M',
        }
    }, {
        'display_name': 'Training Env - Datascience',
        'slug': 'training-datascience',
        'user_groups': ['power-users', 'admins'],
        'kubespawner_override': {
            'image': 'training/datascience:label',
            'cpu_limit': 4,
            'mem_limit': '8G',
        }
    ...

Updated plan

We decided it would be best not to implement a technical solution to this, for fear of making the configuration etc too complex to maintain and use. Instead, we'll add documentation to @consideRatio's post for how to do this with some custom python code:

@consideRatio
Copy link
Member

This is a very common feature request that has come in many variations so I'm hesitant to implement logic about it tailored for a specific variation.

There is a general strategy that can be used, no matter if it should be based on groups or something else that I wrote about in https://discourse.jupyter.org/t/tailoring-spawn-options-and-server-configuration-to-certain-users/8449.

Looking through issues i find these that seem related:

@choldgraf
Copy link
Member Author

choldgraf commented Mar 14, 2022

Ah very cool! I was sure this had been discussed elsewhere but didn't find an obvious canonical place for it.

So if I understand correctly, the "Problem 1" in your post is what we're talking about here. A hub administrator could implement the logic for this as-necessary, based on individual users or groups. But, there likely is not a need for new development, since this is already technically possible. Is that right?

And similarly, for issues like #307, your suggestion there would be "create function that generates the profile_list for users on your own, and implement the 'matrix' behavior you need". Right?

As this is a very common request, I think it could be valuable to document the solution you describe as well as a little example in the KubeSpawner docs or the Z2JH docs. Alternatively, we could just have a more discoverable section like Control what user profiles a user sees and link to your post. Does that make sense to you?

@rigzba21
Copy link

@consideRatio thank you for the link to the two strategies! I took a different approach (before reading your post) by registering a custom Authenticator post_auth_hook that sets the profile_list based on information in the user's auth_state such as group assignment, roles/scopes etc that come from an external auth provider.

Is there a downside to using a post_auth_hook to set the profile_list versus using either a custom_options_form or pre_spawn_hook as you recommend? I'm just wondering if I need to reevaluate my approach or I'm missing something.

Thanks!

@consideRatio
Copy link
Member

@choldgraf I'm overall thinking that we should point to my discourse post rather from multiple locations if needed in multiple projects documentation (z2jh, kubespawner, elsewhere). I was thinking if I should write it here on in z2jh, but opted to make it on the discourse forum knowing it was relevant for this and z2jh.

I'm overall afraid seeing another layer of complexity be added on top of profile_list, thinking it would become an option that would be fragile, complicated, and yet still too limited to meet the needs of users. So, I'm overall positive towards suggesting users embrace the complexity but power of tailoring their spawn options with custom logic they control - as documented with the forum post.

@consideRatio
Copy link
Member

@rigzba21 regarding:

I took a different approach (before reading your post) by registering a custom Authenticator post_auth_hook that sets the profile_list based on information in the user's auth_state such as group assignment, roles/scopes etc that come from an external auth provider.

Hmmm, but how did you set profile_list? It is a configuration on a KubeSpawner instance. If you would set c.KubeSpawner.profile_list, you set the default for the KubeSpawner instances created as part of about to start a server, but you don't set it for the specific user. Also, a user can have multiple servers with a opt-in JupyterHub feature called named servers, making it even more complicated to do at the time of a user being authentication.

Did you set c.KubeSpawner.profile_list from the post_auth_hook or did you manage to set the to-be-started KubeSpawner instance specifically somehow, even though the user had just logged in?

@choldgraf
Copy link
Member Author

choldgraf commented Apr 22, 2022

That makes sense to me @consideRatio - I think the main thing is that there are "breadcrumbs" in the main documentation that point to your discourse post, so that when people search for keywords in the docs, they might still discover your post there, does that make sense?

For example, similar to: https://mybinder.readthedocs.io/en/latest/howto/speed.html

@consideRatio
Copy link
Member

consideRatio commented Apr 22, 2022

@choldgraf 💯 !

Action point to resolve issue

Like done in this mybinder documentation, link out to the forum post on how to configure spawn options based on custom logic from somewhere in this repo's docs.

@choldgraf
Copy link
Member Author

@consideRatio I've updated the top comment w/ this new plan

@manics
Copy link
Member

manics commented Apr 23, 2022

If we did want to add this feature (or other major features) to profiles in future I think we'd be better off making the changes in https://github.com/jupyterhub/wrapspawner so all JupyterHub spawners benefit, not just Z2JH.

@rigzba21
Copy link

Did you set c.KubeSpawner.profile_list from the post_auth_hook or did you manage to set the to-be-started KubeSpawner instance specifically somehow, even though the user had just logged in?

@consideRatio it's been a while since I last looked at this, but to answer your question, yes, I remember setting c.KubeSpawner.profile_list from within a post_auth_hook and it seemed to work well enough for me at the time 🤷.

@benjimin
Copy link

benjimin commented Dec 20, 2022

I think it would be good to implement some logic concerning this (e.g. let profiles each optionally specify a list of user groups, and only offer those profiles to users who belong to one of those groups).

The problem with recommending extensive custom code (to be inserted via helm) is that it is very difficult to test and debug. For example, I'm currently attempting to debug an issue whereby starting a server with a specific profile (which uses a customised image, and is supposed to be restricted to a subset of users via aws-cognito) seems to poison the spawner such that immediately subsequent attempts to spawn the default server will unexpectedly also use the same customised image. The docs are simply referring me back to this snippet of code hosted at discourse, meaning there is also no version control and limited scope to propose fixes to the code or documentation or test suite, for this common use-case. (It also doesn't feel like best practice for security to inject arbitrary python via helm & k8s resources?)

@yuvipanda
Copy link
Collaborator

There's custom code in https://github.com/2i2c-org/infrastructure/blob/5303ff3f5d9f3f9a33f79b44330c4d156fdfdc11/helm-charts/basehub/values.yaml#L703 that implements this specifically for GitHub.

I think long term, finding some way to do this with respect to JupyterHub groups is probably the way to go, coupled with some way to sync jupyterhub groups with external group membership.

@yuvipanda
Copy link
Collaborator

The custom code now supports JupyterHub groups: https://github.com/2i2c-org/infrastructure/blob/bc7692dfc05fe926c4a0b32261f203a7b2a430df/helm-charts/basehub/values.yaml#L1381.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants