Use renewable Azure CLI authentication for Helix - #17592
missymessa wants to merge 16 commits into
Conversation
Resolve the configured Helix service connection to its endpoint GUID and forward the resolved client, tenant, and endpoint IDs to renewable AzurePipelinesCredential authentication for Helix submissions and monitoring. AB#12269 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b83ddd94-a1da-4c3c-aead-1d1643a6b83f
There was a problem hiding this comment.
🟡 Changes recommended
The documentation’s Helix Job Monitor example still instructs using a service connection ID for azureSubscription, which conflicts with the updated templates expecting a service connection name (resolved to endpoint GUID).
Get a fresh assessment by requesting another Copilot review.
Pull request overview
This PR updates Arcade’s Azure DevOps Helix templates to rely on the resolved service connection (endpoint) GUID provided by AzureCLI@2 for Entra/WIF authentication, so AzurePipelinesCredential can request OIDC assertions from the correct issuer during long-running Helix operations.
Changes:
- Capture
AZURESUBSCRIPTION_CLIENT_ID,AZURESUBSCRIPTION_TENANT_ID, and the resolvedAZURESUBSCRIPTION_SERVICE_CONNECTION_IDfromAzureCLI@2, and forward them to Helix submission/monitor processes. - Update template parameter documentation/comments to clarify that the input is the service connection name (resolved to endpoint GUID by Azure DevOps for
AzureCLI@2). - Extend Helix sending documentation with the WIF/endpoint-ID rationale.
File summaries
| File | Description |
|---|---|
| eng/common/core-templates/steps/send-to-helix.yml | Uses AzureCLI@2-provided resolved endpoint GUID and forwards it (plus client/tenant IDs) to Helix submission. |
| eng/common/core-templates/job/helix-job-monitor.yml | Applies the same resolved endpoint GUID forwarding for the standalone Helix Job Monitor flow. |
| Documentation/AzureDevOps/SendingJobsToHelix.md | Documents the WIF requirement and the endpoint-ID forwarding rationale for Entra authentication. |
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Use the workload identity federation service connection name consistently in both examples. AB#12269 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b83ddd94-a1da-4c3c-aead-1d1643a6b83f
There was a problem hiding this comment.
🔵 Needs a closer look
It changes authentication/identity propagation in widely-consumed Azure DevOps core templates, so a final human review is warranted to mitigate rollout risk despite the changes appearing coherent and opt-in.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Lite
mmitche
left a comment
There was a problem hiding this comment.
I don't think this works. Without addSSponToEnvironment, those variables will not be available AFAIK
|
Yup, the test build I ran came back as a failure: https://dev.azure.com/dnceng/internal/_build/results?buildId=3080543&view=results Going to move this to draft until I can validate the changes work. |
There was a problem hiding this comment.
🔵 Needs a closer look
It changes shared Helix authentication behavior in core pipeline templates, which is high-impact and warrants final human validation across real AzDO WIF configurations.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 0 new
- Review effort level: Lite
Keep Helix submission and monitoring inside AzureCLI@2 so Microsoft Entra-issued service connections use the task's renewable Azure CLI session instead of the legacy-issuer OIDC endpoint. AB#12269 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40ffbc91-7138-4298-b61c-73a788185f11
There was a problem hiding this comment.
🟡 Changes recommended
The implementation unsets AZURESUBSCRIPTION_* variables (disabling the AzurePipelinesCredential path) which conflicts with the PR description’s stated approach and needs reconciliation for correctness/maintainability.
Get a fresh assessment by requesting another Copilot review.
Review details
- Files reviewed: 3/3 changed files
- Comments generated: 2
- Review effort level: Lite
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40ffbc91-7138-4298-b61c-73a788185f11
There was a problem hiding this comment.
🔵 Needs a closer look
Template behavior and inline comments around clearing/passing AZURESUBSCRIPTION_* need clarification/alignment to avoid maintainer confusion and apparent mismatch with the PR’s stated intent.
Review details
Suppressed comments (2)
eng/common/core-templates/steps/send-to-helix.yml:54
- The inline script clears AZURESUBSCRIPTION_* variables without any explanation. Since these variables are also the inputs that enable AzurePipelinesCredential, this behavior is non-obvious and easy to accidentally undo during future edits (and it also appears to conflict with the PR description’s mention of passing resolved IDs through). Add a short comment explaining that this is intentional to force DefaultIdentityTokenCredential to use the Azure CLI session maintained by AzureCLI@2.
inlineScript: |
Remove-Item Env:AZURESUBSCRIPTION_CLIENT_ID -ErrorAction SilentlyContinue
Remove-Item Env:AZURESUBSCRIPTION_TENANT_ID -ErrorAction SilentlyContinue
Remove-Item Env:AZURESUBSCRIPTION_SERVICE_CONNECTION_ID -ErrorAction SilentlyContinue
eng/common/core-templates/job/helix-job-monitor.yml:241
- This comment states AzurePipelinesCredential “cannot authenticate Entra-issued service connections”, but the PR description indicates the intent is to support Entra-issued WIF endpoints by resolving/passing the endpoint GUID. Even if the code still prefers Azure CLI, the current wording is absolute and can mislead future maintainers. Reword to describe the actual intent here: clearing AZURESUBSCRIPTION_* to keep DefaultIdentityTokenCredential on the Azure CLI session.
# AzurePipelinesCredential currently receives Azure DevOps-issued assertions,
# which cannot authenticate Entra-issued service connections. Force Arcade's
# credential chain to use the renewable Azure CLI session maintained by this task.
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Lite
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 40ffbc91-7138-4298-b61c-73a788185f11
Document the WIF service connection contract and make the default monitor window long enough for observed runtime builds. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ee73e53-8098-4533-b3f9-1686640d4f55
Restore SYSTEM_ACCESSTOKEN inside AzureCLI so JobMonitor uses the build OAuth token for Azure DevOps APIs rather than the Helix service connection token. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ee73e53-8098-4533-b3f9-1686640d4f55
| $(Build.SourcesDirectory)\eng\common\msbuild.ps1 ` | ||
| $(Build.SourcesDirectory)/${{ parameters.HelixProjectPath }} ` |
Preserve the pipeline OAuth token in a secret variable before AzureCLI replaces SYSTEM_ACCESSTOKEN, then restore it for JobMonitor Azure DevOps calls. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ee73e53-8098-4533-b3f9-1686640d4f55
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ee73e53-8098-4533-b3f9-1686640d4f55
|
@mmitche I documented the dotnet/runtime validation here: https://dev.azure.com/dnceng/internal/_workitems/edit/12269#11163075 We'll need this change to flow to dotnet/runtime first, but then we can merge dotnet/runtime#134494 after. |


Summary
AzureCLI@2withkeepAzSessionActive: trueAzureCliCredential, while preserving the existing credential order for other Arcade consumersWhy
The original approach attempted to use
AzurePipelinesCredentialwith the endpoint GUID resolved byAzureCLI@2. Staging builds 3079813 and 3080543 disproved that design: the OIDC request returned an Azure DevOps-issued assertion (vstoken.dev.azure.com), while the staging service connection is configured with a Microsoft Entra issuer (login.microsoftonline.com/.../v2.0), producingAADSTS700211.addSpnToEnvironmentwould expose the task's current WIF assertion, but that assertion is not a renewable credential for Helix operations that may wait for hours. Instead,AzureCLI@2maintains a renewable CLI login for the lifetime of the task. The Helix clients now explicitly preferAzureCliCredential, then retain the existing credentials as fallbacks.A subsequent staging canary, 3080737, proved the Azure CLI WIF login succeeds. It also exposed a second issue in the previously published SDK: managed identity ran before Azure CLI and IMDS returned a fatal
Identity not found.PreferAzureCliCredentialfixes that ordering for Helix only.Compatibility
HelixUseEntraAuthenticationanduseEntraAuthenticationremain opt-in.DefaultIdentityTokenCredentialconsumers retain the existing credential order.Validation
Microsoft.DotNet.Helix.Sdk.Tests: 328 passed, 0 failedd6ec7b3f, produced and selectedMicrosoft.DotNet.Helix.Sdk 12.0.0-ci, authenticated through Azure CLI WIF, submitted staging Helix job4cc4865f-6fc6-4808-96c7-ad9d60d0bbf2, and completed its work item successfully3083038was marked partially succeeded only because the unrelatedEmit Smart CI telemetry to App Insightsstep exited 1; the authentication canary task and Helix submission both succeededRollout
Land this change in
mainfirst. PR #17589 is therelease/11.0backport and must remain draft until this PR is merged.AB#12269