Modify /jwt/auth endpoint for registry tag protection feature
What does this MR do and why?
Related to https://gitlab.com/gitlab-org/gitlab/-/issues/499874.
The rational behind the changes in this MR is described in detail here. These changes sit behind a new feature flag (https://gitlab.com/gitlab-org/gitlab/-/issues/505455+).
References
Please include cross links to any resources that are relevant to this MR This will give reviewers and future readers helpful context to give an efficient review of the changes introduced.
- https://gitlab.com/gitlab-org/gitlab/-/issues/499874
- https://gitlab.com/groups/gitlab-org/-/epics/15608#jwt-auth
MR acceptance checklist
Please evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.
Screenshots or screen recordings
Not applicable as the corresponding frontend changes (https://gitlab.com/gitlab-org/gitlab/-/issues/499871) are not yet implemented.
How to set up and validate locally
We'll assume that you have a gitlab-org/gitlab-test
project in your GDK, and a PAT from a user with Owner role with read/write registry permissions. Set the CR_PAT
environment variable to the PAT value and CR_USER
to the username.
For these tests I'm going to use the jq
and jwt
CLI tools to facilitate parsing the output of requests. Adjust the curl
commands if you don't want to use them (in which case you'll have to manually parse and decode the tokens).
-
First make a test with the FF disabled (default). To do so we need to obtain a token from the
/jwt/auth
endpoint:curl -s -u "$CR_USER:$CR_PAT" \ -G \ --data-urlencode "service=container_registry" \ --data-urlencode "scope=repository:gitlab-org/gitlab-test:pull,push" \ http://gdk.test:3000/jwt/auth | jq -r '.token' | jwt decode -j - | jq -r '.payload.access'
[ { "actions": [ "pull", "push" ], "meta": { "project_id": 2, "project_path": "gitlab-org/gitlab-test", "root_namespace_id": 24 }, "name": "gitlab-org/gitlab-test", "type": "repository" } ]
Note that there is no meta.tag_deny_access_patterns
key.
-
Now let's enable the FF for our project in the Rails console:
project = Project.find_by_full_path 'gitlab-org/gitlab-test' Feature.enable(:container_registry_protected_tags, project)
-
Repeat the request. You should see exactly the same output as there are no configured rules for this project.
-
Now let's create some rules:
project.container_registry_protection_tag_rules.create(tag_name_pattern: 'latest', minimum_access_level_for_push: Gitlab::Access::MAINTAINER, minimum_access_level_for_delete: Gitlab::Access::MAINTAINER) project.container_registry_protection_tag_rules.create(tag_name_pattern: 'precious', minimum_access_level_for_push: Gitlab::Access::OWNER, minimum_access_level_for_delete: Gitlab::Access::OWNER)
-
Repeat the request. You should see:
[ { "actions": [ "pull", "push" ], "meta": { "project_id": 2, "project_path": "gitlab-org/gitlab-test", "root_namespace_id": 24, "tag_deny_access_patterns": { "push": [] } }, "name": "gitlab-org/gitlab-test", "type": "repository" } ]
Note the meta.tag_deny_access_patterns
object is now present, and the empty push
array within, even though our user (as an admin) has no tag restrictions.
-
Now set the
CR_USER
andCR_PAT
variables to a username/PAT of a user with the Developer role in this project. -
Repeat the request. You should see:
[ { "actions": [ "pull", "push" ], "meta": { "project_id": 2, "project_path": "gitlab-org/gitlab-test", "root_namespace_id": 24, "tag_deny_access_patterns": { "push": [ "latest", "precious" ] } }, "name": "gitlab-org/gitlab-test", "type": "repository" } ]
-
Promote the user to Maintainer in this project, and then repeat the request. We can also test the
delete
action:curl -s -u "$CR_USER:$CR_PAT" \ -G \ --data-urlencode "service=container_registry" \ --data-urlencode "scope=repository:gitlab-org/gitlab-test:pull,push,delete" \ http://gdk.test:3000/jwt/auth | jq -r '.token' | jwt decode -j - | jq -r '.payload.access'
[ { "actions": [ "pull", "push", "delete" ], "meta": { "project_id": 2, "project_path": "gitlab-org/gitlab-test", "root_namespace_id": 24, "tag_deny_access_patterns": { "delete": [ "precious" ], "push": [ "precious" ] } }, "name": "gitlab-org/gitlab-test", "type": "repository" } ]