diff --git a/CHANGELOG.md b/CHANGELOG.md index 4414389..babf41e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Sheriff Azure DevOps Extension Changelog +## 0.0.6 + +* `SheriffPlan` and `SheriffApply` tasks updated to support workload identity federation authentication. + ## 0.0.5 * `InstallSheriffCLI` task updated to download Sheriff from Azure Storage. diff --git a/README.rst b/README.rst index 2115772..98a440e 100644 --- a/README.rst +++ b/README.rst @@ -20,8 +20,8 @@ About This is an Azure DevOps extension that provides tasks for installing and running `Sheriff `_, a command line tool to -manage Azure role-based access control (Azure RBAC) and Microsoft Entra -Privileged Identity Management (Microsoft Entra PIM) using desired state configuration. +manage Microsoft Entra Privileged Identity Management (Microsoft Entra PIM) using +desired state configuration. ------------ Installation diff --git a/tasks/SheriffApply/SheriffApplyV0/package-lock.json b/tasks/SheriffApply/SheriffApplyV0/package-lock.json index e0a92fe..bb9b080 100644 --- a/tasks/SheriffApply/SheriffApplyV0/package-lock.json +++ b/tasks/SheriffApply/SheriffApplyV0/package-lock.json @@ -1,12 +1,12 @@ { "name": "sheriff-apply-task", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "sheriff-apply-task", - "version": "0.0.1", + "version": "0.0.2", "license": "GPL-3.0", "dependencies": { "axios": "^1.4.0", diff --git a/tasks/SheriffApply/SheriffApplyV0/package.json b/tasks/SheriffApply/SheriffApplyV0/package.json index 3afb315..ed0f026 100644 --- a/tasks/SheriffApply/SheriffApplyV0/package.json +++ b/tasks/SheriffApply/SheriffApplyV0/package.json @@ -1,6 +1,6 @@ { "name": "sheriff-apply-task", - "version": "0.0.1", + "version": "0.0.2", "description": "", "scripts": { "test": "run-p test:*", diff --git a/tasks/SheriffApply/SheriffApplyV0/src/index.js b/tasks/SheriffApply/SheriffApplyV0/src/index.js index 7051b40..02eb031 100644 --- a/tasks/SheriffApply/SheriffApplyV0/src/index.js +++ b/tasks/SheriffApply/SheriffApplyV0/src/index.js @@ -1,5 +1,8 @@ #!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); + const tl = require('azure-pipelines-task-lib/task'); async function run() { @@ -11,6 +14,8 @@ async function run() { let subscriptionId = tl.getInput('subscriptionId', false); + const agentTempDirectory = tl.getVariable('Agent.TempDirectory'); + const env = {}; const authScheme = tl.getEndpointAuthorizationScheme(connectedService, true); @@ -22,7 +27,18 @@ async function run() { if (authScheme.toLowerCase() === 'workloadidentityfederation') { tl.debug('workload identity federation scheme'); - throw new Error('Workload identity federation scheme not implemented'); + const servicePrincipalId = tl.getEndpointAuthorizationParameter(connectedService, 'serviceprincipalid', false); + env.AZURE_CLIENT_ID = servicePrincipalId; + + const tenantId = tl.getEndpointAuthorizationParameter(connectedService, 'tenantid', false); + env.AZURE_TENANT_ID = tenantId; + + const federatedToken = await this.getIdToken(connectedService); + tl.setSecret(federatedToken); + + const federatedTokenFilePath = path.join(agentTempDirectory, 'azure-identity-token'); + fs.writeFileSync(federatedTokenFilePath, federatedToken); + env.AZURE_FEDERATED_TOKEN_FILE = federatedTokenFilePath; } else if (authScheme.toLowerCase() === 'serviceprincipal') { tl.debug('service principal scheme'); const authType = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', false); diff --git a/tasks/SheriffPlan/SheriffPlanV0/package-lock.json b/tasks/SheriffPlan/SheriffPlanV0/package-lock.json index 10554f6..94053bb 100644 --- a/tasks/SheriffPlan/SheriffPlanV0/package-lock.json +++ b/tasks/SheriffPlan/SheriffPlanV0/package-lock.json @@ -1,12 +1,12 @@ { "name": "sheriff-plan-task", - "version": "0.0.1", + "version": "0.0.2", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "sheriff-plan-task", - "version": "0.0.1", + "version": "0.0.2", "license": "GPL-3.0", "dependencies": { "axios": "^1.4.0", diff --git a/tasks/SheriffPlan/SheriffPlanV0/package.json b/tasks/SheriffPlan/SheriffPlanV0/package.json index 65c6d45..18cdf2b 100644 --- a/tasks/SheriffPlan/SheriffPlanV0/package.json +++ b/tasks/SheriffPlan/SheriffPlanV0/package.json @@ -1,6 +1,6 @@ { "name": "sheriff-plan-task", - "version": "0.0.1", + "version": "0.0.2", "description": "", "scripts": { "test": "run-p test:*", diff --git a/tasks/SheriffPlan/SheriffPlanV0/src/index.js b/tasks/SheriffPlan/SheriffPlanV0/src/index.js index 3ffc205..1cd9b5a 100644 --- a/tasks/SheriffPlan/SheriffPlanV0/src/index.js +++ b/tasks/SheriffPlan/SheriffPlanV0/src/index.js @@ -1,5 +1,8 @@ #!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); + const tl = require('azure-pipelines-task-lib/task'); async function run() { @@ -10,6 +13,8 @@ async function run() { let subscriptionId = tl.getInput('subscriptionId', false); + const agentTempDirectory = tl.getVariable('Agent.TempDirectory'); + const env = {}; const authScheme = tl.getEndpointAuthorizationScheme(connectedService, true); @@ -21,7 +26,18 @@ async function run() { if (authScheme.toLowerCase() === 'workloadidentityfederation') { tl.debug('workload identity federation scheme'); - throw new Error('Workload identity federation scheme not implemented'); + const servicePrincipalId = tl.getEndpointAuthorizationParameter(connectedService, 'serviceprincipalid', false); + env.AZURE_CLIENT_ID = servicePrincipalId; + + const tenantId = tl.getEndpointAuthorizationParameter(connectedService, 'tenantid', false); + env.AZURE_TENANT_ID = tenantId; + + const federatedToken = await this.getIdToken(connectedService); + tl.setSecret(federatedToken); + + const federatedTokenFilePath = path.join(agentTempDirectory, 'azure-identity-token'); + fs.writeFileSync(federatedTokenFilePath, federatedToken); + env.AZURE_FEDERATED_TOKEN_FILE = federatedTokenFilePath; } else if (authScheme.toLowerCase() === 'serviceprincipal') { tl.debug('service principal scheme'); const authType = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', false);