Last active
January 6, 2023 20:29
-
-
Save TJM/028ca421068d518f943685dffc828df4 to your computer and use it in GitHub Desktop.
Handle Artifactory License through script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
############################################################################ | |
# shell script for applying license bucket and licenses to an Artifactory # | |
# deployment. # | |
# # | |
# Author: Andrew Milam <[email protected]> # | |
# # | |
# WARNING: This script is designed as a terraform shell_script resource! # | |
# Use otherwise at your own peril! # | |
# # | |
# Globals # | |
# Required: # | |
# url - artifactory base url # | |
# workspace - terraform workspace # | |
# bucket_id - license bucket id, will be in license file name # | |
# bucket_name - name of the bucket # | |
# license_key - key used by artifactory to decrypt the license # | |
# secrets_project_id - project id where secrets are stored # | |
# admin_password - artifactory admin password # | |
# license_count - license count to apply from bucket # | |
# secret_version - version of the secret in google secrets manager # | |
############################################################################ | |
# required variables | |
: "${url:?}" | |
: "${workspace:?}" | |
: "${bucket_id:?}" | |
: "${bucket_name:?}" | |
: "${license_key:?}" | |
: "${secrets_project_id:?}" | |
: "${admin_password:?}" | |
: "${license_count:?}" | |
: "${secret_version:?}" | |
user="tf-$workspace-$(date '+%y-%m-%d-%H%M%S')" | |
file="${bucket_id}.json" | |
# function that retries other functions x amount of times, x=$1 | |
retry() { | |
tries=$1 | |
shift | |
while ! result=$("$@") && [ "$tries" -gt 0 ]; do | |
tries=$((tries - 1)) | |
if [ "$tries" -le 0 ]; then | |
echo "Deadline exceeded" >&2 | |
return 1 | |
fi | |
echo "Retrying in 5 seconds" >&2 | |
sleep 5 | |
done | |
echo "$result" | |
} | |
# get the encrypted license file from google secrets manager | |
getSecret() { | |
gcloud secrets versions access "$secret_version" --secret "artifactory-license-file" --project "$secrets_project_id" --format='get(payload.data)' | tr '_-' '/+' | base64 --decode > "$file" | |
} | |
# login function | |
login() { | |
curl "https://$url/ui/api/v1/ui/auth/login" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--cookie-jar cookiejar \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Accept-Encoding: gzip, deflate, br' \ | |
--header 'Content-Type: application/json' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--data-raw "{\"user\":\"admin\",\"password\":\"$admin_password\",\"type\":\"login\"}" | |
} | |
# function to get admin access token | |
getToken() { | |
curl "https://$url/ui/api/v1/access/token/scoped?expiry=24&services[]=all&scope=applied-permissions%2Fadmin&username=$user" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
-b cookiejar \ | |
--globoff \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Accept-Encoding: gzip, deflate, br' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--header 'Connection: keep-alive' | |
} | |
# function to apply enterprise license bucket | |
applyBucket() { | |
curl "https://$url/mc/api/v1/buckets" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--header "Authorization: Bearer $1" \ | |
--header 'Content-Type: multipart/form-data' \ | |
--form "file=@./$file;type=application/octet-stream" \ | |
--form "key=$2" \ | |
--form "name=$3" | |
} | |
# function to check license count applied to the deployment | |
checkForLicenses() { | |
curl "https://$url/mc/api/v1/buckets" --silent --fail --show-error --location --header "Authorization: Bearer $1" | |
} | |
# function to check license count applied to the deployment | |
getLicenseCount() { | |
curl "https://$url/mc/api/v1/buckets/$bucket_id/report" --silent --fail --show-error --location --header "Authorization: Bearer $1" | |
} | |
# function to get the Artifactory deployment ID | |
getJpd() { | |
curl "https://$url/mc/api/v1/jpds" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--header "Authorization: Bearer $1" \ | |
--header 'Accept: application/json' | jq -r '.[]?| .id' | |
} | |
# function to apply license(s) from the bucket to the Artifactory deployment | |
applyLicense() { | |
curl "https://$url/mc/api/v1/buckets/$bucket_id/deploy" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--header "Authorization: Bearer $1" \ | |
--header 'Accept: application/json' \ | |
--header 'Content-Type: application/json' \ | |
--data-raw "{\"jpd_id\" : \"$2\",\"license_count\" : \"$3\"}" | |
} | |
removeBucket() { | |
curl -X DELETE "https://$url/mc/api/v1/buckets/$2" \ | |
--silent \ | |
--fail \ | |
--show-error \ | |
--location \ | |
--header "Authorization: Bearer $1" | |
} | |
# function to revoke the admin access token | |
revokeToken() { | |
# revoke the token when complete | |
curl -b cookiejar "https://$url/ui/api/v1/ui/admin/security/accesstokens/revokeTokens" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Content-Type: application/json' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--data-raw "[\"$1\"]" | |
} | |
main() { | |
echo "getting license file from google secrets manager" | |
retry 5 getSecret || { | |
echo "Failed to get secrets from Google Secrets Manager" >&2 | |
return 1 | |
} | |
# login to artifactory | |
echo "logging in" | |
retry 60 login || { | |
echo "Failed to login to Artifactory" >&2 | |
return 1 | |
} | |
# set variable to output from getToken function call | |
echo "generating artifactory admin access token" | |
payload=$(retry 60 getToken) || { | |
echo "Failed to get admin access token" >&2 | |
return 1 | |
} | |
# set variables from payload for usage and token revokaction | |
echo "getting token id" | |
token_id=$(echo "$payload" | jq -r '.token_id') || { | |
echo "Failed to get access token token_id" | |
return 1 | |
} | |
echo "getting access token" | |
access_token=$(echo "$payload" | jq -r '.access_token') || { | |
echo "Failed to get access_token" | |
return 1 | |
} | |
echo "checking if a bucket is already applied" | |
bucket_object=$(retry 60 checkForLicenses "$access_token") || { | |
echo "Failed to check for existing buckets" >&2 | |
return 1 | |
} | |
# if its present, grabs current bucket from artifactory for comparison potentially new value passed in | |
current_bucket_id=$(echo "$bucket_object"| jq -r '.[]?| .identifier') | |
current_bucket_name=$(echo "$bucket_object"| jq -r '.[]?| .name') | |
# if the current bucket is equal to the value passed in, or if empty | |
if [[ "$current_bucket_id" == "$bucket_id" ]] || [[ -z "$current_bucket_id" ]]; | |
then | |
# apply enterprise license bucket to artifactory | |
echo "applying bucket" | |
retry 60 applyBucket "$access_token" "$license_key" "$bucket_name" || { | |
echo "failed to attach bucket" >&2 | |
return 1 | |
} | |
# checks to see if there are any licenses applied from the bucket to the artifactory deployment | |
echo "checking for applied licenses" | |
license=$(retry 60 getLicenseCount "$access_token" | jq -r '.jpds[]?| .license_count') || { | |
echo "Failed to check number of licenses" >&2 | |
return 1 | |
} | |
# set default to 0 if null | |
license_check=${license:="0"} # if null, sets the default to 0 | |
# if the license_check is greater than or equal to the desired desired license_count | |
if [[ $license_check -ge $license_count ]]; then | |
echo "license already applied, skipping" >&2 | |
else | |
# get artifactory deployment | |
echo "getting the artifactory deployment id" | |
jpd=$(retry 60 getJpd "$access_token") || { | |
echo "Failed to retrieve Artifactory JPD" >&2 | |
return 1 | |
} | |
# increment the license | |
increment=$((license_count - license_check)) | |
echo "applying $increment licenses from bucket" | |
retry 60 applyLicense "$access_token" "$jpd" "$increment" || { | |
echo "Failed to attach license to Aritfactory Deployment" >&2 | |
return 1 | |
} | |
fi | |
else | |
# if the bucket needs to be updated | |
echo "current bucket is $current_bucket_id" | |
echo "new bucket id passed in is $bucket_id" | |
echo "bucket needs to be updated" | |
# get artifactory deployment | |
echo "getting the artifactory deployment id" | |
jpd=$(retry 60 getJpd "$access_token") || { | |
echo "Failed to retrieve Artifactory JPD" >&2 | |
return 1 | |
} | |
# apply updated enterprise license bucket to artifactory | |
echo "applying new bucket $bucket_name" | |
retry 60 applyBucket "$access_token" "$license_key" "$bucket_name" || { | |
echo "failed to attach bucket" >&2 | |
return 1 | |
} | |
# apply licenses from bucket | |
echo "applying $license_count licenses from bucket to $jpd" | |
retry 60 applyLicense "$access_token" "$jpd" "$license_count" || { | |
echo "Failed to attach license to Aritfactory Deployment" >&2 | |
return 1 | |
} | |
# remove the old bucket | |
echo "removing previous bucket $current_bucket_name" | |
retry 60 removeBucket "$access_token" "$current_bucket_name" || { | |
echo "Failed to remove previous bucket" | |
return 1 | |
} | |
fi | |
# revoke the token | |
echo "revoking access token" | |
retry 60 revokeToken "$token_id" || { | |
echo "Failed to revoke access token" >&2 | |
return 1 | |
} | |
} | |
main "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
set -e | |
############################################################################ | |
# shell script for getting an admin access token from Artifactory # | |
# NOTE: This shell script uses undocumented "UI" API Access # | |
# # | |
# Author: Tommy McNeely <[email protected]> # | |
# # | |
# WARNING: This script is designed as a test script! # | |
# Use otherwise at your own peril! # | |
# # | |
# Globals (env variables) # | |
# ARTIFACTORY_URL - artifactory base url # | |
# ARTIFACTORY_USERNAME - artifactory admin username # | |
# ARTIFACTORY_PASSWORD - artifactory admin password # | |
# TOKEN_USERNAME - generated token username $ | |
############################################################################ | |
# defaulted variables | |
ARTIFACTORY_URL="${ARTIFACTORY_URL:-http://localhost:8082}" | |
ARTIFACTORY_USERNAME="${ARTIFACTORY_USERNAME:-admin}" | |
ARTIFACTORY_PASSWORD="${ARTIFACTORY_PASSWORD:-password}" | |
TOKEN_USERNAME="${user:-admin-$(date '+%Y-%m-%d-%H%M%S')}" | |
# function that retries other functions x amount of times, x=$1 | |
retry() { | |
tries=$1 | |
shift | |
while ! result=$("$@") && [ "$tries" -gt 0 ]; do | |
tries=$((tries - 1)) | |
if [ "$tries" -le 0 ]; then | |
echo "Deadline exceeded" >&2 | |
return 1 | |
fi | |
echo "Retrying in 5 seconds" >&2 | |
sleep 5 | |
done | |
echo "$result" | |
} | |
# login function | |
login() { | |
curl "${ARTIFACTORY_URL}/ui/api/v1/ui/auth/login" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--cookie-jar cookiejar \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Accept-Encoding: gzip, deflate, br' \ | |
--header 'Content-Type: application/json' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--data-raw "{\"user\":\"${ARTIFACTORY_USERNAME}\",\"password\":\"${ARTIFACTORY_PASSWORD}\",\"type\":\"login\"}" | |
} | |
# function to get admin access token | |
getToken() { | |
curl "${ARTIFACTORY_URL}/ui/api/v1/access/token/scoped?expiry=24&services[]=all&scope=applied-permissions%2Fadmin&username=${TOKEN_USERNAME}" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--cookie cookiejar \ | |
--globoff \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Accept-Encoding: gzip, deflate, br' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--header 'Connection: keep-alive' | |
} | |
# function to revoke the admin access token | |
revokeToken() { | |
# revoke the token when complete | |
curl "${ARTIFACTORY_URL}/ui/api/v1/ui/admin/security/accesstokens/revokeTokens" \ | |
--fail \ | |
--silent \ | |
--show-error \ | |
--location \ | |
--cookie cookiejar \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Content-Type: application/json' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--data-raw "[\"$1\"]" | |
} | |
# login to artifactory | |
echo "Logging in to Artifactory (${ARTIFACTORY_URL}) as ${ARTIFACTORY_USERNAME} ..." >&2 | |
retry 60 login >&2 || { | |
echo "Failed to login to Artifactory" >&2 | |
return 1 | |
} | |
# set variable to output from getToken function call | |
echo "Generating artifactory admin access token." >&2 | |
payload=$(retry 60 getToken) || { | |
echo "Failed to get admin access token" >&2 | |
return 1 | |
} | |
# set variables from payload for usage and token revokaction | |
# token_id=$(echo "$payload" | jq -r '.token_id') || { | |
# echo "Failed to get access token token_id" >&2 | |
# return 1 | |
# } | |
access_token=$(echo "$payload" | jq -r '.access_token') || { | |
echo "Failed to get access_token" >&2 | |
return 1 | |
} | |
echo $access_token | |
# revoke the token | |
# echo "revoking access token" >&2 | |
# retry 60 revokeToken "$token_id" || { | |
# echo "Failed to revoke access token" >&2 | |
# return 1 | |
# } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
before_script: | |
# Variables can't do transformations, so this script converts the branch name into a terraform workspace | |
- export TF_WORKSPACE=$(test "$CI_COMMIT_REF_SLUG" = master && echo default || echo "$CI_COMMIT_REF_SLUG") | |
- export TF_VAR_bucket=$TF_STATE_BUCKET | |
- | | |
set -e | |
if test -z "$TF_VAR_google_oauth_access_token"; then | |
TF_VAR_google_oauth_access_token=$(gcloud auth application-default print-access-token) | |
export TF_VAR_google_oauth_access_token | |
fi | |
- | # login to artifactory | |
set -e | |
echo "logging into artifactory" | |
curl "https://$ARTIFACTORY_URL/ui/api/v1/ui/auth/login" \ | |
--retry 5 \ | |
--cookie-jar cookiejar \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Accept-Encoding: gzip, deflate, br' \ | |
--header 'Content-Type: application/json' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--data-raw "{\"user\":\"admin\",\"password\":\"$ADMIN_PASSWORD\",\"type\":\"login\"}" | |
- | # create admin bearer token and set terraform variable from output to create jfrog resources | |
set -e | |
echo "creating artifactory admin token for jfrog providers to use" | |
payload=$(curl "https://$ARTIFACTORY_URL/ui/api/v1/access/token/scoped?expiry=24&services[]=all&scope=applied-permissions%2Fadmin&username=admin-$CI_COMMIT_REF_SLUG" \ | |
-b cookiejar \ | |
--globoff \ | |
--header 'Accept: application/json, text/plain, */*' \ | |
--header 'Accept-Encoding: gzip, deflate, br' \ | |
--header 'X-Requested-With: XMLHttpRequest' \ | |
--header 'Connection: keep-alive') | |
token_id=$(echo $payload| jq -r '.token_id') | |
- export TF_VAR_artifactory_access_token=$(echo $payload| jq -r '.access_token') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment