From cc1fd098057d1326cdb333bef9834895fa0925e5 Mon Sep 17 00:00:00 2001
From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch>
Date: Fri, 25 Oct 2024 17:13:01 +0200
Subject: [PATCH] WIP check gitlab tokens

---
 check_gitlab_tokens | 237 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 237 insertions(+)
 create mode 100755 check_gitlab_tokens

diff --git a/check_gitlab_tokens b/check_gitlab_tokens
new file mode 100755
index 0000000..9b4ca1f
--- /dev/null
+++ b/check_gitlab_tokens
@@ -0,0 +1,237 @@
+#!/bin/bash
+# ======================================================================
+#
+# Check Gitlab tokens
+#
+# requirements:
+# - inc/rest-api-client.sh
+# - curl
+#
+# ----------------------------------------------------------------------
+# 2024-10-25  v0.0  <axel.hahn@iml.unibe.ch>
+# ======================================================================
+
+
+cd "$( dirname "$0" )" || exit
+
+. "$( dirname $0 )/inc_pluginfunctions" || exit 1
+
+export self_APPVERSION=0.1
+
+GITLAB_API='https://gitlab.example.com/api/v4'
+GITLAB_TOKEN='glpat-12345678'
+
+GITLAB_API='https://git-repo.iml.unibe.ch/api/v4'
+GITLAB_TOKEN='glpat-4Lh6j_aJv7b6zVsRxyXF'
+
+GITLAB_CONFIG=/etc/icinga2/gitlab.cfg
+REST_CLIENT="$( dirname $0 )/../inc/rest-api-client.sh"
+
+typeset -i iSince=395
+typeset -i iTokenCount
+typeset -i iTokensFound
+NL="
+"
+
+typeset -i iWarnLimit=300
+typeset -i iCriticalLimit=200
+
+typeset -i iCountWarn=0
+typeset -i iCountCritical=0
+output=""
+
+# ----------------------------------------------------------------------
+# functions
+# ----------------------------------------------------------------------
+
+
+function showHelp(){
+    local _self; _self=$(basename $0)
+cat <<EOF
+$( ph.showImlHelpHeader )
+
+Check gitlab tokens and warn if a token expires soon.
+
+This check fetches the gitlbab tokens created in the last $iSince days
+from the Gitlab API. It skips
+
+    - personal access tokens of users
+    - revoked tokens
+
+SYNTAX:
+$_self [-w WARN_LIMIT] [-c CRITICAL_LIMIT]
+
+OPTIONS:
+
+    -h or --help   show this help.
+
+    -w VALUE       warning level  (default: $iWarnLimit)
+    -c VALUE       critical level (default: $iCriticalLimit)
+
+    -g FILE        path to GITLAB_CONFIG; default: $GITLAB_CONFIG
+    -r FILE        path to REST_CLIENT; default: $REST_CLIENT
+
+    -s DAYS        Number of days for max age of token; default: $iSince
+
+PARAMETERS:
+
+    None.
+
+EXAMPLE:
+    $(basename $0) -w 28 -c 7
+
+EOF
+}
+
+# Ffetch data from gitlab api with page requests
+# param  string  url
+# param  string  output file
+# param  int     optional: number of items per page; default: 100
+function _getPagesToFile(){
+    local url="$1"
+    local outfile="$2"
+    local iPerPage=${3:-100}
+    local page=0
+
+    test -f "${outfile}" && rm "${outfile}"
+
+    grep -q "?" <<< "$url" || url="${url}?"
+    while true; do
+        (( page++ ))
+
+        pageUrl="$url&per_page=${iPerPage}&page=${page}"
+        # echo "Request: $pageUrl"
+
+        http.makeRequest "$pageUrl"
+        if ! http.isOk > /dev/null; then
+            echo "ERROR: Request failed: $pageUrl"
+            http.getResponseHeader
+            http.getResponse
+            exit 1
+        fi
+
+        # if response is "[]" then we are done
+        if ! http.getResponse | grep -q "^\[\]$"; then
+            http.getResponse >> "${outfile}"
+        else
+            break
+        fi
+
+    done
+}
+
+function getKey(){
+    echo "$1" | jq -r ".$2" | grep -v "null"
+}
+
+# ----------------------------------------------------------------------
+# MAIN
+# ----------------------------------------------------------------------
+
+# --- check param -h
+case "$1" in
+    "--help"|"-h")
+        showHelp
+        exit 0
+        ;;
+    *)
+esac
+
+REST_CLIENT=$(   ph.getValueWithParam $REST_CLIENT   r "$@")
+GITLAB_CONFIG=$( ph.getValueWithParam $GITLAB_CONFIG g "$@")
+
+# --- check requirements
+ph.require curl
+. "${GITLAB_CONFIG}" || exit 1
+. "${REST_CLIENT}" || exit 1
+http.help >/dev/null || exit 1
+
+
+iWarnLimit=$(     ph.getValueWithParam $iWarnLimit     w "$@")
+iCriticalLimit=$( ph.getValueWithParam $iCriticalLimit c "$@")
+iSince=$(         ph.getValueWithParam $iSince         s "$@")
+
+http.init
+http.addHeader "PRIVATE-TOKEN: $GITLAB_TOKEN"
+http.setBaseUrl "$GITLAB_API"
+
+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
+
+
+# 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
+
+iTokensFound=0
+
+for i in $( seq 1 $iTokenCount )
+do
+
+    # get nth token
+    entry="$( cat /tmp/gitlab-tokens.json | jq ".[$i]" )"
+
+    # hide non active tokens
+    if [ "$( getKey "$entry" "active" )" = "false" ]; then
+        continue
+    fi
+
+    # hide tokens without name
+    sName=$( getKey "$entry" "name" )
+    if [ -z "$sName" ]; then
+        continue
+    fi
+
+    # 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 '"') "
+    if ! grep -q "_[0-9]*_bot" <<< "$myusername" ; then
+        continue
+    fi
+
+    iTokensFound+=1
+
+    # check expiration
+    sExpire=$( getKey "$entry" "expires_at" )
+
+    # remove "-" from date to get an integer
+    sExpire2=${sExpire//\-}
+
+    
+    sStatus="OK      "
+    if [ "$sExpire2" -le "$sDateWarn" ]; then
+        if [ "$sExpire2" -le "$sDateCritical" ]; then
+            iCountCritical+=1
+            sStatus="Critical"
+        else
+            iCountWarn+=1
+            sStatus="Warning "
+        fi
+    fi
+
+    output+="$sExpire $sStatus $sName $myusername${NL}" 
+
+done 
+
+if [ $iCountCritical -gt 0 ]; then
+    ph.setStatus "critical"
+elif [ $iCountWarn -gt 0 ]; then
+    ph.setStatus "warning"
+else
+    ph.setStatus "ok"
+fi
+
+ph.status "$iTokensFound Gitlab Tokens (max $iSince days old) .. critical: $iCountCritical ($iCriticalLimit days) .. warnings: $iCountWarn ($iWarnLimit days)"
+echo
+
+echo "$output"
+rm -f /tmp/gitlab-tokens.json /tmp/gitlab-users.json
\ No newline at end of file
-- 
GitLab