Skip to content

Commit aab6757

Browse files
author
Adir Atias
committed
fix: resolve ARM token resource from AZURE_AUTHORITY_HOST for sovereign cloud ACR auth
ArgoCD hardcodes the ARM token scope to the commercial endpoint (https://management.core.windows.net) when exchanging a Workload Identity access token for an ACR refresh token. On sovereign clouds, this causes 401 Unauthorized because the token audience does not match the cloud ARM resource. This change resolves the ARM token resource from AZURE_AUTHORITY_HOST, which is the only cloud-identifying env var injected by the AKS Workload Identity mutating webhook into workload pods. AZURE_ENVIRONMENT is NOT injected into pods (only into the webhook controller itself). Supported clouds: - Azure Public (login.microsoftonline.com) -> management.core.windows.net - Azure US Government (login.microsoftonline.us) -> management.core.usgovcloudapi.net - Azure China (login.partner.microsoftonline.cn) -> management.core.chinacloudapi.cn - Azure US Nat (login.microsoftonline.eaglex.ic.gov) -> management.core.eaglex.ic.gov - Azure US Sec (login.microsoftonline.microsoft.scloud) -> management.core.microsoft.scloud - Azure Bleu (login.sovcloud-identity.fr) -> management.sovcloud-api.fr - Azure Delos (login.sovcloud-identity.de) -> management.sovcloud-api.de AZURE_ARM_TOKEN_RESOURCE env var is preserved as an explicit override for backward compatibility and any unrecognized cloud environments. Signed-off-by: Adir Atias <adatias@microsoft.com>
1 parent f71239c commit aab6757

1 file changed

Lines changed: 51 additions & 2 deletions

File tree

util/helm/creds.go

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@ import (
99
"io"
1010
"net/http"
1111
"net/url"
12+
"os"
1213
"strings"
1314
"time"
1415

1516
"github.com/golang-jwt/jwt/v5"
17+
1618
gocache "github.com/patrickmn/go-cache"
1719
log "github.com/sirupsen/logrus"
1820

1921
argoutils "github.com/argoproj/argo-cd/v3/util"
20-
"github.com/argoproj/argo-cd/v3/util/env"
2122
"github.com/argoproj/argo-cd/v3/util/workloadidentity"
2223
)
2324

@@ -181,7 +182,7 @@ func (creds AzureWorkloadIdentityCreds) getAccessTokenAfterChallenge(ctx context
181182
realm := tokenParams["realm"]
182183
service := tokenParams["service"]
183184

184-
armTokenScope := env.StringFromEnv("AZURE_ARM_TOKEN_RESOURCE", "https://management.core.windows.net")
185+
armTokenScope := getARMTokenResource()
185186
armAccessToken, err := creds.tokenProvider.GetToken(armTokenScope + "/.default")
186187
if err != nil {
187188
return "", fmt.Errorf("failed to get Azure access token: %w", err)
@@ -292,3 +293,51 @@ func (creds AzureWorkloadIdentityCreds) challengeAzureContainerRegistry(ctx cont
292293

293294
return tokenParams, nil
294295
}
296+
297+
// getARMTokenResource returns the Azure Resource Manager token resource/audience
298+
// for the current cloud environment. This is needed for the ACR OAuth2 token
299+
// exchange (/oauth2/exchange) on sovereign clouds, where the ARM resource
300+
// differs from the commercial default.
301+
//
302+
// Resolution order:
303+
// 1. AZURE_ARM_TOKEN_RESOURCE env var (explicit override for any cloud)
304+
// 2. AZURE_AUTHORITY_HOST env var (injected by the AKS Workload Identity
305+
// mutating webhook into every labeled pod)
306+
// 3. Default: commercial (https://management.core.windows.net)
307+
func getARMTokenResource() string {
308+
// Allow explicit override for any cloud environment
309+
if v := os.Getenv("AZURE_ARM_TOKEN_RESOURCE"); v != "" {
310+
return v
311+
}
312+
313+
// Resolve from AZURE_AUTHORITY_HOST, which is injected by the AKS Workload
314+
// Identity webhook into pods labeled with azure.workload.identity/use: "true".
315+
// Note: AZURE_ENVIRONMENT is NOT injected into workload pods by the webhook,
316+
// only AZURE_AUTHORITY_HOST, AZURE_CLIENT_ID, AZURE_TENANT_ID, and
317+
// AZURE_FEDERATED_TOKEN_FILE are injected.
318+
// Ref: https://azure.github.io/azure-workload-identity/docs/installation/mutating-admission-webhook.html
319+
authorityHost := strings.TrimRight(os.Getenv("AZURE_AUTHORITY_HOST"), "/")
320+
switch authorityHost {
321+
// Azure US Government (FairFax, GCC)
322+
case "https://login.microsoftonline.us":
323+
return "https://management.core.usgovcloudapi.net"
324+
// Azure China (Mooncake)
325+
case "https://login.partner.microsoftonline.cn":
326+
return "https://management.core.chinacloudapi.cn"
327+
// Azure US Nat (USNat / EagleX)
328+
case "https://login.microsoftonline.eaglex.ic.gov":
329+
return "https://management.core.eaglex.ic.gov"
330+
// Azure US Sec (USSec)
331+
case "https://login.microsoftonline.microsoft.scloud":
332+
return "https://management.core.microsoft.scloud"
333+
// Azure Bleu (France sovereign)
334+
case "https://login.sovcloud-identity.fr":
335+
return "https://management.sovcloud-api.fr"
336+
// Azure Delos (Germany sovereign)
337+
case "https://login.sovcloud-identity.de":
338+
return "https://management.sovcloud-api.de"
339+
// Azure Public (Commercial) or unrecognized
340+
default:
341+
return "https://management.core.windows.net"
342+
}
343+
}

0 commit comments

Comments
 (0)