Skip to content

Commit 814d054

Browse files
DonLeeTejasri-Microsoft
authored andcommitted
fix(auth): resolve tenant from az cli, clear stale audiences, normalize issuer
Three fixes discovered during end-to-end azd up testing: 1. `az containerapp auth microsoft update` rejects `--issuer` and `--tenant-id` together; the issuer is derived from tenant-id. 2. `azd env get-value AZURE_TENANT_ID` prints its error message to stdout (not stderr), corrupting TENANT_ID when that key is absent. Read from `az account show` first instead. 3. `--allowed-token-audiences api://<clientId>` breaks EasyAuth login because the ID tokens it issues have `aud=<clientId>` (GUID), not the identifierUri. Drop the override and normalize `allowedAudiences` to just the clientId via an authConfig PUT (which also clears stale values left by prior runs and fixes `openIdIssuer` if it was previously corrupted). Verified: Web `/.auth/login/aad` -> 302 to login.microsoftonline.com with the correct client_id, redirect_uri, and scopes; API returns 401 to unauthenticated callers; allowedApplications on the API restricts callers to the Web clientId.
1 parent a58a99d commit 814d054

2 files changed

Lines changed: 76 additions & 50 deletions

File tree

infra/scripts/configure_auth.ps1

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ function Azd-Get($key, $default = "") {
2525
$EnvName = Azd-Get "AZURE_ENV_NAME" "cps"
2626
$ResourceGroup = Azd-Get "AZURE_RESOURCE_GROUP"
2727
$SubscriptionId = Azd-Get "AZURE_SUBSCRIPTION_ID"
28-
$TenantId = Azd-Get "AZURE_TENANT_ID"
29-
if (-not $TenantId) { $TenantId = (az account show --query tenantId -o tsv) }
28+
$TenantId = (az account show --query tenantId -o tsv)
29+
if (-not $TenantId) { $TenantId = Azd-Get "AZURE_TENANT_ID" "" }
30+
if (-not $TenantId) { throw "Could not resolve Azure tenant id. Run 'az login' or set AZURE_TENANT_ID." }
3031

3132
$WebName = Azd-Get "CONTAINER_WEB_APP_NAME"
3233
$WebFqdn = Azd-Get "CONTAINER_WEB_APP_FQDN"
@@ -217,18 +218,18 @@ Write-Host ""
217218
Write-Host "➡️ Step 5/6: Enabling EasyAuth on Web + API container apps"
218219
$Issuer = "https://login.microsoftonline.com/$TenantId/v2.0"
219220

220-
function Configure-EasyAuth($CaName, $ClientId, $Audience) {
221+
function Configure-EasyAuth($CaName, $ClientId) {
222+
# Note: --tenant-id and --issuer are mutually exclusive. Do not override
223+
# --allowed-token-audiences; EasyAuth issues ID tokens with aud=<client_id>.
221224
az containerapp auth microsoft update -n $CaName -g $ResourceGroup `
222225
--client-id $ClientId `
223226
--client-secret-name $CaSecretName `
224227
--tenant-id $TenantId `
225-
--issuer $Issuer `
226-
--allowed-token-audiences $Audience `
227228
--yes --output none
228229
}
229230

230-
Configure-EasyAuth $ApiName $ApiClientId $ApiIdentifierUri
231-
Configure-EasyAuth $WebName $WebClientId $WebIdentifierUri
231+
Configure-EasyAuth $ApiName $ApiClientId
232+
Configure-EasyAuth $WebName $WebClientId
232233

233234
az containerapp auth update -n $WebName -g $ResourceGroup --enabled true --unauthenticated-client-action AllowAnonymous --output none
234235
az containerapp auth update -n $ApiName -g $ResourceGroup --enabled true --unauthenticated-client-action AllowAnonymous --output none
@@ -243,25 +244,33 @@ az containerapp update -n $WebName -g $ResourceGroup `
243244
--output none
244245
Write-Host " ✓ Web env vars updated"
245246

246-
$authUrl = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.App/containerApps/$ApiName/authConfigs/current?api-version=2024-03-01"
247-
$current = az rest --method get --url $authUrl | ConvertFrom-Json
248-
if (-not $current.properties) { $current | Add-Member -MemberType NoteProperty -Name properties -Value (@{}) }
249-
if (-not $current.properties.identityProviders) { $current.properties | Add-Member -MemberType NoteProperty -Name identityProviders -Value (@{}) }
250-
if (-not $current.properties.identityProviders.azureActiveDirectory) { $current.properties.identityProviders | Add-Member -MemberType NoteProperty -Name azureActiveDirectory -Value (@{}) }
251-
$aad = $current.properties.identityProviders.azureActiveDirectory
252-
if (-not $aad.validation) { $aad | Add-Member -MemberType NoteProperty -Name validation -Value (@{}) }
253-
if (-not $aad.validation.defaultAuthorizationPolicy) { $aad.validation | Add-Member -MemberType NoteProperty -Name defaultAuthorizationPolicy -Value (@{}) }
254-
$policy = $aad.validation.defaultAuthorizationPolicy
255-
$allowed = @()
256-
if ($policy.allowedApplications) { $allowed = @($policy.allowedApplications) }
257-
if ($allowed -notcontains $WebClientId) { $allowed += $WebClientId }
258-
$policy.allowedApplications = $allowed
247+
function Patch-AuthConfig($CaName, $ClientId, $AddWebAllowed) {
248+
$url = "/subscriptions/$SubscriptionId/resourceGroups/$ResourceGroup/providers/Microsoft.App/containerApps/$CaName/authConfigs/current?api-version=2024-03-01"
249+
$current = az rest --method get --url $url | ConvertFrom-Json
250+
if (-not $current.properties) { $current | Add-Member -MemberType NoteProperty -Name properties -Value (@{}) }
251+
if (-not $current.properties.identityProviders) { $current.properties | Add-Member -MemberType NoteProperty -Name identityProviders -Value (@{}) }
252+
if (-not $current.properties.identityProviders.azureActiveDirectory) { $current.properties.identityProviders | Add-Member -MemberType NoteProperty -Name azureActiveDirectory -Value (@{}) }
253+
$aad = $current.properties.identityProviders.azureActiveDirectory
254+
if (-not $aad.registration) { $aad | Add-Member -MemberType NoteProperty -Name registration -Value (@{}) }
255+
$aad.registration.openIdIssuer = "https://login.microsoftonline.com/$TenantId/v2.0"
256+
if (-not $aad.validation) { $aad | Add-Member -MemberType NoteProperty -Name validation -Value (@{}) }
257+
$aad.validation.allowedAudiences = @($ClientId)
258+
if (-not $aad.validation.defaultAuthorizationPolicy) { $aad.validation | Add-Member -MemberType NoteProperty -Name defaultAuthorizationPolicy -Value (@{}) }
259+
$policy = $aad.validation.defaultAuthorizationPolicy
260+
$allowed = @()
261+
if ($policy.allowedApplications) { $allowed = @($policy.allowedApplications) }
262+
if ($AddWebAllowed -and ($allowed -notcontains $WebClientId)) { $allowed += $WebClientId }
263+
$policy.allowedApplications = $allowed
259264

260-
$tmp = New-TemporaryFile
261-
$current | ConvertTo-Json -Depth 20 | Out-File -FilePath $tmp -Encoding utf8
262-
Retry { az rest --method put --url $authUrl --headers "Content-Type=application/json" --body "@$tmp" | Out-Null }
263-
Remove-Item $tmp
264-
Write-Host " ✓ API 'allowed applications' includes Web client id"
265+
$tmp = New-TemporaryFile
266+
$current | ConvertTo-Json -Depth 20 | Out-File -FilePath $tmp -Encoding utf8
267+
Retry { az rest --method put --url $url --headers "Content-Type=application/json" --body "@$tmp" | Out-Null }
268+
Remove-Item $tmp
269+
}
270+
271+
Patch-AuthConfig $ApiName $ApiClientId $true
272+
Patch-AuthConfig $WebName $WebClientId $false
273+
Write-Host " ✓ authConfigs normalized (issuer, audiences, allowedApplications)"
265274

266275
az containerapp auth update -n $WebName -g $ResourceGroup --unauthenticated-client-action RedirectToLoginPage --output none
267276
az containerapp auth update -n $ApiName -g $ResourceGroup --unauthenticated-client-action Return401 --output none

infra/scripts/configure_auth.sh

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,14 @@ echo "============================================================"
2323
ENV_NAME="$(azd env get-value AZURE_ENV_NAME 2>/dev/null || echo "")"
2424
RESOURCE_GROUP="$(azd env get-value AZURE_RESOURCE_GROUP)"
2525
SUBSCRIPTION_ID="$(azd env get-value AZURE_SUBSCRIPTION_ID)"
26-
TENANT_ID="$(azd env get-value AZURE_TENANT_ID 2>/dev/null || az account show --query tenantId -o tsv)"
26+
TENANT_ID="$(az account show --query tenantId -o tsv)"
27+
if [[ -z "$TENANT_ID" ]]; then
28+
TENANT_ID="$(azd env get-value AZURE_TENANT_ID 2>/dev/null || true)"
29+
fi
30+
if [[ -z "$TENANT_ID" ]]; then
31+
echo "❌ Could not resolve Azure tenant id. Run 'az login' or set AZURE_TENANT_ID." >&2
32+
exit 1
33+
fi
2734

2835
WEB_NAME="$(azd env get-value CONTAINER_WEB_APP_NAME)"
2936
WEB_FQDN="$(azd env get-value CONTAINER_WEB_APP_FQDN)"
@@ -275,23 +282,21 @@ ensure_ca_secret_from_app_reg "$WEB_CLIENT_ID" "$WEB_NAME"
275282
echo ""
276283
echo "➡️ Step 5/6: Enabling EasyAuth on Web + API container apps"
277284

278-
OPENID_ISSUER="https://login.microsoftonline.com/${TENANT_ID}/v2.0"
279-
280285
configure_easyauth_app() {
281286
local ca_name="$1"
282287
local client_id="$2"
283-
local audience="$3"
288+
# Note: --tenant-id and --issuer are mutually exclusive; tenant-id derives
289+
# the v2.0 issuer automatically. Do not override --allowed-token-audiences;
290+
# EasyAuth issues ID tokens with aud=<client_id>, which is the default.
284291
az containerapp auth microsoft update -n "$ca_name" -g "$RESOURCE_GROUP" \
285292
--client-id "$client_id" \
286293
--client-secret-name "$CA_SECRET_NAME" \
287294
--tenant-id "$TENANT_ID" \
288-
--issuer "$OPENID_ISSUER" \
289-
--allowed-token-audiences "$audience" \
290295
--yes --output none
291296
}
292297

293-
configure_easyauth_app "$API_NAME" "$API_CLIENT_ID" "$API_IDENTIFIER_URI"
294-
configure_easyauth_app "$WEB_NAME" "$WEB_CLIENT_ID" "$WEB_IDENTIFIER_URI"
298+
configure_easyauth_app "$API_NAME" "$API_CLIENT_ID"
299+
configure_easyauth_app "$WEB_NAME" "$WEB_CLIENT_ID"
295300

296301
# Make sure auth is enabled and (temporarily) permissive so we can still push
297302
# env vars / verify deployment. Final lockdown happens at the end.
@@ -318,31 +323,43 @@ az containerapp update -n "$WEB_NAME" -g "$RESOURCE_GROUP" \
318323
--output none
319324
echo " ✓ Web env vars: APP_WEB_CLIENT_ID / APP_WEB_SCOPE / APP_API_SCOPE / APP_AUTH_ENABLED"
320325

321-
# Patch API authConfig: restrict to Web client id
322-
# (equivalent to portal "Allow requests from specific client applications")
323-
API_AUTHCONFIG_URL="/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.App/containerApps/${API_NAME}/authConfigs/current?api-version=2024-03-01"
324-
325-
CURRENT_AUTH_JSON="$(az rest --method get --url "$API_AUTHCONFIG_URL")"
326-
PATCHED_AUTH_JSON="$(echo "$CURRENT_AUTH_JSON" | python3 -c "
327-
import json, sys
328-
doc = json.load(sys.stdin)
329-
props = doc.setdefault('properties', {})
326+
# Patch both authConfigs:
327+
# - API: add Web client id to allowedApplications
328+
# - Both: reset allowedAudiences to only the clientId, normalize openIdIssuer
329+
patch_authconfig() {
330+
local ca_name="$1"
331+
local client_id="$2"
332+
local add_web_allowed="$3" # "true" / "false"
333+
local url="/subscriptions/${SUBSCRIPTION_ID}/resourceGroups/${RESOURCE_GROUP}/providers/Microsoft.App/containerApps/${ca_name}/authConfigs/current?api-version=2024-03-01"
334+
local cur patched
335+
cur="$(az rest --method get --url "$url")"
336+
patched="$(echo "$cur" | ADD_WEB="$add_web_allowed" WEB_CLIENT_ID="$WEB_CLIENT_ID" CLIENT_ID="$client_id" TENANT_ID="$TENANT_ID" python3 -c "
337+
import json, os, sys
338+
d = json.load(sys.stdin)
339+
props = d.setdefault('properties', {})
330340
idp = props.setdefault('identityProviders', {})
331341
aad = idp.setdefault('azureActiveDirectory', {})
342+
reg = aad.setdefault('registration', {})
343+
reg['openIdIssuer'] = f\"https://login.microsoftonline.com/{os.environ['TENANT_ID']}/v2.0\"
332344
val = aad.setdefault('validation', {})
345+
val['allowedAudiences'] = [os.environ['CLIENT_ID']]
333346
policy = val.setdefault('defaultAuthorizationPolicy', {})
334347
allowed = set(policy.get('allowedApplications') or [])
335-
allowed.add('${WEB_CLIENT_ID}')
348+
if os.environ['ADD_WEB'] == 'true':
349+
allowed.add(os.environ['WEB_CLIENT_ID'])
336350
policy['allowedApplications'] = sorted(allowed)
337-
print(json.dumps(doc))
351+
print(json.dumps(d))
338352
")"
353+
echo "$patched" > /tmp/authconfig_patch.json
354+
retry az rest --method put --url "$url" \
355+
--headers "Content-Type=application/json" \
356+
--body @/tmp/authconfig_patch.json >/dev/null
357+
rm -f /tmp/authconfig_patch.json
358+
}
339359

340-
echo "$PATCHED_AUTH_JSON" > /tmp/api_authconfig.json
341-
retry az rest --method put --url "$API_AUTHCONFIG_URL" \
342-
--headers "Content-Type=application/json" \
343-
--body @/tmp/api_authconfig.json >/dev/null
344-
rm -f /tmp/api_authconfig.json
345-
echo " ✓ API 'allowed applications' now includes Web client id"
360+
patch_authconfig "$API_NAME" "$API_CLIENT_ID" "true"
361+
patch_authconfig "$WEB_NAME" "$WEB_CLIENT_ID" "false"
362+
echo " ✓ authConfigs normalized (issuer, audiences, allowedApplications)"
346363

347364
# Final lockdown
348365
az containerapp auth update -n "$WEB_NAME" -g "$RESOURCE_GROUP" \

0 commit comments

Comments
 (0)