Skip to content

Commit

Permalink
Merge pull request #2405 from consideRatio/pr/add-hub.loadRoles
Browse files Browse the repository at this point in the history
Add hub.loadRoles configuration
  • Loading branch information
manics authored Oct 2, 2021
2 parents bf65b10 + 6bc9530 commit 509fc47
Show file tree
Hide file tree
Showing 10 changed files with 121 additions and 5 deletions.
6 changes: 5 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,11 @@ jobs:
- run:
command: |
export KUBECONFIG="$HOME/.kube/config"
helm upgrade --install jupyterhub ./jupyterhub --values dev-config.yaml --values dev-config-arm.yaml --wait
helm upgrade --install jupyterhub ./jupyterhub \
--wait \
--values dev-config.yaml \
--values dev-config-arm.yaml \
--values dev-config-local-chart-extra-config.yaml
name: Install local chart

- run:
Expand Down
7 changes: 6 additions & 1 deletion .github/workflows/test-chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ jobs:
#
# The upgrade-from input should match the version information from
# https://jupyterhub.github.io/helm-chart/info.json
#
- k3s-channel: v1.19
test: upgrade
upgrade-from: stable
Expand Down Expand Up @@ -282,6 +283,7 @@ jobs:
echo
helm diff upgrade --install jupyterhub ./jupyterhub --values dev-config.yaml \
--values dev-config-local-chart-extra-config.yaml \
${{ matrix.local-chart-extra-args }} \
--show-secrets \
--context=3 \
Expand All @@ -308,7 +310,10 @@ jobs:
- name: "Install local chart"
run: |
helm upgrade --install jupyterhub ./jupyterhub --values dev-config.yaml ${{ matrix.local-chart-extra-args }}
helm upgrade --install jupyterhub ./jupyterhub \
--values dev-config.yaml \
--values dev-config-local-chart-extra-config.yaml \
${{ matrix.local-chart-extra-args }}
- name: "Await local chart"
uses: jupyterhub/action-k8s-await-workloads@v1
Expand Down
24 changes: 24 additions & 0 deletions dev-config-local-chart-extra-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This config file is useful in the upgrade tests, where we upgrade from
# either the latest stable chart or the latest dev release of the chart. This
# config is only applied to the chart we upgrade to. It helps us handle
# situations when we add new configuration options that would fail with a schema
# validation error in the previous chart versions.
#
# Note that one could think that it would be possible to have dev-config.yaml
# include this config and then pass --set hub.some-option=null to null it out
# when it must not be passed, but that still triggers schema validation errors.
#
hub:
# FIXME: move loadRoles to dev-config.yaml after 2.0.0 is released.
loadRoles:
test-scoped-access:
description: Used to JupyterHub 2.0.0+ RBAC scoped access, currently to the /hub/api/info endpoint via read:hub.
scopes: [read:hub]
services: [test-with-scoped-access]
test-role-with-explicit-name:
name: test-role-2
description: Access to users' information and group membership
scopes: [users, groups]
users: [cyclops, gandalf]
services: [test]
groups: []
2 changes: 2 additions & 0 deletions dev-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ hub:
test:
admin: true
apiToken: give-pytest-control
test-with-scoped-access:
apiToken: give-pytest-scoped-control
test-hub-existing-secret:
apiToken: dddd4444
test-explicit-name:
Expand Down
7 changes: 7 additions & 0 deletions jupyterhub/files/hub/jupyterhub_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,13 @@ def camelCaseify(s):

c.JupyterHub.services.append(service)

for key, role in get_config("hub.loadRoles", {}).items():
# c.JupyterHub.load_roles is a list of dicts, but
# hub.loadRoles is a dict of dicts to make the config mergable
role.setdefault("name", key)

c.JupyterHub.load_roles.append(role)


set_config_if_not_none(c.Spawner, "cmd", "singleuser.cmd")
set_config_if_not_none(c.Spawner, "default_url", "singleuser.defaultUrl")
Expand Down
34 changes: 34 additions & 0 deletions jupyterhub/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,40 @@ properties:
An alias for api_token provided for backward compatibility by
the JupyterHub Helm chart that will be transformed to
api_token.
loadRoles:
type: object
additionalProperties: true
description: |
This is where you should define JupyterHub roles and apply them to
JupyterHub users, groups, and services to grant them additional
permissions as defined in JupyterHub's RBAC system.
Complement this documentation with [JupyterHub's
documentation](https://jupyterhub.readthedocs.io/en/latest/rbac/roles.html#defining-roles)
about `load_roles`.
Note that while JupyterHub's native configuration `load_roles` accepts
a list of role objects, this Helm chart only accepts a dictionary where
each key represents the name of a role and the value is the actual
role object.
```yaml
hub:
loadRoles:
teacher:
description: Access to users' information and group membership
# this role provides permissions to...
scopes: [users, groups]
# this role will be assigned to...
users: [erik]
services: [grading-service]
groups: [teachers]
```
When configuring JupyterHub roles via this Helm chart, the `name`
field can be omitted as it can be implied by the dictionary key.
shutdownOnLogout:
type: [boolean, "null"]
description: *jupyterhub-native-config-description
Expand Down
1 change: 1 addition & 0 deletions jupyterhub/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ hub:
runAsGroup: 1000
allowPrivilegeEscalation: false
lifecycle: {}
loadRoles: {}
services: {}
pdb:
enabled: false
Expand Down
21 changes: 18 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,31 @@ def pytest_configure(config):


@pytest.fixture(scope="module")
def request_data():
def admin_api_token():
base_dir = os.path.dirname(os.path.dirname(__file__))
with open(os.path.join(base_dir, "dev-config.yaml")) as f:
y = yaml.safe_load(f)
token = y["hub"]["services"]["test"]["apiToken"]
return token


@pytest.fixture(scope="module")
def scoped_api_token():
"""This token is granted a limited scope"""
base_dir = os.path.dirname(os.path.dirname(__file__))
with open(os.path.join(base_dir, "dev-config.yaml")) as f:
y = yaml.safe_load(f)
token = y["hub"]["services"]["test-with-scoped-access"]["apiToken"]
return token


@pytest.fixture(scope="module")
def request_data(admin_api_token):
hub_url = os.environ.get("HUB_URL", "https://local.jovyan.org:30443")
return {
"token": token,
"token": admin_api_token,
"hub_url": f'{hub_url.rstrip("/")}/hub/api',
"headers": {"Authorization": f"token {token}"},
"headers": {"Authorization": f"token {admin_api_token}"},
"test_timeout": 60,
"request_timeout": 25,
}
Expand Down
16 changes: 16 additions & 0 deletions tests/test_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,22 @@ def test_api_info(api_request):
assert result["spawner"]["class"] == "kubespawner.spawner.KubeSpawner"


def test_api_info_with_scoped_token(api_request, scoped_api_token):
"""
Test access to the hub api's /info endpoint with an hub api token defined
via hub.services and that is granted the permissions of a role via
hub.loadRoles chart configuration.
A typical jupyterhub logging response to this test:
[I 2019-09-25 12:03:12.086 JupyterHub log:174] 200 GET /hub/api/info (test@127.0.0.1) 10.21ms
"""

print("asking for the hub information using a dedicated token with read:hub scope")
r = api_request.get("/info", headers={"Authorization": f"token {scoped_api_token}"})
assert r.status_code == 200


def test_api_create_and_get_user(api_request, jupyter_user):
"""
Tests the hub api's /users/:user endpoint, both POST and GET.
Expand Down
8 changes: 8 additions & 0 deletions tools/templates/lint-and-validate-values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,14 @@ hub:
oauth_roles: [dummy]
info:
key1: value1
loadRoles:
test-role-1:
name: test-role-1
description: Access to users' information and group membership
scopes: [users, groups]
users: [cyclops, gandalf]
services: [test-service-1]
groups: [test-group-1]
pdb:
enabled: true
maxUnavailable: 1
Expand Down

0 comments on commit 509fc47

Please sign in to comment.