Sender constraining personal access tokens
See the epic (Allow users to require demonstrated proof of po... (&14383)) for context, pre-work, and other related issues.
This issue is to apply the constraint on senders that, when configured, they demonstrate proof of possession of a signing key for the user whose PAT is being used.
Implementation plan
- Identify the logic that is used in the REST API to authenticate via PersonalAccessTokens (Users only - not Group or Project)
- Update the logic so that:
- IF the Feature Flag is enabled for the user
- IF the user has enabled the DPoP user setting
- Use the logic from Parse and validate DPoP Tokens (#480638) to validate that the token was signed by one of the user's valid & active SSH keys
- If the DPoP is valid then authentication should succeed
- If the DPoP is invalid then authentication should fail
- Files from the original MR that can be re-used:
- app/controllers/graphql_controller.rb
- lib/api/api_guard.rb
- lib/gitlab/auth/auth_finders.rb
- spec/requests/*
Original "Problem" and "Proposal"
Problem
While it is great that we removed support for non-expiring tokens in %16.0, I think we can go a step further to protect access tokens (PATs, PrATs, GATs, Service Account tokens) that do get leaked and have a long expiration time, say, close to a year. An attacker in possession of such a leaked token can still maintain access to that user's account and the organization that user is associated with, for that period of time.
Currently we don't authenticate who's sending the token through an API request. We just check to see if the token hasn't expired and the token is authorized to perform the action mentioned in the request and we let it through. So, the backend has no way of knowing if it is the legitimate user with their access token or if it is the attacker using a leaked token that is making the request. If the leaked token belongs to a high-privileged user (Maintainer or above) in that organization, this could be very bad.
Proposal
To prevent such a misuse of leaked high-privileged access tokens, I'm proposing that we start supporting mechanisms like Demonstrating Proof-of-Possession (DPoP) or Mutual TLS that bind access tokens to a principal. Mechanisms like these would sender-constrain the tokens and immediately invalidate token leaks as an attacker in possession of such a leaked token won't be able to do anything with it unless they have the private key (for the client certificate in mTLS case or to demonstrate proof of possession in DPoP case) associated with that token to authenticate their request to the authorization server.
Since this proposal is suggesting adding another security layer on top of existing tokens for them to work, I'm proposing that we implement this only for tokens belonging to high-privileged users (Maintainers or above) and enable this as a user-level setting that these users have to enable to sender-constrain their PATs. We can gradually roll this out to all the users, depending on the adoption of this feature and perhaps make this an instance-level/top-level group setting that admins/group owners can enable.
I'm opening this issue as this idea was proposed multiple times (here and here) but we never had a security typefeature open for it.
/cc @adil.farrukh @hsutor