Skip to content

Commit

Permalink
Support workload identity federation service connection (#147) (#153)
Browse files Browse the repository at this point in the history
Add support for [Workload identity federation for Azure service connections](https://devblogs.microsoft.com/devops/workload-identity-federation-for-azure-deployments-is-now-generally-available/).

This change is based on the implementation in the [Azure CLI Task V2](https://github.com/microsoft/azure-pipelines-tasks/blob/5278dc64cd07ce067e40f3e4a2bf5e15edf12b57/Tasks/AzureCLIV2/azureclitask.ts).

Added [azure-pipelines-tasks-artifacts-common@2.230.0](https://www.npmjs.com/package/azure-pipelines-tasks-artifacts-common/v/2.230.0)
so the [getSystemAccessToken](https://github.com/microsoft/azure-pipelines-tasks/blob/68caa90dd430a9f2a1cb2cacc1d8b6fcc48fbb71/Tasks/GradleV3/Modules/environment.ts#L10-L27)
function could be used to get the system token to auth the request for
the creation of the OIDC token.

Tested in my Azure DevOps organisation with a new Pulumi project created
using the Azure C# template which successfully deployed in pipeline run
[20240505.12](https://dev.azure.com/brdbr/public-playground/_build/results?buildId=438&view=logs&j=12f1170f-54f2-53f3-20dd-22fc7dff55f9&t=eb980582-45a7-5e52-4a39-69f73379d8d6).
  • Loading branch information
Isenr authored May 15, 2024
1 parent e06ea19 commit 8e3168e
Show file tree
Hide file tree
Showing 4 changed files with 260 additions and 13 deletions.
156 changes: 152 additions & 4 deletions buildAndReleaseTask/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions buildAndReleaseTask/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"axios": "^1.6.2",
"azure-devops-node-api": "^12.1.0",
"azure-pipelines-task-lib": "^4.7.0",
"azure-pipelines-tasks-artifacts-common": "^2.230.0",
"azure-pipelines-tool-lib": "^2.0.7",
"semver": "^7.5.4",
"typed-rest-client": "^1.8.11"
Expand Down
20 changes: 14 additions & 6 deletions buildAndReleaseTask/pulumi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,14 @@ function getExecOptions(
* this function returns an env var map with the `ARM_*`
* env vars.
*/
function tryGetAzureEnvVarsFromServiceEndpoint(): IEnvMap {
async function tryGetAzureEnvVarsFromServiceEndpoint(): Promise<IEnvMap> {
const connectedServiceName = tl.getInput("azureSubscription", false);
if (!connectedServiceName) {
return {};
}
tl.debug(tl.loc("Debug_ServiceEndpointName", connectedServiceName));

const serviceEndpoint = getServiceEndpoint(connectedServiceName);
const serviceEndpoint = await getServiceEndpoint(connectedServiceName);
if (serviceEndpoint) {
tl.debug(
`Service endpoint retrieved with client ID ${serviceEndpoint.clientId}`
Expand All @@ -228,9 +228,8 @@ function tryGetAzureEnvVarsFromServiceEndpoint(): IEnvMap {
return {};
}

return {
const envMap: IEnvMap = {
ARM_CLIENT_ID: serviceEndpoint.clientId,
ARM_CLIENT_SECRET: serviceEndpoint.servicePrincipalKey,
ARM_SUBSCRIPTION_ID: serviceEndpoint.subscriptionId,
ARM_TENANT_ID: serviceEndpoint.tenantId,

Expand All @@ -239,9 +238,17 @@ function tryGetAzureEnvVarsFromServiceEndpoint(): IEnvMap {
// Azure Storage-based backend for state persistence.
// https://docs.microsoft.com/en-us/azure/developer/go/azure-sdk-authorization#use-environment-based-authentication
AZURE_CLIENT_ID: serviceEndpoint.clientId,
AZURE_CLIENT_SECRET: serviceEndpoint.servicePrincipalKey,
AZURE_TENANT_ID: serviceEndpoint.tenantId,
};
if (serviceEndpoint.servicePrincipalKey) {
envMap["ARM_CLIENT_SECRET"] = serviceEndpoint.servicePrincipalKey;
envMap["AZURE_CLIENT_SECRET"] = serviceEndpoint.servicePrincipalKey;
}
if (serviceEndpoint.oidcToken) {
envMap["ARM_OIDC_TOKEN"] = serviceEndpoint.oidcToken;
envMap["ARM_USE_OIDC"] = "true";
}
return envMap;
}

/**
Expand Down Expand Up @@ -281,7 +288,8 @@ export async function runPulumi(taskConfig: TaskConfig) {
try {
const toolPath = tl.which("pulumi");
const agentEnvVars = tryGetEnvVars();
const azureServiceEndpointEnvVars = tryGetAzureEnvVarsFromServiceEndpoint();
const azureServiceEndpointEnvVars =
await tryGetAzureEnvVarsFromServiceEndpoint();
const loginEnvVars = {
...azureServiceEndpointEnvVars,
...agentEnvVars,
Expand Down
Loading

0 comments on commit 8e3168e

Please sign in to comment.