Skip to content

Commit dee29b8

Browse files
committed
feat: add scrit to renew api-token for gitlab
Signed-off-by: sebastien.heurtematte <[email protected]>
1 parent c39de6a commit dee29b8

File tree

2 files changed

+288
-0
lines changed

2 files changed

+288
-0
lines changed

gitlab/gitlab_admin.sh

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,81 @@ create_api_token() {
227227
echo "${token}"
228228
}
229229

230+
check_api_token_validity() {
231+
local username="${1:-}"
232+
_check_parameter "username" "${username}"
233+
local user_id
234+
user_id="$(_get_id_from_username "${username}")"
235+
local name="CI token"
236+
237+
impersonation_tokens=$(curl -sSL --header "${TOKEN_HEADER}" \
238+
"${API_BASE_URL}/users/${user_id}/impersonation_tokens?per_page=100")
239+
240+
check_error=$(echo "$impersonation_tokens" | jq -c '.error' 2>/dev/null) || true
241+
if [[ -n "${check_error}" ]]; then
242+
echo "Error: ${check_error}" >&2
243+
exit 1
244+
fi
245+
246+
expired=true
247+
expires_at=""
248+
for token in $(echo "$impersonation_tokens" | jq -c '.[]'); do
249+
name=$(echo "$token" | jq -r '.name')
250+
if [ "$name" == "CI token" ]; then
251+
revoked=$(echo "$token" | jq -r '.revoked')
252+
active=$(echo "$token" | jq -r '.active')
253+
expires_at=$(echo "$token" | jq -r '.expires_at')
254+
255+
# echo "Revoked: $revoked - Active: $active - Expires at: $expires_at"
256+
257+
if [[ "$active" == "true" ]] && [[ "$revoked" == "false" ]]; then
258+
expired=false
259+
fi
260+
fi
261+
done
262+
if [ "$expired" == "true" ]; then
263+
echo "CI Token ${username}(${user_id}) expired or revoked: $expires_at"
264+
exit 1
265+
else
266+
echo "CI Token ${username}(${user_id}) is still valid, expired: $expires_at"
267+
fi
268+
}
269+
270+
revoke_api_token() {
271+
local username="${1:-}"
272+
_check_parameter "username" "${username}"
273+
local user_id
274+
user_id="$(_get_id_from_username "${username}")"
275+
local name="CI token"
276+
277+
impersonation_tokens=$(curl -sSL --header "${TOKEN_HEADER}" \
278+
"${API_BASE_URL}/users/${user_id}/impersonation_tokens?state=active&per_page=100")
279+
280+
check_error=$(echo "$impersonation_tokens" | jq -c '.error' 2>/dev/null) || true
281+
if [[ -n "${check_error}" ]]; then
282+
echo "Error: ${check_error}" >&2
283+
exit 1
284+
fi
285+
286+
for token in $(echo "$impersonation_tokens" | jq -c '.[]'); do
287+
name=$(echo "$token" | jq -r '.name')
288+
if [ "$name" == "CI token" ]; then
289+
id=$(echo "$token" | jq -r '.id')
290+
revoked=$(echo "$token" | jq -r '.revoked')
291+
active=$(echo "$token" | jq -r '.active')
292+
expires_at=$(echo "$token" | jq -r '.expires_at')
293+
294+
# echo "Revoked: $revoked - Active: $active - Expires at: $expires_at"
295+
296+
if [[ "$active" == "true" ]] && [[ "$revoked" == "false" ]]; then
297+
echo "Revoking token ${name}(${id}): $expires_at" >&2
298+
curl -sSL --request DELETE --header "${TOKEN_HEADER}" \
299+
"${API_BASE_URL}/users/${user_id}/impersonation_tokens/${id}"
300+
fi
301+
fi
302+
done
303+
}
304+
230305
create_bot_user() {
231306
local project_name="${1:-}"
232307
local username="${2:-}"

gitlab/gitlab_bot_token_renew.sh

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#!/usr/bin/env bash
2+
#*******************************************************************************
3+
# Copyright (c) 2024 Eclipse Foundation and others.
4+
# This program and the accompanying materials are made available
5+
# under the terms of the Eclipse Public License 2.0
6+
# which is available at http://www.eclipse.org/legal/epl-v20.html
7+
# SPDX-License-Identifier: EPL-2.0
8+
#*******************************************************************************
9+
10+
# Create bot user in GitLab and set up SSH key
11+
12+
# Bash strict-mode
13+
# set -o errexit
14+
set -o nounset
15+
set -o pipefail
16+
17+
IFS=$'\n\t'
18+
SCRIPT_FOLDER="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"
19+
CI_ADMIN_ROOT="${SCRIPT_FOLDER}/.."
20+
JIRO_ROOT_FOLDER="$("${CI_ADMIN_ROOT}/utils/local_config.sh" "get_var" "jiro-root-dir")"
21+
OTTERDOG_CONFIGS_ROOT="$("${CI_ADMIN_ROOT}/utils/local_config.sh" "get_var" "otterdog-configs-root-dir")"
22+
GITLAB_PASS_DOMAIN="gitlab.eclipse.org"
23+
24+
#shellcheck disable=SC1091
25+
source "${SCRIPT_FOLDER}/../pass/pass_wrapper.sh"
26+
#shellcheck disable=SC1091
27+
source "${SCRIPT_FOLDER}/../utils/common.sh"
28+
29+
set +o errexit
30+
31+
export VAULT_ADDR=${VAULT_ADDR:-https:\/\/secretsmanager.eclipse.org}
32+
export VAULT_AUTH_METHOD=${VAULT_AUTH_METHOD:-token}
33+
export VAULT_TOKEN=${VAULT_TOKEN:-""}
34+
35+
VAULT_MOUNT_PATH="cbi"
36+
37+
usage() {
38+
cat << EOF # remove the space between << and EOF, this is due to web plugin issue
39+
Usage: $(basename "${BASH_SOURCE[0]}") <project_id> [-h] [-v] [-f] [-t]
40+
41+
Renew GitLab API token for the bot user of the project <project_id> or all projects bots registered in the secretsmanager.
42+
43+
e.g:
44+
* gitlab_bot_token_renew.sh technology.cbi -f # Renew the token and update tools for the project technology.cbi
45+
* gitlab_bot_token_renew.sh -f # Renew the token and update tools for all projects bots registered in the secretsmanager
46+
47+
Available options:
48+
49+
-h Help
50+
-v Verbose mode
51+
52+
# Script params:
53+
-f FORCE_UPDATE: Force update token and tools for the project
54+
-t FORCE_TOOLS_UPDATE: Force update tools for the project
55+
56+
EOF
57+
exit
58+
}
59+
60+
FORCE_UPDATE=""
61+
FORCE_TOOLS_UPDATE=""
62+
PARAM=${1:-}
63+
64+
if [[ -n "${PARAM}" ]] && [[ "${PARAM}" =~ ^- ]]; then
65+
OPTIND=1
66+
else
67+
OPTIND=2
68+
fi
69+
70+
while getopts ":hvtf" option; do
71+
case $option in
72+
h) usage ;;
73+
v) set -x ;;
74+
f)
75+
FORCE_UPDATE="true"
76+
;;
77+
t)
78+
FORCE_TOOLS_UPDATE="true"
79+
;;
80+
:)
81+
echo "ERROR: the option -$OPTARG need an argument." >&2
82+
exit 1
83+
;;
84+
-?*) echo "Unknown option: $1" && exit 1 ;;
85+
*) break ;;
86+
esac
87+
done
88+
89+
if ! vault token lookup > /dev/null; then
90+
echo "Check your token validity and export VAULT_TOKEN"
91+
exit 1
92+
fi
93+
94+
if ! vault kv list -mount="${VAULT_MOUNT_PATH}" > /dev/null; then
95+
echo "Error accessing the secret mount: ${VAULT_MOUNT_PATH}}"
96+
exit 1
97+
fi
98+
99+
if [[ ${FORCE_UPDATE} == "true" ]]; then
100+
echo "WARN: Force update token and tools"
101+
fi
102+
if [[ ${FORCE_TOOLS_UPDATE} == "true" ]]; then
103+
echo "WARN: Force update tools"
104+
fi
105+
106+
# Renew all tokens for all projects registered in Vault
107+
renew_all_tokens() {
108+
projects=$(vault kv list -mount="${VAULT_MOUNT_PATH}" -format=json)
109+
if [ "$?" -ne 0 ]; then
110+
echo "ERROR: listing secrets at mount: ${VAULT_MOUNT_PATH}}"
111+
return 1
112+
fi
113+
for project in $(echo "${projects}" | jq -r '.[]'); do
114+
local project_id="${project%/}"
115+
renew_token "${project_id}"
116+
done
117+
}
118+
119+
# Check if the API token is still valid and renew it if necessary
120+
renew_token() {
121+
local project_id="${1:-}"
122+
echo "############### Check project: ${project_id} ###############"
123+
token=$(vault kv get -mount="${VAULT_MOUNT_PATH}" -field="api-token" "${project_id}/gitlab.eclipse.org" 2>/dev/null) || true
124+
[[ -z "$token" ]] && echo "No GitLab api token found for ${project_id}" && return
125+
126+
username=$(vault kv get -mount="${VAULT_MOUNT_PATH}" -field="username" "${project_id}/gitlab.eclipse.org" 2>/dev/null) || true
127+
if [[ "${FORCE_UPDATE}" == "true" ]]; then
128+
revoke_token "${project_id}" "${username}"
129+
create_token "${project_id}" "${username}"
130+
update_tools "${project_id}"
131+
return
132+
fi
133+
if "${SCRIPT_FOLDER}/gitlab_admin.sh" check_api_token_validity "${username}"; then
134+
if [[ -z "${FORCE_TOOLS_UPDATE}" ]]; then
135+
update_tools_answer=$(_question_true_false "Force update tools for ${project_id}")
136+
if [[ "${update_tools_answer}" == "true" ]];then
137+
update_tools "${project_id}"
138+
fi
139+
elif [[ "${FORCE_TOOLS_UPDATE}" == "true" ]]; then
140+
update_tools "${project_id}"
141+
else
142+
echo "No tools update for ${project_id}"
143+
fi
144+
else
145+
create_token "${project_id}" "${username}"
146+
update_tools "${project_id}"
147+
fi
148+
}
149+
150+
update_tools() {
151+
local project_id="${1:-}"
152+
if [[ -z "${project_id}" ]]; then
153+
echo "No project_id provided"
154+
return 1
155+
fi
156+
update_jenkins "${project_id}"
157+
update_otterdog "${project_id}"
158+
}
159+
160+
# Create a new API token for the bot user
161+
create_token() {
162+
local project_id="${1:-}"
163+
local username="${2:-}"
164+
echo "####### Create API token for project ${project_id} and user ${username} #######"
165+
token="$("${SCRIPT_FOLDER}/gitlab_admin.sh" "create_api_token" "${username}")"
166+
echo "Adding API token to pass: bots/${project_id}/${GITLAB_PASS_DOMAIN}/api-token"
167+
echo "${token}" | passw cbi insert --echo "bots/${project_id}/${GITLAB_PASS_DOMAIN}/api-token"
168+
}
169+
170+
revoke_token() {
171+
local project_id="${1:-}"
172+
local username="${2:-}"
173+
echo "####### Revoke API token for project ${project_id} and user ${username} #######"
174+
"${SCRIPT_FOLDER}/gitlab_admin.sh" "revoke_api_token" "${username}"
175+
}
176+
177+
# Update Jenkins configuration
178+
update_jenkins() {
179+
local project_id="${1:-}"
180+
echo "####### Update Jenkins configuration for ${project_id} #######"
181+
if [[ -d "${JIRO_ROOT_FOLDER}/instances/${project_id}" ]]; then
182+
echo "Recreate token in Jenkins instance for ${project_id}"
183+
"${JIRO_ROOT_FOLDER}/jenkins-create-credentials-token.sh" "gitlab" "${project_id}"
184+
"${JIRO_ROOT_FOLDER}/jenkins-create-credentials-token.sh" "gitlab_pat" "${project_id}"
185+
else
186+
echo "WARN: No Jenkins instance found for ${project_id}"
187+
fi
188+
}
189+
190+
# Update Otterdog configuration
191+
update_otterdog() {
192+
local project_id="${1:-}"
193+
echo "####### Update Otterdog configuration for ${project_id} #######"
194+
pushd "${OTTERDOG_CONFIGS_ROOT}" > /dev/null
195+
otterdog_conf=$(jq --arg project_id "$project_id" '.organizations[] | select(.name == $project_id)' < otterdog.json)
196+
if [[ -n "${otterdog_conf}" ]]; then
197+
github_id=$(echo "$otterdog_conf" | jq -r '.github_id')
198+
echo "Update api token with Otterdog for ${project_id}(${github_id})"
199+
PASSWORD_STORE_DIR="$("${SCRIPT_FOLDER}/../utils/local_config.sh" "get_var" "cbi-dir" "password-store")"
200+
export PASSWORD_STORE_DIR
201+
otterdog fetch-config -f "${github_id}"
202+
otterdog apply -f "${github_id}" -n --update-secrets --update-filter "*GITLAB_API_TOKEN"
203+
else
204+
echo "WARN: No Otterdog configuration found for ${project_id}"
205+
fi
206+
popd > /dev/null
207+
}
208+
209+
if [[ -z "${PARAM}" || "${PARAM}" =~ ^- ]]; then
210+
renew_all_tokens
211+
else
212+
renew_token "${PARAM}"
213+
fi

0 commit comments

Comments
 (0)