Skip to content

Commit 0663ab0

Browse files
committed
Improve token handling and cleanup in docker.md
Refactor token loading and cleanup functions in docker script. Fixes issue with this error during cleanup WRITE ERROR: VS30063: You are not authorized to access https://dev.azure.com. Also fixed issue with hard code AZP_TOKEN_FILE location being a hard coded path /azp/.token which may not exists. Changed it to use the same location as the script location.
1 parent 1fa9f5f commit 0663ab0

1 file changed

Lines changed: 74 additions & 25 deletions

File tree

docs/pipelines/agents/docker.md

Lines changed: 74 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)