diff --git a/docs/requirements.txt b/docs/requirements.txt index 2d9da795..bba34b26 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -4,6 +4,7 @@ alabaster_jupyterhub # Temporary fix of #3021. Revert back to released autodoc-traits when # 0.1.0 released. https://github.com/jupyterhub/autodoc-traits/archive/75885ee24636efbfebfceed1043459715049cd84.zip +myst_parser pydata-sphinx-theme pytablewriter>=0.56 recommonmark>=0.6 diff --git a/docs/source/changelog.md b/docs/source/changelog.md index ffa2c029..66330e11 100644 --- a/docs/source/changelog.md +++ b/docs/source/changelog.md @@ -423,12 +423,11 @@ whether it was through discussion, testing, documentation, or development. allowing the Authenticator to *require* that authentication data is fresh immediately before the user's server is launched. -```eval_rst -.. seealso:: +```{seealso} - - :meth:`.Authenticator.refresh_user` - - :meth:`.Spawner.create_certs` - - :meth:`.Spawner.move_certs` + - {meth}`.Authenticator.refresh_user` + - {meth}`.Spawner.create_certs` + - {meth}`.Spawner.move_certs` ``` #### New features diff --git a/docs/source/conf.py b/docs/source/conf.py index 317420d7..e403e939 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -19,7 +19,8 @@ extensions = [ 'autodoc_traits', 'sphinx_copybutton', 'sphinx-jsonschema', - 'recommonmark', + #'recommonmark', + 'myst_parser', ] # The master toctree document. @@ -111,9 +112,9 @@ class HelpAllDirective(SphinxDirective): def setup(app): - app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) + # app.add_config_value('recommonmark_config', {'enable_eval_rst': True}, True) app.add_css_file('custom.css') - app.add_transform(AutoStructify) + # app.add_transform(AutoStructify) app.add_directive('jupyterhub-generate-config', ConfigDirective) app.add_directive('jupyterhub-help-all', HelpAllDirective) diff --git a/docs/source/getting-started/faq.md b/docs/source/getting-started/faq.md index ae912847..f18227e9 100644 --- a/docs/source/getting-started/faq.md +++ b/docs/source/getting-started/faq.md @@ -1,7 +1,7 @@ # Frequently asked questions -### How do I share links to notebooks? +## How do I share links to notebooks? In short, where you see `/user/name/notebooks/foo.ipynb` use `/hub/user-redirect/notebooks/foo.ipynb` (replace `/user/name` with `/hub/user-redirect`). diff --git a/docs/source/index.rst b/docs/source/index.rst index 8d51a6bc..dfcc3e68 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -108,6 +108,14 @@ API Reference api/index +RBAC Reference +-------------- + +.. toctree:: + :maxdepth: 2 + + rbac + Contributing ------------ diff --git a/docs/source/rbac.md b/docs/source/rbac.md new file mode 100644 index 00000000..857fca1c --- /dev/null +++ b/docs/source/rbac.md @@ -0,0 +1,51 @@ +# JupyterHub RBAC + +Role Based Access Control (RBAC) in JupyterHub serves to provide finer grained access to perform actions by users or services. + +## Motivation +The JupyterHub API requires authentication before allowing changes to the administration system. For instance, currently the default behaviour is that creating or deleting users requires *admin rights*. This ensures that an arbitrary user, or even an unauthenticated third party, cannot disrupt the status of the Hub. + +This system is functional, but lacks flexibility. If your Hub serves a number of users in different departments, you might want to delegate permissions to other users or automate certain processes. With this framework, appointing a 'group-only admin', or a bot that culls idle servers, requires granting full rights to all actions. This can be error-prone and violates the [principle of least privilige](https://en.wikipedia.org/wiki/Principle_of_least_privilege). + +To remedy situations like this, we implement an RBAC system. By equipping users, groups and services with *roles* that supply them with a collection of permissions (*scopes*), administrators are able to fine-tune which parties are able to access which resources. + +### Available scopes + +[](./reference/rest-api.rst) documentation details all available scopes and which of these are required for what particular API request. + +The roles can then be defined as follows: +```python +c.JupyterHub.load_groups = { + 'class-A': ['johan', 'student1', 'student2'], + 'class-B': ['johan', 'student3', 'student4'] +} +c.JupyterHub.load_roles = [ + { +   'name': 'class-A-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-A'], +   'groups': ['class-A'] + }, + { +   'name': 'class-B-student', +   'description': 'Grants access to information about the group', +   'scopes': ['read:groups!group=class-B'], +   'groups': ['class-B'] + }, + { +   'name': 'teacher', +   'description': 'Allows for accessing information about teacher group members and starting/stopping their servers', +   'scopes': ['read:users!group=class-A', 'read:users!group=class-B', 'users:servers!group=class-A', 'users:servers!group=class-B'], +   'users': ['johan'] + } +] +``` +In the above example, `johan` has privileges inherited from class-A and class-B roles and the `teacher` role on top of those. Note the filters (`!group=`) limiting the priviliges only to the class-A and class-B group members. + +## Technical Implementation + +```{admonition} Here's my title +:class: warning + +Here's my admonition content +```