Skip to content

GitLab token rotation

A GitLab access token lives at most a year. The token-rotator job rotates the tokens it manages every night, 90 days before they expire, and writes each new value to every place that holds it. The GitLabTokenExpiring alert from dc-monitoring reports every other machine token in time to renew it by hand. The rotator’s README covers how it works; this page covers what you do. It lives in the trusted-ops group, whose members alone can merge there, because the job holds an instance-admin token.

  1. Create a group or project access token with the lowest role and the fewest scopes that work. A personal token stops working when its owner leaves, and only its owner can renew it.

  2. Store the value only where the service reads it: a CI/CD variable or a Coolify environment variable. A copy in Bitwarden goes stale at the first rotation.

  3. Add the token to tokens.py in a merge request, from a fork unless you are in trusted-ops, with every place that holds the value:

    GitLabToken(
    "deploy-bot", # the token's name in GitLab
    "projects/123", # groups/<id>, projects/<id> or users/<id>
    (
    CoolifyEnv("applications/<uuid>", "DEPLOY_TOKEN"), # or services/<uuid>
    CiVariable("dc/dcentralize/deploy", "DEPLOY_TOKEN"),
    ),
    ),

GitLab revokes the old value the moment a token is rotated, so a place missing from the list breaks at the next rotation. A token that is also used where the rotator cannot write, such as a file on a server, stays out of tokens.py and is renewed by hand. So are tokens on gitlab.com.

GitLabTokenExpiring posts in the dcentralize-alerts Mattermost channel once a day for every group, project or machine-user token with fewer than 45 days left.

  • A token in tokens.py: its rotation failed. The failed rotate_tokens job in the token-rotator pipelines names the token and the place it could not write.
  • Any other token: rotate it in GitLab and update every place that holds it, or add it to tokens.py so it is rotated from then on.

Personal tokens are not in the alert: GitLab mails their owner 60, 30 and 7 days before one expires.

Never rotate a token from tokens.py in GitLab by hand: every place that holds it keeps the revoked value. Ask a trusted-ops member to run the rotator with --force <name> instead, as its README describes under Running it by hand. That rotates the token, which revokes the leaked value, and writes the new value to every place in the same run. It needs no old value, so it also repairs a token whose rotation failed halfway.