@@ -316,42 +316,79 @@ Next, create the Dockerfile.
316316 #! /bin/bash
317317 set -e
318318
319- if [ -z " ${AZP_URL} " ]; then
320- echo 1>&2 " error: missing AZP_URL environment variable"
321- exit 1
322- fi
319+ # Load a token either from the environment variable or by using the service principal credentials.
320+ load_azp_token () {
321+ # Always un-export AZP_CLIENTSECRET so it is never inherited by
322+ # child processes (e.g., agent job processes). It remains available
323+ # as a shell variable so that it can be used to generate a token.
324+ export -n AZP_CLIENTSECRET
325+
326+ if [ -n " $AZP_CLIENTID " ]; then
327+ if [ -z " $AZP_CLIENTSECRET " ]; then
328+ echo 1>&2 " error: AZP_CLIENTSECRET must be set when AZP_CLIENTID is used"
329+ exit 1
330+ fi
331+
332+ if [ -z " $AZP_TENANTID " ]; then
333+ echo 1>&2 " error: AZP_TENANTID must be set when AZP_CLIENTID is used"
334+ exit 1
335+ fi
336+
337+ echo " Using service principal credentials to get token"
338+ # Isolate Azure CLI state to a dedicated, restrictive directory to avoid
339+ # leaking cached credentials/tokens to subsequent pipeline job processes.
340+ export AZURE_CONFIG_DIR=" $( mktemp -d) "
341+ chmod 700 " $AZURE_CONFIG_DIR "
342+ az login --allow-no-subscriptions --service-principal --username " $AZP_CLIENTID " --password " $AZP_CLIENTSECRET " --tenant " $AZP_TENANTID "
343+ # adapted from https://learn.microsoft.com/en-us/azure/databricks/dev-tools/user-aad-token
344+ AZP_TOKEN=$( az account get-access-token --query accessToken --output tsv)
345+ # Log out and remove the isolated Azure CLI config directory to purge cached tokens.
346+ az logout --username " $AZP_CLIENTID " > /dev/null 2>&1 || true
347+ az account clear > /dev/null 2>&1 || true
348+ rm -rf " $AZURE_CONFIG_DIR "
349+ unset AZURE_CONFIG_DIR
350+ echo " Token retrieved"
351+ fi
323352
324- if [ -n " $AZP_CLIENTID " ]; then
325- echo " Using service principal credentials to get token"
326- az login --allow-no-subscriptions --service-principal --username " $AZP_CLIENTID " --password " $AZP_CLIENTSECRET " --tenant " $AZP_TENANTID "
327- # adapted from https://learn.microsoft.com/en-us/azure/databricks/dev-tools/user-aad-token
328- AZP_TOKEN=$( az account get-access-token --query accessToken --output tsv)
329- echo " Token retrieved"
330- fi
353+ if [ -z " ${AZP_TOKEN_FILE} " ]; then
354+ if [ -z " ${AZP_TOKEN} " ]; then
355+ echo 1>&2 " error: missing AZP_TOKEN environment variable"
356+ exit 1
357+ fi
331358
332- if [ -z " ${AZP_TOKEN_FILE} " ]; then
333- if [ -z " ${AZP_TOKEN} " ]; then
334- echo 1>&2 " error: missing AZP_TOKEN environment variable"
335- exit 1
359+ AZP_TOKEN_FILE=" $( dirname " $0 " ) /.token"
336360 fi
337361
338- AZP_TOKEN_FILE=" /azp/.token"
339- echo -n " ${AZP_TOKEN} " > " ${AZP_TOKEN_FILE} "
340- fi
341-
342- unset AZP_CLIENTSECRET
343- unset AZP_TOKEN
362+ if [ -n " ${AZP_TOKEN-} " ]; then
363+ echo -n " ${AZP_TOKEN} " > " ${AZP_TOKEN_FILE} "
364+ else
365+ if [ ! -r " ${AZP_TOKEN_FILE} " ]; then
366+ echo 1>&2 " error: AZP_TOKEN_FILE is not readable: ${AZP_TOKEN_FILE} "
367+ exit 1
368+ fi
369+ if [ ! -s " ${AZP_TOKEN_FILE} " ]; then
370+ echo 1>&2 " error: AZP_TOKEN_FILE is empty: ${AZP_TOKEN_FILE} "
371+ exit 1
372+ fi
373+ fi
344374
345- if [ -n " ${AZP_WORK} " ]; then
346- mkdir -p " ${AZP_WORK} "
347- fi
375+ # Unset the AZP_TOKEN environment variable to prevent it from being exposed.
376+ # At this point the token is only available in the file specified by AZP_TOKEN_FILE.
377+ unset AZP_TOKEN
378+ }
348379
380+ # Cleanup function to remove the agent configuration.
349381 cleanup () {
350382 trap " " EXIT
351383
352384 if [ -e ./config.sh ]; then
353385 print_header " Cleanup. Removing Azure Pipelines agent..."
354386
387+ # Ensure we have a new token if using service principal credentials, as the old one might have expired between the time it was waiting to run a job and now.
388+ if [ -n " $AZP_CLIENTID " ]; then
389+ load_azp_token
390+ fi
391+
355392 # If the agent has some running jobs, the configuration removal process will fail.
356393 # So, give it some time to finish the job.
357394 while true ; do
@@ -369,8 +406,20 @@ Next, create the Dockerfile.
369406 echo -e " \n${lightcyan} $1 ${nocolor} \n"
370407 }
371408
409+ if [ -z " ${AZP_URL} " ]; then
410+ echo 1>&2 " error: missing AZP_URL environment variable"
411+ exit 1
412+ fi
413+
414+ # Load the AZP token for initial setup.
415+ load_azp_token
416+
417+ if [ -n " ${AZP_WORK} " ]; then
418+ mkdir -p " ${AZP_WORK} "
419+ fi
420+
372421 # Let the agent ignore the token env variables
373- export VSO_AGENT_IGNORE=" AZP_TOKEN,AZP_TOKEN_FILE"
422+ export VSO_AGENT_IGNORE=" AZP_TOKEN,AZP_TOKEN_FILE,AZP_CLIENTSECRET "
374423
375424 print_header " 1. Determining matching Azure Pipelines agent..."
376425
0 commit comments