From 1801319148f25a4f79b7d4f373540b43a955fd9c Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Fri, 24 Jan 2025 13:17:26 -0300 Subject: [PATCH 1/6] rm roles and permissions section from this page --- docs/docs/how-tos/configure-keycloak-howto.md | 51 ------------------- 1 file changed, 51 deletions(-) diff --git a/docs/docs/how-tos/configure-keycloak-howto.md b/docs/docs/how-tos/configure-keycloak-howto.md index f949894f..47e93947 100644 --- a/docs/docs/how-tos/configure-keycloak-howto.md +++ b/docs/docs/how-tos/configure-keycloak-howto.md @@ -132,57 +132,6 @@ Your new user can now log in to Nebari, visit your provided Nebari domain URI wh ![Nebari - Log in to Keycloak page](/img/how-tos/nebari_login_screen.png) -## In-depth look at Roles and Groups - -Groups represent a collection of users that perform similar actions and therefore require similar permissions. By default, Nebari is deployed with the following groups: `admin`, `developer`, and `analyst` (in roughly descending order of permissions and scope). - -:::info -Users in a particular group will also get access to that groups shared folder. So if `user A` belongs to the `developer`, they will also have access to the `~/shared/developer` folder. This also applies to new groups that you create. -::: - -Roles on the other hand represent the type or category of user. This includes access and permissions that this category of user will need to perform their regular job duties. The differences between `groups` and `roles` are subtle. Particular roles (one or many), like `conda_store_admin`, are associated with a particular group, such as `admin` and any user in this group will then assume the role of `conda_store_admin`. - -:::info -These roles can be stacked. This means that if a user is in one group with role `conda_store_admin` and another group with role `conda_store_viewer`, this user ultimately has the role `conda_store_admin`. -::: - -| Group | Access to Nebari Resources | Roles | Permissions Description | -| ------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `analyst` | | | | -| `developer` | | | | -| `admin` | | | | -| `superadmin` | | | | - -:::info -Check [Conda-store authorization model](https://conda-store.readthedocs.io/en/latest/contributing.html#authorization-model) for more details on conda-store authorization. -::: - -:::caution -The role `jupyterhub_admin` gives users elevated permissions to JupyterHub and should be applied judiciously. As mentioned in the table above, a JupyterHub admin is able to impersonate other users and view the contents of their home folder. For more details, read through the [JupyterHub documentation](https://z2jh.jupyter.org/en/stable/jupyterhub/customizing/user-management.html#admin-users). -::: - -To create new groups or modify (or delete) existing groups, log in as `root` and click **Groups** on the left-hand side. - -As an example, we create a new group named `conda-store-manager`. This group will have administrator access to the [Conda-Store service]. - -1. Click **New** in the upper-right hand corner under **Groups**. - -![Keycloak groups tab screenshot - user groups view](/img/how-tos/keycloak_groups.png) - -- Then, give the new group an appropriate name. - -![Keycloak add group form - name field set to conda-store-manager](/img/how-tos/keycloak_new_group1.png) - -2. Under **Role Mapping**, add the appropriate **Client Roles** as needed; there should be no need to update the **Realm Roles**. - -![Keycloak group conda-store-manager form - role mappings tab focused with expanded client roles dropdown](/img/how-tos/keycloak_new_group2.png) - -In this example, the new group only has one mapped role, `conda_store_admin`; however, it's possible to attach multiple **Client Roles** to a single group. - -![Keycloak group conda-store-manager form - role mappings tab focused ](/img/how-tos/keycloak_new_group3.png) - -Once complete, return to the **Users** section in the dashboard and add the relevant users to this newly created group. - [keycloak-login]: /docs/tutorials/login-keycloak From bdc44f59b81791496e5fb2b86e356b2e7f192702 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Fri, 24 Jan 2025 13:17:58 -0300 Subject: [PATCH 2/6] include fine-grained section and add missing pieces --- docs/docs/how-tos/fine-grained-permissions.md | 92 ++++++++++++++++--- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/docs/docs/how-tos/fine-grained-permissions.md b/docs/docs/how-tos/fine-grained-permissions.md index f682acb2..ca287f01 100644 --- a/docs/docs/how-tos/fine-grained-permissions.md +++ b/docs/docs/how-tos/fine-grained-permissions.md @@ -1,15 +1,25 @@ # Fine Grained Permissions via Keycloak -Nebari provides its users (particularly admins) a way to manage roles and permissions to -various services like `jupyterhub` and `conda-store` via Keycloak. The idea is to be able to manage -roles and permissions from a central place, in this case Keycloak. An admin or anyone who has -permissions to create a role in Keycloak will create role(s) with assigned scopes (permissions) -to it and attach it to user(s) or group(s). +Nebari uses Keycloak to centrally manage roles, permissions, and scopes for various +services like `jupyterhub` and `conda-store`. By default, Nebari provides a set of +predefined clients and default roles that cover common needs—such as basic view/read +permissions or full admin control, a full list of which can be found in the [] section. -These roles are created and attached from keycloak's interface and scoped for a particular -client (i.e. a Nebari service such as `jupyterhub` or `conda-store`). This means the roles for a -particular service (say `jupyterhub`) should be created within the Keycloak client named -`jupyterhub`. +However, certain environments require more specialized or granular access controls. In these cases, administrators (or any user with appropriate privileges) can create custom roles and scopes directly in Keycloak. This allows you to tailor the permission model to fit your precise security and governance requirements—all while still benefiting from the ready-to-use defaults Nebari provides. + +## Managing Roles and Permissions +Overview +- *Roles*: Define a set of permissions (or scopes) for a particular client (service). +- *Groups*: Aggregate users who share similar permissions. +- *Scopes*: The individual permissions (e.g., “read:users:name” for reading user names) that can be attached to a role. + +By creating custom roles with specific scopes, and assigning them to groups or users, +you can fine-tune exactly who can do what in your Nebari environment. More details on how to create roles and scopes can be found in the [Creating a Role](#creating-a-role) section. + +## Default Clients and permissions in Nebari + +Nebari comes with several custom Keycloak clients in a fresh deployment. These map to +key Nebari services and integrations: By default, Nebari comes with several custom clients included in a fresh deployment. These clients facilitate various services and integrations within the Nebari ecosystem. @@ -31,7 +41,60 @@ Keycloak admin console, as illustrated in the image below. This can be accessed at `/auth/admin/master/console/#/realms/nebari/clients` -## Creating a Role +Groups represent a collection of users that perform similar actions and therefore require similar permissions. By default, Nebari is deployed with the following groups: `admin`, `developer`, and `analyst` (in roughly descending order of permissions and scope). + +:::info +Users in a particular group will also get access to that groups shared folder. So if `user A` belongs to the `developer`, they will also have access to the `~/shared/developer` folder. This also applies to new groups that you create. +::: + +Roles on the other hand represent the type or category of user. This includes access and permissions that this category of user will need to perform their regular job duties. The differences between `groups` and `roles` are subtle. Particular roles (one or many), like `conda_store_admin`, are associated with a particular group, such as `admin` and any user in this group will then assume the role of `conda_store_admin`. + +:::info +These roles can be stacked. This means that if a user is in one group with role `conda_store_admin` and another group with role `conda_store_viewer`, this user ultimately has the role `conda_store_admin`. +::: + +## In-depth look at Roles and Groups + +Below is a table illustrating each default group, the resources they can access, and the roles they inherit. The table also includes a brief description of the permissions granted to each group. + +| Group | Access to Nebari Resources | Roles | Permissions Description | +| ------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `analyst` |
  • Conda-Store
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_developer`
  • `jupyterhub_developer`
  • `argo_viewer`
  • `grafana_viewer`
|
  • Default user permissions
  • Access to start a server instance and generate JupyterHub access token.
  • Read/write access to shared `analyst` folder group mount
  • Read access to `analyst` and write access to personal conda-store namespace
  • Read access to Argo-Workflows and Jupyter-Scheduler
  • Inherent Grafana permissions from [Grafana viewer scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles)
| +| `developer` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana Developer
|
  • `conda_store_developer`
  • `dask_developer`
  • `jupyterhub_developer`
  • `argo_developer`
  • `grafana_developer`
|
  • All of the above access, plus...
  • Read access `developer` conda-store namespace
  • Access to create Dask clusters.
  • Read/write access to shared `developer` folder group mount
  • Read/create access to Argo-Workflows and Jupyter-Scheduler
  • Inherent Grafana permissions from [Grafana editor scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles)
| +| `admin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_admin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `grafana_admin`
|
  • All of the above access, plus...
  • Read/write access to all conda-store available namespaces/environments.
  • Access to Jupyterhub Admin page and can access JupyterLab users spaces
  • Access to Keycloak and can add remove users and groups
  • Inherent Grafana permissions from [Grafana administrator scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles)
| +| `superadmin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_superadmin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `realm_admin` (Keycloak)
  • `grafana_admin`
|
  • All of the above access, plus...
  • Delete (build and environment) access on conda-store
  • Full access to Keycloak (realm) (same as `root`)
| + +:::info +Check [Conda-store authorization model](https://conda-store.readthedocs.io/en/latest/contributing.html#authorization-model) for more details on conda-store authorization. +::: + +:::caution +The role `jupyterhub_admin` gives users elevated permissions to JupyterHub and should be applied judiciously. As mentioned in the table above, a JupyterHub admin is able to impersonate other users and view the contents of their home folder. For more details, read through the [JupyterHub documentation](https://z2jh.jupyter.org/en/stable/jupyterhub/customizing/user-management.html#admin-users). +::: + +To create new groups or modify (or delete) existing groups, log in as `root` and click **Groups** on the left-hand side. + +As an example, we create a new group named `conda-store-manager`. This group will have administrator access to the [Conda-Store service]. + +1. Click **New** in the upper-right hand corner under **Groups**. + +![Keycloak groups tab screenshot - user groups view](/img/how-tos/keycloak_groups.png) + +- Then, give the new group an appropriate name. + +![Keycloak add group form - name field set to conda-store-manager](/img/how-tos/keycloak_new_group1.png) + +2. Under **Role Mapping**, add the appropriate **Client Roles** as needed; there should be no need to update the **Realm Roles**. + +![Keycloak group conda-store-manager form - role mappings tab focused with expanded client roles dropdown](/img/how-tos/keycloak_new_group2.png) + +In this example, the new group only has one mapped role, `conda_store_admin`; however, it's possible to attach multiple **Client Roles** to a single group. + +![Keycloak group conda-store-manager form - role mappings tab focused ](/img/how-tos/keycloak_new_group3.png) + +Once complete, return to the **Users** section in the dashboard and add the relevant users to this newly created group. + +### Creating a Role The process for creating a role is similar, irrespective of the service. To create a role for a service @@ -49,7 +112,7 @@ service ![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_add_role_attributes.png) -## Adding Role to Group(s) / User(s) +### Adding Role to Group(s) / User(s) Creating a role in Keycloak has no effect on any user or group's permissions. To grant a set of permissions to a user or group, we need to _attach_ the role to the user or group. To add a role to a user: @@ -83,6 +146,13 @@ for the roles to take in effect. For example let's say we add a set of roles for conda-store again (similarly for `jupyterhub` as well), after the roles are granted/revoked. ::: +## Components and Scopes + +When specifying fine-grained permissions in Keycloak, we use the `components` and +`scopes` attributes. These attributes are used to define the permissions that a role +grants to a user or group. This model follows the RBAC (Role-Based Access Control) model +and is based upong the same structure utilized by [Jupyterhub](https://jupyterhub.readthedocs.io/en/latest/rbac/index.html). + ### Components Attribute We have seen in the above example the `component` attribute while creating a role. The value of this parameter From d14f4b05d5e53d3ab92880ed77138fcd121df5f7 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Fri, 24 Jan 2025 15:13:34 -0300 Subject: [PATCH 3/6] add markdown table component --- ...ssions.md => fine-grained-permissions.mdx} | 111 +++++++++++++++++- docs/package.json | 3 +- docs/src/components/MarkdownTable.ts | 37 ++++++ 3 files changed, 144 insertions(+), 7 deletions(-) rename docs/docs/how-tos/{fine-grained-permissions.md => fine-grained-permissions.mdx} (56%) create mode 100644 docs/src/components/MarkdownTable.ts diff --git a/docs/docs/how-tos/fine-grained-permissions.md b/docs/docs/how-tos/fine-grained-permissions.mdx similarity index 56% rename from docs/docs/how-tos/fine-grained-permissions.md rename to docs/docs/how-tos/fine-grained-permissions.mdx index ca287f01..d717479d 100644 --- a/docs/docs/how-tos/fine-grained-permissions.md +++ b/docs/docs/how-tos/fine-grained-permissions.mdx @@ -8,6 +8,7 @@ permissions or full admin control, a full list of which can be found in the [] s However, certain environments require more specialized or granular access controls. In these cases, administrators (or any user with appropriate privileges) can create custom roles and scopes directly in Keycloak. This allows you to tailor the permission model to fit your precise security and governance requirements—all while still benefiting from the ready-to-use defaults Nebari provides. ## Managing Roles and Permissions + Overview - *Roles*: Define a set of permissions (or scopes) for a particular client (service). - *Groups*: Aggregate users who share similar permissions. @@ -57,12 +58,110 @@ These roles can be stacked. This means that if a user is in one group with role Below is a table illustrating each default group, the resources they can access, and the roles they inherit. The table also includes a brief description of the permissions granted to each group. -| Group | Access to Nebari Resources | Roles | Permissions Description | -| ------------ | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `analyst` |
  • Conda-Store
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_developer`
  • `jupyterhub_developer`
  • `argo_viewer`
  • `grafana_viewer`
|
  • Default user permissions
  • Access to start a server instance and generate JupyterHub access token.
  • Read/write access to shared `analyst` folder group mount
  • Read access to `analyst` and write access to personal conda-store namespace
  • Read access to Argo-Workflows and Jupyter-Scheduler
  • Inherent Grafana permissions from [Grafana viewer scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles)
| -| `developer` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana Developer
|
  • `conda_store_developer`
  • `dask_developer`
  • `jupyterhub_developer`
  • `argo_developer`
  • `grafana_developer`
|
  • All of the above access, plus...
  • Read access `developer` conda-store namespace
  • Access to create Dask clusters.
  • Read/write access to shared `developer` folder group mount
  • Read/create access to Argo-Workflows and Jupyter-Scheduler
  • Inherent Grafana permissions from [Grafana editor scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles)
| -| `admin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_admin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `grafana_admin`
|
  • All of the above access, plus...
  • Read/write access to all conda-store available namespaces/environments.
  • Access to Jupyterhub Admin page and can access JupyterLab users spaces
  • Access to Keycloak and can add remove users and groups
  • Inherent Grafana permissions from [Grafana administrator scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles)
| -| `superadmin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_superadmin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `realm_admin` (Keycloak)
  • `grafana_admin`
|
  • All of the above access, plus...
  • Delete (build and environment) access on conda-store
  • Full access to Keycloak (realm) (same as `root`)
| +import React from 'react'; + +export const GroupTable = ({ groups }) => { + return ( + + + + + + + + + + + {groups.map((group) => ( + + {/* 1. Resources */} + + + {/* 2. Roles */} + + + {/* 3. Permissions Description */} + + + ))} + +
GroupAccess to Nebari ResourcesRolesPermissions Description
+
    + {group.resources.map((resource) => ( +
  • {resource}
  • + ))} +
+
+
    + {group.roles.map((role) => ( +
  • {role}
  • + ))} +
+
+
    + {group.permissions.map((perm, i) => ( +
  • {perm}
  • + ))} +
+
+ ); +}; + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import MarkdownTable from @site/src/components/MardownTable; + +
+ + + + + +| Group | Access to Nebari Resources | Roles | Permissions Description | +| --------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `analyst` |
  • Conda-Store
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_developer`
  • `jupyterhub_developer`
  • `argo_viewer`
  • `grafana_viewer`
|
  • Default user permissions.
  • Access to start a server instance and generate a JupyterHub access token.
  • Read/write access to shared `analyst` folder group mount.
  • Read access to the `analyst` namespace in conda-store (write access to personal namespace).
  • Read access to Argo Workflows and Jupyter Scheduler.
  • Inherits Grafana viewer permissions from [Grafana viewer scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles).
| + +
+ + +| Group | Access to Nebari Resources | Roles | Permissions Description | +| ----------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `developer` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana Developer
|
  • `conda_store_developer`
  • `dask_developer`
  • `jupyterhub_developer`
  • `argo_developer`
  • `grafana_developer`
|
  • Includes all `analyst` access, plus...
  • Read access to the `developer` namespace in conda-store.
  • Ability to create Dask clusters.
  • Read/write access to the shared `developer` folder group mount.
  • Read/create access to Argo Workflows and Jupyter Scheduler.
  • Inherits Grafana editor permissions from [Grafana editor scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles).
| + +
+ + +| Group | Access to Nebari Resources | Roles | Permissions Description | +| ------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `admin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_admin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `grafana_admin`
|
  • Includes all `developer` access, plus...
  • Read/write access to all conda-store namespaces/environments.
  • Access to JupyterHub Admin page and ability to access users’ JupyterLab spaces.
  • Access to Keycloak for user and group management.
  • Inherits Grafana administrator permissions from [Grafana administrator scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles).
| + +
+ + +| Group | Access to Nebari Resources | Roles | Permissions Description | +| ------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `superadmin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_superadmin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `realm_admin` (Keycloak)
  • `grafana_admin`
|
  • Includes all `admin` access, plus...
  • Delete (build and environment) access in conda-store.
  • Full realm administration in Keycloak (same as `root`).
| + +
+
+ +
+ + | :::info Check [Conda-store authorization model](https://conda-store.readthedocs.io/en/latest/contributing.html#authorization-model) for more details on conda-store authorization. diff --git a/docs/package.json b/docs/package.json index f287dba8..8142a898 100644 --- a/docs/package.json +++ b/docs/package.json @@ -49,7 +49,8 @@ "prism-react-renderer": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.77.8" + "sass": "^1.77.8", + "react-markdown": "^8.0.7" }, "devDependencies": { "@babel/eslint-parser": "^7.25.1", diff --git a/docs/src/components/MarkdownTable.ts b/docs/src/components/MarkdownTable.ts new file mode 100644 index 00000000..73463525 --- /dev/null +++ b/docs/src/components/MarkdownTable.ts @@ -0,0 +1,37 @@ +import React, { FC } from 'react'; +import ReactMarkdown from 'react-markdown'; + +interface MarkdownTableProps { + headers: string[]; + rows: string[][]; +} + +export const MarkdownTable: FC = ({ headers, rows }) => { + return ( + + + + { + headers.map((headerText, headerIdx) => ( + + )) + } + + + + { + rows.map((rowData, rowIdx) => ( + + { + rowData.map((cellContent, cellIdx) => ( + + )) + } + + ))} + +
{ headerText }
+ { cellContent } +
+ ); +}; From 4486a7b90e4ab0949fbc04cf4fdd40a01eaceb27 Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Fri, 24 Jan 2025 23:50:03 -0300 Subject: [PATCH 4/6] add table component and refactor scopes section with detailed info --- .../docs/how-tos/fine-grained-permissions.mdx | 490 ++++++++++-------- docs/package.json | 5 +- docs/src/components/MarkdownTable.ts | 37 -- docs/src/components/MarkdownTable/index.tsx | 46 ++ 4 files changed, 328 insertions(+), 250 deletions(-) delete mode 100644 docs/src/components/MarkdownTable.ts create mode 100644 docs/src/components/MarkdownTable/index.tsx diff --git a/docs/docs/how-tos/fine-grained-permissions.mdx b/docs/docs/how-tos/fine-grained-permissions.mdx index d717479d..e700a7d3 100644 --- a/docs/docs/how-tos/fine-grained-permissions.mdx +++ b/docs/docs/how-tos/fine-grained-permissions.mdx @@ -1,30 +1,23 @@ -# Fine Grained Permissions via Keycloak +--- +title: Fine-Grained Permissions via Keycloak +description: Learn how to manage roles, groups, and scopes in Keycloak to grant fine-grained permissions in Nebari. +--- +Nebari uses [Keycloak](https://www.keycloak.org/) to centrally manage roles, +permissions, and scopes for its core services like `jupyterhub` and `conda-store`. By +default, Nebari provides: -Nebari uses Keycloak to centrally manage roles, permissions, and scopes for various -services like `jupyterhub` and `conda-store`. By default, Nebari provides a set of -predefined clients and default roles that cover common needs—such as basic view/read -permissions or full admin control, a full list of which can be found in the [] section. +- **Predefined roles** (e.g., `conda_store_admin`, `jupyterhub_developer`) +- **Default groups** (`admin`, `developer`, `analyst`, `superadmin`) +- **Clients** corresponding to key Nebari services -However, certain environments require more specialized or granular access controls. In these cases, administrators (or any user with appropriate privileges) can create custom roles and scopes directly in Keycloak. This allows you to tailor the permission model to fit your precise security and governance requirements—all while still benefiting from the ready-to-use defaults Nebari provides. +These defaults cover most common access requirements. However, when more specific or +granular access control is needed, administrators can create custom roles and scopes in +Keycloak, see [Creating Custom Roles with Scopes](#creating-custom-roles-with-scopes). -## Managing Roles and Permissions +## Default Clients and Groups in Nebari -Overview -- *Roles*: Define a set of permissions (or scopes) for a particular client (service). -- *Groups*: Aggregate users who share similar permissions. -- *Scopes*: The individual permissions (e.g., “read:users:name” for reading user names) that can be attached to a role. - -By creating custom roles with specific scopes, and assigning them to groups or users, -you can fine-tune exactly who can do what in your Nebari environment. More details on how to create roles and scopes can be found in the [Creating a Role](#creating-a-role) section. - -## Default Clients and permissions in Nebari - -Nebari comes with several custom Keycloak clients in a fresh deployment. These map to -key Nebari services and integrations: - -By default, Nebari comes with several custom clients included in a fresh deployment. -These clients facilitate various services and integrations within the Nebari ecosystem. -The predefined clients are as follows: +A fresh Nebari deployment comes with several custom Keycloak clients (services) enabled. +You can manage these from **Clients** in the Keycloak admin console: ```yaml clients: @@ -35,145 +28,219 @@ clients: - forwardauth ``` -To manage and configure these clients, you can navigate to the `Clients` tab within the -Keycloak admin console, as illustrated in the image below. +Users are organized into default groups: `admin`, `developer`, `analyst`, and +`superadmin`. Each group has one or more default roles that define their access level +across Nebari services. -![Keycloak clients](/img/how-tos/fine_grainer_permissions_keycloak_clients.png) - -This can be accessed at `/auth/admin/master/console/#/realms/nebari/clients` +:::info Shared Folders +Membership in one of the default groups also grants access to the corresponding shared +folder (e.g., the `developer` group has access to `~/shared/developer`). Since, +`2024.9.1` Nebari now required a special role to access the shared folders +`Allow-group-directory-creation-role`. +::: -Groups represent a collection of users that perform similar actions and therefore require similar permissions. By default, Nebari is deployed with the following groups: `admin`, `developer`, and `analyst` (in roughly descending order of permissions and scope). +## In-depth Look at Default Roles and Groups -:::info -Users in a particular group will also get access to that groups shared folder. So if `user A` belongs to the `developer`, they will also have access to the `~/shared/developer` folder. This also applies to new groups that you create. -::: +Groups represent a collection of users that perform similar actions and therefore +require similar permissions. By default, Nebari is deployed with the following groups: +`admin`, `developer`, and `analyst` (in roughly descending order of permissions and +scope). -Roles on the other hand represent the type or category of user. This includes access and permissions that this category of user will need to perform their regular job duties. The differences between `groups` and `roles` are subtle. Particular roles (one or many), like `conda_store_admin`, are associated with a particular group, such as `admin` and any user in this group will then assume the role of `conda_store_admin`. +Roles on the other hand represent the type or category of user. This includes access and +permissions that this category of user will need to perform their regular job duties. +The differences between `groups` and `roles` are subtle. Particular roles (one or many), +like `conda_store_admin`, are associated with a particular group, such as `admin` and +any user in this group will then assume the role of `conda_store_admin`. -:::info -These roles can be stacked. This means that if a user is in one group with role `conda_store_admin` and another group with role `conda_store_viewer`, this user ultimately has the role `conda_store_admin`. +:::tip Technical Note +Roles in nebari can stack, meaning that if a user is in one group with role +`conda_store_admin` and another group with role `conda_store_viewer`, this user +ultimately has the role `conda_store_admin`. Also, in case of different level of access +orignating from different groups, precedence is given to the highest level of access. ::: -## In-depth look at Roles and Groups - -Below is a table illustrating each default group, the resources they can access, and the roles they inherit. The table also includes a brief description of the permissions granted to each group. - -import React from 'react'; - -export const GroupTable = ({ groups }) => { - return ( - - - - - - - - - - - {groups.map((group) => ( - - {/* 1. Resources */} - - - {/* 2. Roles */} - - - {/* 3. Permissions Description */} - - - ))} - -
GroupAccess to Nebari ResourcesRolesPermissions Description
-
    - {group.resources.map((resource) => ( -
  • {resource}
  • - ))} -
-
-
    - {group.roles.map((role) => ( -
  • {role}
  • - ))} -
-
-
    - {group.permissions.map((perm, i) => ( -
  • {perm}
  • - ))} -
-
- ); -}; +Below is a table that outlines the default roles, groups, and permissions that come with +Nebari: import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; -import MarkdownTable from @site/src/components/MardownTable; -
+import { Table } from '@site/src/components/MarkdownTable'; + +
- - -| Group | Access to Nebari Resources | Roles | Permissions Description | -| --------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `analyst` |
  • Conda-Store
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_developer`
  • `jupyterhub_developer`
  • `argo_viewer`
  • `grafana_viewer`
|
  • Default user permissions.
  • Access to start a server instance and generate a JupyterHub access token.
  • Read/write access to shared `analyst` folder group mount.
  • Read access to the `analyst` namespace in conda-store (write access to personal namespace).
  • Read access to Argo Workflows and Jupyter Scheduler.
  • Inherits Grafana viewer permissions from [Grafana viewer scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles).
| - -
- - -| Group | Access to Nebari Resources | Roles | Permissions Description | -| ----------- | -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `developer` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana Developer
|
  • `conda_store_developer`
  • `dask_developer`
  • `jupyterhub_developer`
  • `argo_developer`
  • `grafana_developer`
|
  • Includes all `analyst` access, plus...
  • Read access to the `developer` namespace in conda-store.
  • Ability to create Dask clusters.
  • Read/write access to the shared `developer` folder group mount.
  • Read/create access to Argo Workflows and Jupyter Scheduler.
  • Inherits Grafana editor permissions from [Grafana editor scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles).
| + ]} + /> +
+ + + + +
+ + +
+ + + - - +:::note +See [Conda-Store Authorization +Model](https://conda-store.readthedocs.io/en/latest/contributing.html#authorization-model) +for additional details. +::: -| Group | Access to Nebari Resources | Roles | Permissions Description | -| ------- | ---------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `admin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_admin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `grafana_admin`
|
  • Includes all `developer` access, plus...
  • Read/write access to all conda-store namespaces/environments.
  • Access to JupyterHub Admin page and ability to access users’ JupyterLab spaces.
  • Access to Keycloak for user and group management.
  • Inherits Grafana administrator permissions from [Grafana administrator scopes](https://grafana.com/docs/grafana/latest/administration/roles-and-permissions/#organization-roles).
| +:::warning +The `jupyterhub_admin` role grants permission to impersonate other users, including +viewing their home folder contents. Use it sparingly and refer to the [JupyterHub +docs](https://z2jh.jupyter.org/en/stable/jupyterhub/customizing/user-management.html#admin-users) +for more info. +::: -
- +## Roles, Groups, and Scopes -| Group | Access to Nebari Resources | Roles | Permissions Description | -| ------------ | ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| `superadmin` |
  • Conda-Store
  • Dask
  • Jupyterhub
  • Argo Workflows
  • Grafana
|
  • `conda_store_superadmin`
  • `dask_admin`
  • `jupyterhub_admin`
  • `argo_admin`
  • `realm_admin` (Keycloak)
  • `grafana_admin`
|
  • Includes all `admin` access, plus...
  • Delete (build and environment) access in conda-store.
  • Full realm administration in Keycloak (same as `root`).
| +When managing user access in Nebari, it's helpful to understand how **roles**, +**groups**, and **scopes** work together: -
- +- **Roles**: A named set of permissions, while also providing a way to categorize users + by their access level or job function. Example: `conda_store_developer` or + `jupyterhub_admin`. +- **Groups**: Collections of users who need similar permissions. For example, the + `developer` group might contain multiple roles like `conda_store_developer` and + `jupyterhub_developer`. +- **Scopes**: A Service's fine-grained permission entity within a role. For instance, a + JupyterHub scope might be `read:users:name` (to read other users’ names), while a + Conda-Store scope might be `admin!namespace=analyst` (to grant admin-level access in + the `analyst` namespace). - +Whenever you create or modify a role in Keycloak, it won’t affect anyone until it’s +assigned to a group or user. Below is the general process: - | +**Typical Workflow**: +1. **Create or edit** a role (and define its scopes) under the relevant **Client** + (e.g., `jupyterhub`, `conda_store`) in Keycloak. +2. **Assign** this role to a **group** (or directly to an individual user). +3. **Add users** to that group if you haven’t already. -:::info -Check [Conda-store authorization model](https://conda-store.readthedocs.io/en/latest/contributing.html#authorization-model) for more details on conda-store authorization. +:::note +Users must log out and log back in for newly assigned roles to take effect. ::: -:::caution -The role `jupyterhub_admin` gives users elevated permissions to JupyterHub and should be applied judiciously. As mentioned in the table above, a JupyterHub admin is able to impersonate other users and view the contents of their home folder. For more details, read through the [JupyterHub documentation](https://z2jh.jupyter.org/en/stable/jupyterhub/customizing/user-management.html#admin-users). -::: +### Granting Permissions to a User -To create new groups or modify (or delete) existing groups, log in as `root` and click **Groups** on the left-hand side. +Let’s say you have someone who only needs *administrator-level privileges for +Conda-Store*, while leaving other services at their default access. -As an example, we create a new group named `conda-store-manager`. This group will have administrator access to the [Conda-Store service]. +As an example, we create a new group named `conda-store-manager`. This group will have +administrator access to the `Conda-Store` service. 1. Click **New** in the upper-right hand corner under **Groups**. @@ -183,112 +250,113 @@ As an example, we create a new group named `conda-store-manager`. This group wil ![Keycloak add group form - name field set to conda-store-manager](/img/how-tos/keycloak_new_group1.png) -2. Under **Role Mapping**, add the appropriate **Client Roles** as needed; there should be no need to update the **Realm Roles**. +2. Under **Role Mapping**, add the appropriate **Client Roles** as needed; there should + be no need to update the **Realm Roles**. ![Keycloak group conda-store-manager form - role mappings tab focused with expanded client roles dropdown](/img/how-tos/keycloak_new_group2.png) -In this example, the new group only has one mapped role, `conda_store_admin`; however, it's possible to attach multiple **Client Roles** to a single group. +In this example, the new group only has one mapped role, `conda_store_admin`; however, +it's possible to attach multiple **Client Roles** to a single group. ![Keycloak group conda-store-manager form - role mappings tab focused ](/img/how-tos/keycloak_new_group3.png) -Once complete, return to the **Users** section in the dashboard and add the relevant users to this newly created group. - -### Creating a Role - -The process for creating a role is similar, irrespective of the service. To create a role for a -service - -1. Select the appropriate client and click on "Add Role". - -![Keycloak client add jupyterhub role](/img/how-tos/keycloak_jupyterhub_client.png) - -2. On the "Add Role" form, write a meaningful name and description for the role. Be sure to include what this role intends to accomplish. Click "Save". - -![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_jupyterhub_add_role.png) - -3. Now the role has been created, but it does nothing. Let's add some permissions to it by clicking on the "Attributes" tab - and adding scopes. The following sections will explain the `components` and `scopes` in more detail. - - ![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_add_role_attributes.png) - -### Adding Role to Group(s) / User(s) +Once complete, return to the **Users** section in the dashboard and add the relevant +users to this newly created group. -Creating a role in Keycloak has no effect on any user or group's permissions. To grant a set of permissions -to a user or group, we need to _attach_ the role to the user or group. To add a role to a user: - -1. Select users on the left sidebar and enter the username in the Lookup searchbar. - - ![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_select_user.png) +:::note +To create new groups or modify (or delete) existing groups, log in as `root` and click +**Groups** on the left-hand side. +::: -2. Select that user and click on the "Role Mappings" tab. +### Creating Custom Roles with Scopes -![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_user_role_mapping_tab.png) +Beyond Nebari’s default roles, you can also create your own with highly specific +permissions. The process for creating a role is similar, irrespective of the service. -3. Select the Client associated with the Role being added. +:::warning +Nebari currently only supports custom roles for the `jupyterhub` and `conda_store`. +Future releases may extend this to other services. +::: -![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_user_role_mapping_roles.png) +#### Components and Syntax -4. Select the role in the "Available Roles" and click on "Add Selected >>". +In Nebari, **scopes** are closely tied to the service (client) you’re working +with— In Keycloak's roles we identify them as “components.” -![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_user_role_mapping_add_role.png) +- **Components**: + Specifies the service that a role’s scopes apply to (e.g., `jupyterhub` or `conda-store`). +- **Scopes**: + The actual permission strings recognized by that service. -To attach a role to a group, follow the above steps by clicking on the groups tab and -selecting a group instead of selecting the user in the first step. +
-In the above section, we learned how to create a role with some attributes and attach it to a user or a group. -Now we will learn how to create scopes to grant a particular set of permissions to the user. +#### JupyterHub Scopes -:::note -After the roles are assigned to a user or group in Keycloak, the user **must** logout and login back in to the service -for the roles to take in effect. For example let's say we add a set of roles for `conda-store` to the user named -"John Doe", now for the user "John Doe" to be able to avail newly granted/revoked roles, they need to login to -conda-store again (similarly for `jupyterhub` as well), after the roles are granted/revoked. -::: - -## Components and Scopes - -When specifying fine-grained permissions in Keycloak, we use the `components` and -`scopes` attributes. These attributes are used to define the permissions that a role -grants to a user or group. This model follows the RBAC (Role-Based Access Control) model -and is based upong the same structure utilized by [Jupyterhub](https://jupyterhub.readthedocs.io/en/latest/rbac/index.html). +JupyterHub scopes syntax in Nebari follow [JupyterHub’s built-in RBAC +syntax](https://jupyterhub.readthedocs.io/en/stable/rbac/scopes.html). For example: +``` +shares!user,read:users:name,read:groups:name +``` +- `shares!user`: Allows sharing servers with other users. +- `read:users:name`: Grants read access to other users’ names. +- `read:groups:name`: Grants read access to other groups’ names. -### Components Attribute +This combination allows a user to share their server with others (via `shares!user`) and +also read other users’ and groups’ names. -We have seen in the above example the `component` attribute while creating a role. The value of this parameter -depends on the type of component in the service, we're creating a role for, currently we only have two components: +For a complete list of JupyterHub scopes, see the +[https://jupyterhub.readthedocs.io/en/stable/rbac/scopes.html#available-scopes](JupyterHub +documentation). -- `jupyterhub`: to create `jupyterhub` native roles in the `jupyterhub` client. -- `conda-store`: to create `conda-store` roles in the `conda_store` client +Nebari extend these scoped including a new *share* scope that is reserved for +`Jhub-apps` usage, allowing, as seen above for sharing servers with other users, +including more specifcaly jhub-apps applications (apps). -### JupyterHub Scopes +--- -The syntax for the `scopes` attribute for a `jupyterhub` role in Keycloak in Nebari follows the native RBAC scopes syntax -for JupyterHub itself. The documentation can be found [here](https://jupyterhub.readthedocs.io/en/stable/rbac/scopes.html#scope-conventions). +#### Conda-Store Scopes -As an example, scopes for allowing users to share apps in Nebari's `jhub-apps` launcher may look like this: +Conda-Store scopes are defined at the namespace level. For example: +``` +admin!namespace=analyst,developer!namespace=nebari-git +``` +- `admin!namespace=analyst`: Grants an **admin** role in the `analyst` namespace. +- `developer!namespace=nebari-git`: Grants a **developer** role in the `nebari-git` namespace. -> `shares!user,read:users:name,read:groups:name` +This grants an **admin** role in the `analyst` namespace, plus a **developer** role in +the `nebari-git` namespace. When assigned to a user or group, these permissions apply +only to those specified namespaces in Conda-Store. -The `scopes` defined above consists of three scopes: +Conda-store scopes follow a much simpler syntax than JupyterHub scopes, as they are only +defined at the namespace level: +``` +!namespace= +``` +whereas the `access_level` there entices the available conda-store' roles as per its own +documentation +[Conda-Store +role-mappings](https://conda.store/conda-store/explanations/conda-store-concepts#role-mappings). -- `shares!user`: grants permissions to share user's server -- `read:users:name`: grants permissions to read other user's names -- `read:groups:name`: grants permissions to read other groups's names +
-To be able to share a server to a group or a user you need to be able to read other user's or group's names and must have -permissions to be able to share your server, this is what this set of permissions implement. +### Creating a Role -### Conda Store Scopes +In the following example, we create a new role for the `JupyterHub` client granting the +same level of permission outlined in the section above [JupyterHub Scopes](#jupyterhub-scopes). -The scopes for roles for the `conda-store` Client are applied to the `namespace` level of `conda-store`. +1. Select the appropriate client and click on "Add Role". +![Keycloak client add jupyterhub role](/img/how-tos/keycloak_jupyterhub_client.png) -Below is example of granting a user specialized permissions to `conda-store`: +1. On the "Add Role" form, write a meaningful name and description for the role. Be sure + to include what this role intends to accomplish. Click "Save". -> `admin!namespace=analyst,developer!namespace=nebari-git` +![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_jupyterhub_add_role.png) -The `scopes` defined above consists of two scopes: +3. Now the role has been created, but it does nothing. Let's add some permissions to it + by clicking on the "Attributes" tab and adding scopes. The following sections will + explain the `components` and `scopes` in more detail. -- `admin!namespace=analyst`: grants `admin` access to namespace `analyst` -- `developer!namespace=nebari-git`: grants `developer` access to namespace `nebari-git` + ![Keycloak clients add jupyterhub role form](/img/how-tos/keycloak_add_role_attributes.png) -When attached to a user or a group, the above-mentioned permissions will be granted to the user/group. +To make these new permissions effective, assign the custom role to a user or group (via +**Role Mappings**). Again, any user changes require a re-login to become active. diff --git a/docs/package.json b/docs/package.json index 8142a898..f2e94bd5 100644 --- a/docs/package.json +++ b/docs/package.json @@ -44,13 +44,14 @@ "@docusaurus/preset-classic": "3.5.0", "@mdx-js/react": "^3.0.0", "clsx": "^2.1.1", + "dedent": "^0.7.0", "docusaurus-lunr-search": "^3.3.0", "docusaurus-plugin-sass": "^0.2.5", "prism-react-renderer": "^2.1.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.77.8", - "react-markdown": "^8.0.7" + "react-markdown": "^8.0.7", + "sass": "^1.77.8" }, "devDependencies": { "@babel/eslint-parser": "^7.25.1", diff --git a/docs/src/components/MarkdownTable.ts b/docs/src/components/MarkdownTable.ts deleted file mode 100644 index 73463525..00000000 --- a/docs/src/components/MarkdownTable.ts +++ /dev/null @@ -1,37 +0,0 @@ -import React, { FC } from 'react'; -import ReactMarkdown from 'react-markdown'; - -interface MarkdownTableProps { - headers: string[]; - rows: string[][]; -} - -export const MarkdownTable: FC = ({ headers, rows }) => { - return ( -
- - - { - headers.map((headerText, headerIdx) => ( - - )) - } - - - - { - rows.map((rowData, rowIdx) => ( - - { - rowData.map((cellContent, cellIdx) => ( - - )) - } - - ))} - -
{ headerText }
- { cellContent } -
- ); -}; diff --git a/docs/src/components/MarkdownTable/index.tsx b/docs/src/components/MarkdownTable/index.tsx new file mode 100644 index 00000000..eb882aff --- /dev/null +++ b/docs/src/components/MarkdownTable/index.tsx @@ -0,0 +1,46 @@ +import React from 'react'; +import ReactMarkdown from 'react-markdown'; +import dedent from 'dedent'; + +/** + * Each row in the table is an array of cells. + * Each cell can be either: + * - A single Markdown string, OR + * - An array of Markdown lines (which we'll join with '\n'). + */ +export interface MarkdownTableProps { + headers: string[]; + rows: Array>; +} + +export function Table({ headers, rows }: MarkdownTableProps) { + return ( + + + + {headers.map((header, headerIdx) => ( + + ))} + + + + {rows.map((rowData, rowIdx) => ( + + {rowData.map((cellData, cellIdx) => { + // If the cellData is an array of strings, join them with "\n" + const cellContent = Array.isArray(cellData) + ? dedent(cellData.join('\n')) + : dedent(cellData); + + return ( + + ); + })} + + ))} + +
{header}
+ {cellContent} +
+ ); +} From 287ae39ef8502b3eb2c208d181554fc49e9986bd Mon Sep 17 00:00:00 2001 From: vinicius douglas cerutti Date: Wed, 29 Jan 2025 17:43:55 -0300 Subject: [PATCH 5/6] fix lint typo --- docs/docs/how-tos/fine-grained-permissions.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/how-tos/fine-grained-permissions.mdx b/docs/docs/how-tos/fine-grained-permissions.mdx index e700a7d3..8b7fd659 100644 --- a/docs/docs/how-tos/fine-grained-permissions.mdx +++ b/docs/docs/how-tos/fine-grained-permissions.mdx @@ -56,7 +56,7 @@ any user in this group will then assume the role of `conda_store_admin`. Roles in nebari can stack, meaning that if a user is in one group with role `conda_store_admin` and another group with role `conda_store_viewer`, this user ultimately has the role `conda_store_admin`. Also, in case of different level of access -orignating from different groups, precedence is given to the highest level of access. +originating from different groups, precedence is given to the highest level of access. ::: Below is a table that outlines the default roles, groups, and permissions that come with From 8b8d94a4248b1196d8ff8b94d4afdc131dcc55a6 Mon Sep 17 00:00:00 2001 From: "Vinicius D. Cerutti" <51954708+viniciusdc@users.noreply.github.com> Date: Wed, 26 Feb 2025 16:43:39 -0300 Subject: [PATCH 6/6] Include extra permissions for API conda-store token --- docs/docs/how-tos/fine-grained-permissions.mdx | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/docs/how-tos/fine-grained-permissions.mdx b/docs/docs/how-tos/fine-grained-permissions.mdx index 8b7fd659..eff682f4 100644 --- a/docs/docs/how-tos/fine-grained-permissions.mdx +++ b/docs/docs/how-tos/fine-grained-permissions.mdx @@ -183,6 +183,7 @@ import { Table } from '@site/src/components/MarkdownTable'; [ '- Includes all Admin permissions, plus...', '- Delete privileges in Conda-Store (build & environment).', + '- Admin API service token privileges in Conda-Store.', '- Full Keycloak realm administration (root-level).', ], ],