Dependency Proxy: Add group access token scope checks
📓 History
!129697 (merged) added scope checks for group access tokens accessing the Dependency Proxy. This MR had to be reverted because it caused service account users to lose access to Dependency Proxy (incident).
This MR implements Add scope checks when using Dependency Proxy wi... (!129697 - merged) changes but keep user types access that previously had access to the dependency proxy (For example service_account
)
To reduce the scope of this MR, some specs have been extracted into a separate MR Improve spec coverage for dependency proxy for ... (!136946 - merged).
🌱 Context
Dependency Proxy Authorization and Authentication Overview
🔬 Details
docker login
sends these GET requests:
-
/v2/
->Groups::DependencyProxyAuthController#authenticate
-
/jwt/auth
->JwtController#auth
docker pull
sends these GET requests:
-
/v2/
->Groups::DependencyProxyAuthController#authenticate
-
/jwt/auth
->JwtController#auth
-
/v2/<group_path>/dependency_proxy/containers/<image_name>/manifests/<image_tag>
->Groups::DependencyProxyForContainersController#manifest
💥
Problem docker login
and docker pull
requests from a group access token with insufficient scopes for Dependency Proxy are not rejected.
We can add the scope checks, but where should we add it?
In policy code (in GroupPolicy
, to be specific), we are passed only the token user and the dependency proxy group. We do not have a handle to the actual token. We considered doing bot_user.personal_access_tokens.first
but decided it will not work, because it is possible to add tokens even to a bot user. As such, we cannot determine if a group access token has the correct scopes in a policy code.
In the controller code, when we authenticate the token, we have a handle to the token, but we do not know the dependency proxy group
🚑
Solution - We do group access token scope checking in
Auth::DependencyProxyAuthenticationService
, called fromJwtController
- We do group membership checking in
GroupPolicy
Screenshots or screen recordings
No UI changes
How to set up and validate locally
Enable Dependency Proxy for a group
Testing new behavior
docker login
A group access token with insufficient scopes should fail - Create a group access token for the group. Give it only the
read_registry
scope. - Clear docker credentials:
docker logout http://gdk.test:3000
- Enable the feature flag for the token. Run in Rails console:
token = PersonalAccessToken.find_by_name('<name_of_token>') Feature.enable(:packages_dependency_proxy_containers_scope_check, token.user)
- Login:
docker login http://gdk.test:3000 -p <group_access_token>
. The login should fail. - Disable the feature flag for the token. Run in Rails console:
token = PersonalAccessToken.find_by_name('<name_of_token>') Feature.disable(:packages_dependency_proxy_containers_scope_check, token.user)
- Feature flags are cached. It might be necessary to restart GDK before proceeding to the next step, to have the updated feature flag value in effect.
- Login:
docker login http://gdk.test:3000 -p <group_access_token>
. The login should succeed.
Verifying that existing behavior still works
docker pull
A group access token with sufficient scopes should be able to - Create another group access token, this time give it both
read_registry
andwrite_registry
scopes. - Login with the newer token. It should be successful.
- Pull an image:
docker pull gdk.test:3000/<group-namespace>/dependency_proxy/containers/alpine:latest
. This should also be successful. - Open the group dependency proxy page (Group home -> Operate -> Dependency Proxy, or
http://gdk.test:3000/groups/<group-namespace>/-/dependency_proxy
), you should see the pulled image in the list of images
docker login
and docker pull
A revoked group access token, even with sufficient scopes, should fail - Revoke the token used for the successful pull in the previous step. From the Rails console, run
PersonalAccessToken.last.revoke!
- Try the
docker pull
again:docker pull gdk.test:3000/<group-namespace>/dependency_proxy/containers/alpine:latest
. This time the operation should fail with a forbidden response. This confirms that we do our auth checks for every operation, even if the user is already logged in. - Try
docker login
again with the token. This time the login should fail.
api
scope should be able to docker pull
A group access token with The api
scope grants read_registry
and write_registry
access (documentation).
- Create a new group access token, this time give it only the
api
scope. -
docker login
anddocker pull
should be both successful just like A group access token with sufficient scopes
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #431386