diff --git a/check_gitlab_tokens b/check_gitlab_tokens index 58fdd8cad3aec51bff3e72990f3baf0a59029d9a..c3ad8495a6ae11fcde45308a89d873923f17bf11 100755 --- a/check_gitlab_tokens +++ b/check_gitlab_tokens @@ -1,22 +1,22 @@ #!/bin/bash # ====================================================================== # -# Check Gitlab tokens +# Check Gitlab tokens of groups and projects. +# It warns if tokens expire soon. # # requirements: # - inc/rest-api-client.sh # - curl # # ---------------------------------------------------------------------- -# 2024-10-25 v0.0 <axel.hahn@iml.unibe.ch> +# 2024-10-29 v1.0 <axel.hahn@iml.unibe.ch> # ====================================================================== - cd "$( dirname "$0" )" || exit - . "$( dirname $0 )/inc_pluginfunctions" || exit 1 -export self_APPVERSION=0.1 +export self_APPVERSION=1.0 + GITLAB_API='https://gitlab.example.com/api/v4' GITLAB_TOKEN='glpat-12345678' @@ -24,6 +24,11 @@ GITLAB_TOKEN='glpat-12345678' GITLAB_CONFIG=/etc/icinga2/gitlab.cfg REST_CLIENT="$( dirname $0 )/../inc/rest-api-client.sh" +projectUrls= + +OUT_TOKENS=/tmp/gitlab-tokens__$USER.json +OUT_USERS=/tmp/gitlab-users__$USER.json + typeset -i iSince=395 typeset -i iTokenCount typeset -i iTokensFound @@ -35,19 +40,20 @@ typeset -i iCriticalLimit=10 typeset -i iCountWarn=0 typeset -i iCountCritical=0 + output="" # ---------------------------------------------------------------------- # functions # ---------------------------------------------------------------------- - +# Show help function showHelp(){ local _self; _self=$(basename $0) cat <<EOF $( ph.showImlHelpHeader ) -Check gitlab tokens and warn if a token expires soon. +Check gitlab tokens and warn if tokens expire soon. This check fetches the gitlbab tokens created in the last $iSince days from the Gitlab API. It skips @@ -55,8 +61,11 @@ from the Gitlab API. It skips - personal access tokens of users - revoked tokens +The script can run several seconds depending on count of tokens, projects +and users. Maybe you want to call it with a longer interval. + SYNTAX: -$_self [-w WARN_LIMIT] [-c CRITICAL_LIMIT] +$_self [OPTIONS] OPTIONS: @@ -74,13 +83,22 @@ PARAMETERS: None. -EXAMPLE: - $(basename $0) -w 28 -c 7 +EXAMPLES: + + $_self -w 28 -c 7 + Set other warning and critical level + + $_self -g ./gitlab.cfg + Set a custom gitlab config file + + $_self -r /opt/bash-api-client/bash-api-client.sh + Set a custom gitlab config file EOF } -# Ffetch data from gitlab api with page requests +# Fetch data from gitlab api with multiple page requests +# # param string url # param string output file # param int optional: number of items per page; default: 100 @@ -104,7 +122,7 @@ function _getPagesToFile(){ echo "ERROR: Request failed: $pageUrl" http.getResponseHeader http.getResponse - exit 1 + ph.abort fi # if response is "[]" then we are done @@ -117,8 +135,45 @@ function _getPagesToFile(){ done } +# Get web link of a project to see its tokens +# +# global string projectUrls string to cache project name + link +# +# param string username eg. projects_14_bot_nnnnnn +# return string +function getWeblink(){ + local myusername="$1" + + sType=$( cut -f 1 -d "_" <<< "$myusername" )s + # sType is one of users|projects + + sId2=$( cut -f 2 -d "_" <<< "$myusername" ) + local data + local myurl + if ! grep -q "^/$sType/$sId2:" <<< "$projectUrls" ; then + http.makeRequest "/$sType/$sId2" + if ! http.isOk > /dev/null; then + echo "ERROR: Request /$sType/$sId2 failed: $pageUrl" + http.getResponseHeader + http.getResponse + ph.abort + fi + data="$( http.getResponse )" + myname=$( getKey "$data" "name" ) + myurl=$( getKey "$data" "web_url" ) + if [ -n "$myurl" ]; then + projectUrls+="/$sType/$sId2:$myname <$myurl/-/settings/access_tokens>$NL" + fi + fi + grep "^/$sType/$sId2:" <<< "$projectUrls" | cut -f 2- -d ":" +} + +# Get a single value from json +# param string json data +# param string key +# return string function getKey(){ - echo "$1" | jq -r ".$2" | grep -v "null" + jq -r ".$2" <<< "$1" | grep -v "null" } # ---------------------------------------------------------------------- @@ -156,26 +211,23 @@ startdate="$( date +%Y-%m-%dT00:00:00Z --date "$iSince days ago")" sDateWarn="$( date +%Y%m%d --date "${iWarnLimit} days" )" sDateCritical="$( date +%Y%m%d --date "${iCriticalLimit} days" )" -url="/personal_access_tokens/?revoked=false&created_after=${startdate}" -_getPagesToFile "$url" "/tmp/gitlab-tokens.json" -_getPagesToFile "/users" /tmp/gitlab-users.json +# get all tokens +# see https://docs.gitlab.com/ee/api/personal_access_tokens.html +_getPagesToFile "/personal_access_tokens/?revoked=false&created_after=${startdate}" "$OUT_TOKENS" +# get all users +# see https://docs.gitlab.com/ee/api/users.html +_getPagesToFile "/users?exclude_humans=true&exclude_external=true&exclude_internal=true&created_after=${startdate}&search=_bot_" "$OUT_USERS" # IDs / Einträge zählen: -iTokenCount=$( cat /tmp/gitlab-tokens.json | jq ".[].id " | wc -l ) -# echo "Found Tokens since $startdate: $iTokenCount" - - -# echo "Warn when expiring before: ${sDateWarn} ... critical before: ${sDateCritical}" -# loop over tokens +iTokenCount=$( jq ".[].id " < "$OUT_TOKENS" | wc -l ) iTokensFound=0 - for i in $( seq 1 $iTokenCount ) do # get nth token - entry="$( cat /tmp/gitlab-tokens.json | jq ".[$i]" )" + entry="$( jq ".[$i]" < "$OUT_TOKENS")" # hide non active tokens if [ "$( getKey "$entry" "active" )" = "false" ]; then @@ -190,7 +242,7 @@ do # hide tokens referencing a username that doesn't contain "_[number]_bot_" sUserid=$( getKey "$entry" "user_id" ) - myusername="$( cat /tmp/gitlab-users.json | jq ".[] | select(.id == $sUserid)" | jq ".username" | cut -f 1-3 -d "_" | tr -d '"') " + myusername="$( jq ".[] | select(.id == $sUserid)" < "$OUT_USERS" | jq ".username" | cut -f 1-3 -d "_" | tr -d '"') " if ! grep -q "_[0-9]*_bot" <<< "$myusername" ; then continue fi @@ -215,12 +267,9 @@ do fi fi - # url of owning group (is that useful?) - sType=$( cut -f 1 -d "_" <<< "$myusername" )s - sId2=$( cut -f 2 -d "_" <<< "$myusername" ) - myurl="$GITLAB_API/$sType/$sId2" + myproject="$( getWeblink "$myusername" )" - output+="$sExpire $sStatus $sName $myusername $myurl${NL}" + output+="$sExpire $sStatus $sName - $myproject${NL}" done @@ -236,4 +285,10 @@ ph.status "$iTokensFound Gitlab Tokens (max $iSince days old) .. critical: $iCou echo echo "$output" -rm -f /tmp/gitlab-tokens.json /tmp/gitlab-users.json \ No newline at end of file + +# cleanup +rm -f "$OUT_TOKENS" "$OUT_USERS" + +ph.exit + +# ---------------------------------------------------------------------- diff --git a/docs/20_Checks/check_gitlab_tokens.md b/docs/20_Checks/check_gitlab_tokens.md index e93bbae26babc57fe51442fa4a23223d98089b63..50ac7121dab949f53847f0a21e4c652d4415b7ce 100644 --- a/docs/20_Checks/check_gitlab_tokens.md +++ b/docs/20_Checks/check_gitlab_tokens.md @@ -4,12 +4,36 @@ **check_gitlab_tokens** checks all newer tokens of projects and groups if they expire soon. You can set a warning and a critical level in days. +Gitlab has an api requrest `/personal_access_tokens` but it doesn't have the information about the project or usergroup where it is defined. +This check executes additional requests to show it and offers the url to the web linkinterface. + +The check returns + +* unknown - the http request to gitlab api failed +* critical - min. 1 token is expiring soon +* warning - min. 1 token reached the warning level (and no criritical token was found) +* ok - api request was successful; no critical or warning token was found. + ## Requirements * curl * Bash REST API client<br>A set of class like functions with a http. prefix. <br>Docs: <https://os-docs.iml.unibe.ch/bash-rest-api-client/> -Extract or Git pull the Bash REST API client somewhere in your filesystem. eg. /opt/bash-api-client/. With the parameter `-r <FILE>` you point to the file `rest-api-client.sh`. +Extract or Git pull the Bash REST API client somewhere in your filesystem. eg. /opt/bash-api-client/. With the parameter `-r <FILE>` you point to the file `rest-api-client.sh`. + +## Configuration + +The script needs to connect to the Gitlab API. +You need to create a token in a admin group to read all tokens of all projects. + +Put 2 bash variabbles into `/etc/icinga2/gitlab.cfg`: + +```shell +GITLAB_API='https://gitlab.example.com/api/v4' +GITLAB_TOKEN='glpat-1234567890' +``` + +You can use another filename for this configuration - but then you need the parameter `-g <FILE>`to reference it. ## Syntax @@ -18,7 +42,7 @@ Extract or Git pull the Bash REST API client somewhere in your filesystem. eg. / ______________________________________________________________________ CHECK_GITLAB_TOKENS -v0.1 +v1.0 (c) Institute for Medical Education - University of Bern Licence: GNU GPL 3 @@ -26,7 +50,7 @@ Licence: GNU GPL 3 https://os-docs.iml.unibe.ch/icinga-checks/Checks/check_gitlab_tokens.html ______________________________________________________________________ -Check gitlab tokens and warn if a token expires soon. +Check gitlab tokens and warn if tokens expire soon. This check fetches the gitlbab tokens created in the last 395 days from the Gitlab API. It skips @@ -34,8 +58,11 @@ from the Gitlab API. It skips - personal access tokens of users - revoked tokens +The script can run several seconds depending on count of tokens, projects +and users. Maybe you want to call it with a longer interval. + SYNTAX: -check_gitlab_tokens [-w WARN_LIMIT] [-c CRITICAL_LIMIT] +check_gitlab_tokens [OPTIONS] OPTIONS: @@ -53,30 +80,36 @@ PARAMETERS: None. -EXAMPLE: - check_gitlab_tokens -w 28 -c 7 +EXAMPLES: -``` + check_gitlab_tokens -w 28 -c 7 + Set other warning and critical level -### Parameters + check_gitlab_tokens -g ./gitlab.cfg + Set a custom gitlab config file -Add directories to check. -Set a directory that is writable for world or prepared to be accessible for the icinga user. + check_gitlab_tokens -r /opt/bash-api-client/bash-api-client.sh + Set a custom gitlab config file -## Configuration - -The script needs to connect to the Gitlab API. -You need to create a token in a admin group to read all tokens of all projects. +``` -Put 2 bash variabbles into `/etc/icinga2/gitlab.cfg`: +## Example -```shell -GITLAB_API='https://gitlab.example.com/api/v4' -GITLAB_TOKEN='glpat-1234567890' -``` +The execution of `check_gitlab_tokens` returns -You can use another filename for this configuration - but then you need the parameter `-g <FILE>`to reference it. +* a status line with found tokens total, count of warning and critical +* one line per token with + * date of expiration + * status; one of OK, warning, critical based on number of days before expiring + * name of thwe token + * name of the project or group + * web link to the token page of the project or group -## Example +```text +OK: 16 Gitlab Tokens (max 395 days old) .. critical: 0 (10 days) .. warnings: 0 (30 days) -`check_gitlab_tokens -r /opt/rest-api-client/rest-api-client.sh` +2025-01-17 OK changelog - demoproject <https://gitlab.example.com/test/demoproject/-/settings/access_tokens> +2025-01-23 OK read_repo - demoproject <https://gitlab.example.com/test/demoproject/-/settings/access_tokens> +2025-03-14 OK api_token - admin <https://gitlab.example.com/admin/sysadminstuff/-/settings/access_tokens> +... +``` \ No newline at end of file