Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .vault-config/product-builds-engkeyvault.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ secrets:
parameters:
description: Client id for akams app

dn-bot-all-orgs-build-rw-code-rw:
type: azure-devops-access-token
parameters:
domainAccountName: dn-bot
domainAccountSecret:
location: helixkv
name: dn-bot-account-redmond
name: dn-bot-all-orgs-build
organizations: dnceng devdiv microsoft dotnet-security-partners
scopes: build_execute code_write

#AzureDevOps-Artifact-Feeds-Pats
dn-bot-dnceng-artifact-feeds-rw:
type: azure-devops-access-token
Expand Down
1 change: 1 addition & 0 deletions eng/common/core-templates/steps/publish-logs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ steps:
'$(microsoft-symbol-server-pat)'
'$(symweb-symbol-server-pat)'
'$(dnceng-symbol-server-pat)'
'$(dn-bot-all-orgs-build-rw-code-rw)'
'$(System.AccessToken)'
${{parameters.CustomSensitiveDataList}}
continueOnError: true
Expand Down
1 change: 1 addition & 0 deletions eng/publishing/v3/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ stages:
/p:SymbolRequestProject='dotnet'
${{ parameters.symbolPublishingAdditionalParameters}}
/p:BuildQuality='${{ parameters.buildQuality }}'
/p:AzdoApiToken='$(dn-bot-all-orgs-build-rw-code-rw)'
/p:ArtifactsBasePath='$(Build.ArtifactStagingDirectory)/'
/p:BuildId='$(AzDOBuildId)'
/p:AzureDevOpsOrg='$(AzDOAccount)'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -957,68 +957,13 @@ private HttpClient CreateAzdoClient(string tokenOverride = null)

var client = new HttpClient(handler);
client.Timeout = TimeSpan.FromSeconds(TimeoutInSeconds);

string effectiveToken = tokenOverride ?? AzdoApiToken;
if (!string.IsNullOrEmpty(effectiveToken))
{
// Legacy PAT-based authentication
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "", effectiveToken))));
}
else
{
// Entra-based authentication using DefaultIdentityTokenCredential
// This supports AzurePipelinesCredential (from AzureCLI@2), ManagedIdentity, WorkloadIdentity, and AzureCLI
var credential = new DefaultIdentityTokenCredential(
new DefaultIdentityTokenCredentialOptions
{
ManagedIdentityClientId = ManagedIdentityClientId
});
var tokenRequestContext = new TokenRequestContext(["499b84ac-1321-427f-aa17-267ca6975798/.default"]);
AccessToken accessToken = credential.GetToken(tokenRequestContext, CancellationToken.None);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Token);
}

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", "",
tokenOverride ?? AzdoApiToken))));
return client;
}

/// <summary>
/// Checks whether Entra-based credentials are available in the current environment.
/// Returns true if running inside an AzureCLI@2 task (AzurePipelinesCredential),
/// or if a ManagedIdentityClientId is configured.
/// </summary>
private bool HasEntraCredentialsAvailable()
{
// AzurePipelinesCredential environment (set by AzureCLI@2 task with addSpnToEnvironment: true
// when the service connection is configured for Workload Identity Federation).
// Note: SYSTEM_OIDCREQUESTURI is NOT required - AzurePipelinesCredential obtains the OIDC
// token from Azure DevOps using SYSTEM_ACCESSTOKEN and the service connection ID.
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("AZURESUBSCRIPTION_CLIENT_ID")) &&
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("AZURESUBSCRIPTION_TENANT_ID")) &&
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("AZURESUBSCRIPTION_SERVICE_CONNECTION_ID")) &&
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("SYSTEM_ACCESSTOKEN")))
{
return true;
}

// WorkloadIdentityCredential environment
if (!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("servicePrincipalId")) &&
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("idToken")) &&
!string.IsNullOrEmpty(Environment.GetEnvironmentVariable("tenantId")))
{
return true;
}

// Managed Identity is configured
if (!string.IsNullOrEmpty(ManagedIdentityClientId))
{
return true;
}

return false;
}

private SemaphoreSlim _createArtifactSemaphore = new SemaphoreSlim(1,1);

/// <summary>
Expand Down Expand Up @@ -1997,9 +1942,9 @@ protected bool AnyMissingRequiredBaseProperties()
Log.LogError($"The property {nameof(MaestroApiEndpoint)} is required but doesn't have a value set.");
}

if (UseStreamingPublishing && string.IsNullOrEmpty(AzdoApiToken) && !HasEntraCredentialsAvailable())
if (UseStreamingPublishing && string.IsNullOrEmpty(AzdoApiToken))
{
Log.LogError($"The property {nameof(AzdoApiToken)} is required when using streaming publishing (unless Entra credentials are available via AzureCLI@2 or Managed Identity), but doesn't have a value set.");
Log.LogError($"The property {nameof(AzdoApiToken)} is required when using streaming publishing, but doesn't have a value set.");
}

if (UseStreamingPublishing && string.IsNullOrEmpty(ArtifactsBasePath))
Expand Down
Loading