List Revoked and Expired Project and Group Access Tokens
Problem to solve
Currently, GitLab automatically deletes project and group access tokens once they expire or are revoked, which can create challenges for auditing and security reviews due to the lack of a record of expired tokens. This proposal suggests retaining revoked Group / Project Access Token records, to help teams track token usage and expiration for compliance and monitoring purposes.
Proposal
Introduce a new table to the Group & Project Access Token pages that displays a list of expired project and group access tokens. This list should include relevant details such as the token name, expiration date, creation date, e.g.:
Benefits
- Audit Trail: Provides an audit trail for access tokens, helping teams review and ensure compliance with security policies.
- Security Monitoring: Enhances security monitoring by allowing administrators to review and investigate security incidents by determining which access tokens were active at the time.
- Operational Transparency: Improves transparency into token usage and lifecycle management.
Implementation Details
Current State
-
Projects::Settings::AccessTokensController
andGroups::Settings::AccessTokensController
includeAccessTokenActions
. -
AccessTokensActions#revoke
callsResourceAccessTokens::RevokeService.new(current_user, resource, @resource_access_token).execute
. -
RevokeService
callsaccess_token.revoke!
andDeleteUserWorker.perform_async(current_user.id, bot_user.id, skip_authorization: true)
-
DeleteUserWorker
callsUsers::DestroyService.new(current_user).execute(delete_user, options.symbolize_keys)
which callsUsers::GhostUserMigration.create!
-
MigrateRecordsToGhostUserService
migrates a bunch of records to the Ghost user, then callsuser.destroy_dependent_associations_in_batches
. - This is, presumably, why the Bot's
personal_access_tokens
are revoked
Implementation Plan
At least 3 MRs:
- Update
ResourceAccessTokens::RevokeService
to not callDeleteUserWorker
- Use a FeatureFlag like
Feature.enabled?(:retain_resource_access_token_user_after_revoke, resource)
- Use a FeatureFlag like
- Update
WHAT?
to not expire bot user membership when a token expires- Use the same FF
- Update the API & UI of Project Access Tokens to show expired or revoked tokens
- We can display this table if
Feature.enabled?(:retain_resource_access_token_user_after_revoke, resource)
to simplify rollout - Note: this UI might show tokens that "haven't expired yet", but are still inactive as they're revoked. This might be confusing
🤷 - Note: the UI would only show tokens that were revoked / expired after the FF is enabled. (We can't reconstruct lost data). This might also be confusing.
- We can display this table if
- Update the API & UI of Group Access Tokens to show expired or revoked tokens
- As above
- Update the Group & Project Resource Token API endpoints to accept a
state
parameter with eitheractive|inactive
, defaulting toactive
.- This follows the same pattern as https://docs.gitlab.com/ee/api/personal_access_tokens.html#list-personal-access-tokens
Implications:
- An instance (incl .com) will retain an ever-increasing number of Group & Project Bot Users.
- An alternative was to migrate revoked tokens to the Ghost user, but then we lose the association to the group/project so that's a non-starter.
- I don't believe we need to
Block
them because this type of user can't do anything else anyway, and already don't count as a seat?...
- Because we retain the bot user, we will still see their username in comments / notes / whatever - current state is that these all get migrated to the Ghost user
- If a Group/Project Bot is deleted via the Admin panel (or some other method) we will lose it from this new table, too. I don't see a way around that.
Edited by Nick Malcolm