Advertisement

In GitLab version 16.0.0, the default settings for “Personal Access Tokens” (PAT) were changed. Since I use PATs for my deployments, I needed an automated solution to rotate these tokens regularly.

The script requires at least write access to the GitLab API - see Fig. 1.

Configuration PAT

Fig. 1: Configuration of Personal Access Token.

It makes use of two essential commands to rotate the PAT:

  • curl
  • duckdb

The curl command is used to interact with the API of my GitLab instance. Initially, it verifies API access. If the access check is successful, the token is then rotated.

The duckdb command is employed to parse the JSON returned by the API. For more details on using duckdb as an alternative to jq, see this article.

To ensure ample time for the next PAT rotation, the script uses the “expires_at” attribute. The chosen time span is similar to the duration of Let’s Encrypt Certificates.

The new PAT is written to a separate file, which is sourced at the beginning of the script.

If you choose to use the following script, make sure you change the GitLab API url and the PAT in the pat.conf.

vim pat.conf
PAT='CHANGEME'
vim rotate.sh
#!/bin/bash

set -e

: ${CI_API_V4_URL:=https://gitlab.example.com/api/v4/}
: ${PAT_NAME:='self'}

. ./pat.conf

IS_REVOKED=$(curl -s --header "PRIVATE-TOKEN: ${PAT}" "${CI_API_V4_URL}/personal_access_tokens/${PAT_NAME}" \
  | duckdb -noheader -column -c "SELECT revoked FROM read_json_auto('/dev/stdin');" \
  | tr -d '[:blank:]'
)

if [ "${IS_REVOKED}" != "false" ]; then
  echo [ERROR] Token does not exist, access denied to token or the token has already been revoked. Aborting
  exit 1
fi

EXPIRES_AT=$(date --date "+3 months" +"%Y-%m-%d")

NEW_PAT=$(
curl --request POST --header "PRIVATE-TOKEN: ${PAT}" "${CI_API_V4_URL}/personal_access_tokens/${PAT_NAME}/rotate?expires_at=${EXPIRES_AT}" \
  | duckdb -noheader -column -c "SELECT token FROM read_json_auto('/dev/stdin');"
)

if [ -z "${NEW_PAT}" ]; then
  echo '[ERROR] New personal access token is null. Not overwriting the current one in config file. Aborting'
  exit 1
fi

echo "PAT='${NEW_PAT}'" > ./pat.conf

Discussion

If you found a mistake in this article or would like to contribute some content to it, please file an issue in this Git Repository

Disclaimer

The contents of this article are put together to the best of the authors' knowledge, but it cannot be guaranteed that it's always accurate in any environment. It is up to the reader to make sure that all information found in this article, does not do any damage to the reader's working environment or wherever this information is applied to. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, arising from, out of or in connection with this article. Please also note the information given on the Imprint' page.