From f23b101fe850e5d3404212c7e1b0623302cf1612 Mon Sep 17 00:00:00 2001 From: Vladimir Tretyakov Date: Thu, 28 Nov 2024 18:23:00 +0100 Subject: [PATCH] Add "-certificate" param support for azcli (version 2.66.0 and above) (#20698) Co-authored-by: Uladzimir Tratsiakou --- Tasks/AzureCLIV2/azureclitask.ts | 39 +++++++++++++++++++- Tasks/AzureCLIV2/task.json | 4 +- Tasks/AzureCLIV2/task.loc.json | 4 +- _generated/AzureCLIV2.versionmap.txt | 4 +- _generated/AzureCLIV2/azureclitask.ts | 39 +++++++++++++++++++- _generated/AzureCLIV2/task.json | 8 ++-- _generated/AzureCLIV2/task.loc.json | 8 ++-- _generated/AzureCLIV2_Node20/.npmrc | 4 ++ _generated/AzureCLIV2_Node20/azureclitask.ts | 39 +++++++++++++++++++- _generated/AzureCLIV2_Node20/task.json | 8 ++-- _generated/AzureCLIV2_Node20/task.loc.json | 8 ++-- 11 files changed, 137 insertions(+), 28 deletions(-) diff --git a/Tasks/AzureCLIV2/azureclitask.ts b/Tasks/AzureCLIV2/azureclitask.ts index c3000d99ab8a..b2108b6abee5 100644 --- a/Tasks/AzureCLIV2/azureclitask.ts +++ b/Tasks/AzureCLIV2/azureclitask.ts @@ -193,6 +193,37 @@ export class azureclitask { private static federatedToken: string = null; private static tenantId: string = null; + private static isAzVersionGreaterOrEqual(versionToCompare) { + try { + const result = tl.execSync("az", "--version"); + const versionMatch = result.stdout.match(/azure-cli\s+(\d+\.\d+\.\d+)/); + + if (!versionMatch || versionMatch.length < 2) { + tl.error(`Can't parse az version from: ${result}`); + return false; + } + + const currentVersion = versionMatch[1]; + tl.debug(`Current Azure CLI version: ${currentVersion}`); + + // Parse both versions into major, minor, patch components + const [currentMajor, currentMinor, currentPatch] = currentVersion.split('.').map(Number); + const [compareMajor, compareMinor, comparePatch] = versionToCompare.split('.').map(Number); + + // Compare versions + if (currentMajor > compareMajor) return true; + if (currentMajor < compareMajor) return false; + + if (currentMinor > compareMinor) return true; + if (currentMinor < compareMinor) return false; + + return currentPatch >= comparePatch; + } catch (error) { + tl.error(`Error checking Azure CLI version: ${error.message}`); + return false; + } + } + private static async loginAzureRM(connectedService: string):Promise { var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true); var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true); @@ -223,6 +254,7 @@ export class azureclitask { else if (authScheme.toLowerCase() == "serviceprincipal") { let authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true); let cliPassword: string = null; + let authParam: string = "--password"; var servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, "serviceprincipalid", false); var tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, "tenantid", false); @@ -231,6 +263,9 @@ export class azureclitask { if (authType == "spnCertificate") { tl.debug('certificate based endpoint'); + if(azureclitask.isAzVersionGreaterOrEqual("2.66.0")) { + authParam = "--certificate"; + } let certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, "servicePrincipalCertificate", false); cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem'); fs.writeFileSync(cliPassword, certificateContent); @@ -246,10 +281,10 @@ export class azureclitask { tl.setSecret(escapedCliPassword.replace(/\\/g, '\"')); //login using svn if (visibleAzLogin) { - Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed")); + Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed")); } else { - Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed")); + Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed")); } } else if(authScheme.toLowerCase() == "managedserviceidentity") { diff --git a/Tasks/AzureCLIV2/task.json b/Tasks/AzureCLIV2/task.json index 13ad6e197497..bbb9e4192b50 100644 --- a/Tasks/AzureCLIV2/task.json +++ b/Tasks/AzureCLIV2/task.json @@ -19,8 +19,8 @@ "demands": [], "version": { "Major": 2, - "Minor": 248, - "Patch": 0 + "Minor": 249, + "Patch": 5 }, "minimumAgentVersion": "2.0.0", "instanceNameFormat": "Azure CLI $(scriptPath)", diff --git a/Tasks/AzureCLIV2/task.loc.json b/Tasks/AzureCLIV2/task.loc.json index 823a38f9f589..667c7d8bae05 100644 --- a/Tasks/AzureCLIV2/task.loc.json +++ b/Tasks/AzureCLIV2/task.loc.json @@ -19,8 +19,8 @@ "demands": [], "version": { "Major": 2, - "Minor": 248, - "Patch": 0 + "Minor": 249, + "Patch": 5 }, "minimumAgentVersion": "2.0.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", diff --git a/_generated/AzureCLIV2.versionmap.txt b/_generated/AzureCLIV2.versionmap.txt index 02a776d5c95b..3de03a3493e4 100644 --- a/_generated/AzureCLIV2.versionmap.txt +++ b/_generated/AzureCLIV2.versionmap.txt @@ -1,2 +1,2 @@ -Default|2.248.0 -Node20_229_2|2.248.1 +Default|2.249.5 +Node20_229_2|2.249.6 diff --git a/_generated/AzureCLIV2/azureclitask.ts b/_generated/AzureCLIV2/azureclitask.ts index 48bd64474e67..0e81d6b95c5a 100644 --- a/_generated/AzureCLIV2/azureclitask.ts +++ b/_generated/AzureCLIV2/azureclitask.ts @@ -181,6 +181,37 @@ export class azureclitask { private static federatedToken: string = null; private static tenantId: string = null; + private static isAzVersionGreaterOrEqual(versionToCompare) { + try { + const result = tl.execSync("az", "--version"); + const versionMatch = result.stdout.match(/azure-cli\s+(\d+\.\d+\.\d+)/); + + if (!versionMatch || versionMatch.length < 2) { + tl.error(`Can't parse az version from: ${result}`); + return false; + } + + const currentVersion = versionMatch[1]; + tl.debug(`Current Azure CLI version: ${currentVersion}`); + + // Parse both versions into major, minor, patch components + const [currentMajor, currentMinor, currentPatch] = currentVersion.split('.').map(Number); + const [compareMajor, compareMinor, comparePatch] = versionToCompare.split('.').map(Number); + + // Compare versions + if (currentMajor > compareMajor) return true; + if (currentMajor < compareMajor) return false; + + if (currentMinor > compareMinor) return true; + if (currentMinor < compareMinor) return false; + + return currentPatch >= comparePatch; + } catch (error) { + tl.error(`Error checking Azure CLI version: ${error.message}`); + return false; + } + } + private static async loginAzureRM(connectedService: string):Promise { var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true); var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true); @@ -211,6 +242,7 @@ export class azureclitask { else if (authScheme.toLowerCase() == "serviceprincipal") { let authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true); let cliPassword: string = null; + let authParam: string = "--password"; var servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, "serviceprincipalid", false); var tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, "tenantid", false); @@ -219,6 +251,9 @@ export class azureclitask { if (authType == "spnCertificate") { tl.debug('certificate based endpoint'); + if(azureclitask.isAzVersionGreaterOrEqual("2.66.0")) { + authParam = "--certificate"; + } let certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, "servicePrincipalCertificate", false); cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem'); fs.writeFileSync(cliPassword, certificateContent); @@ -234,10 +269,10 @@ export class azureclitask { tl.setSecret(escapedCliPassword.replace(/\\/g, '\"')); //login using svn if (visibleAzLogin) { - Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed")); + Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed")); } else { - Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed")); + Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed")); } } else if(authScheme.toLowerCase() == "managedserviceidentity") { diff --git a/_generated/AzureCLIV2/task.json b/_generated/AzureCLIV2/task.json index a39b7516c7a7..e61aa0f73d94 100644 --- a/_generated/AzureCLIV2/task.json +++ b/_generated/AzureCLIV2/task.json @@ -19,8 +19,8 @@ "demands": [], "version": { "Major": 2, - "Minor": 248, - "Patch": 0 + "Minor": 249, + "Patch": 5 }, "minimumAgentVersion": "2.0.0", "instanceNameFormat": "Azure CLI $(scriptPath)", @@ -226,7 +226,7 @@ "KeepingAzSessionActiveUnsupportedScheme": "The 'keepAzSessionActive' input might be used only for workload identity federation ARM service connection. The referenced service endpoint auth scheme was unexpected: %s. Change the scheme or remove 'keepAzSessionActive' input." }, "_buildConfigMapping": { - "Default": "2.248.0", - "Node20_229_2": "2.248.1" + "Default": "2.249.5", + "Node20_229_2": "2.249.6" } } \ No newline at end of file diff --git a/_generated/AzureCLIV2/task.loc.json b/_generated/AzureCLIV2/task.loc.json index dd7935b3f474..7397cb2dfb00 100644 --- a/_generated/AzureCLIV2/task.loc.json +++ b/_generated/AzureCLIV2/task.loc.json @@ -19,8 +19,8 @@ "demands": [], "version": { "Major": 2, - "Minor": 248, - "Patch": 0 + "Minor": 249, + "Patch": 5 }, "minimumAgentVersion": "2.0.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", @@ -226,7 +226,7 @@ "KeepingAzSessionActiveUnsupportedScheme": "ms-resource:loc.messages.KeepingAzSessionActiveUnsupportedScheme" }, "_buildConfigMapping": { - "Default": "2.248.0", - "Node20_229_2": "2.248.1" + "Default": "2.249.5", + "Node20_229_2": "2.249.6" } } \ No newline at end of file diff --git a/_generated/AzureCLIV2_Node20/.npmrc b/_generated/AzureCLIV2_Node20/.npmrc index 5fca0d518be7..d5c7fef620a3 100644 --- a/_generated/AzureCLIV2_Node20/.npmrc +++ b/_generated/AzureCLIV2_Node20/.npmrc @@ -1 +1,5 @@ scripts-prepend-node-path=true + +registry=https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/ + +always-auth=true \ No newline at end of file diff --git a/_generated/AzureCLIV2_Node20/azureclitask.ts b/_generated/AzureCLIV2_Node20/azureclitask.ts index 81ba5347d2d9..7263d02fc64e 100644 --- a/_generated/AzureCLIV2_Node20/azureclitask.ts +++ b/_generated/AzureCLIV2_Node20/azureclitask.ts @@ -191,6 +191,37 @@ export class azureclitask { private static federatedToken: string = null; private static tenantId: string = null; + private static isAzVersionGreaterOrEqual(versionToCompare) { + try { + const result = tl.execSync("az", "--version"); + const versionMatch = result.stdout.match(/azure-cli\s+(\d+\.\d+\.\d+)/); + + if (!versionMatch || versionMatch.length < 2) { + tl.error(`Can't parse az version from: ${result}`); + return false; + } + + const currentVersion = versionMatch[1]; + tl.debug(`Current Azure CLI version: ${currentVersion}`); + + // Parse both versions into major, minor, patch components + const [currentMajor, currentMinor, currentPatch] = currentVersion.split('.').map(Number); + const [compareMajor, compareMinor, comparePatch] = versionToCompare.split('.').map(Number); + + // Compare versions + if (currentMajor > compareMajor) return true; + if (currentMajor < compareMajor) return false; + + if (currentMinor > compareMinor) return true; + if (currentMinor < compareMinor) return false; + + return currentPatch >= comparePatch; + } catch (error) { + tl.error(`Error checking Azure CLI version: ${error.message}`); + return false; + } + } + private static async loginAzureRM(connectedService: string):Promise { var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true); var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true); @@ -221,6 +252,7 @@ export class azureclitask { else if (authScheme.toLowerCase() == "serviceprincipal") { let authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true); let cliPassword: string = null; + let authParam: string = "--password"; var servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, "serviceprincipalid", false); var tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, "tenantid", false); @@ -229,6 +261,9 @@ export class azureclitask { if (authType == "spnCertificate") { tl.debug('certificate based endpoint'); + if(azureclitask.isAzVersionGreaterOrEqual("2.66.0")) { + authParam = "--certificate"; + } let certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, "servicePrincipalCertificate", false); cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem'); fs.writeFileSync(cliPassword, certificateContent); @@ -244,10 +279,10 @@ export class azureclitask { tl.setSecret(escapedCliPassword.replace(/\\/g, '\"')); //login using svn if (visibleAzLogin) { - Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed")); + Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed")); } else { - Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed")); + Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed")); } } else if(authScheme.toLowerCase() == "managedserviceidentity") { diff --git a/_generated/AzureCLIV2_Node20/task.json b/_generated/AzureCLIV2_Node20/task.json index 4ceef3023892..08279ef8bd26 100644 --- a/_generated/AzureCLIV2_Node20/task.json +++ b/_generated/AzureCLIV2_Node20/task.json @@ -19,8 +19,8 @@ "demands": [], "version": { "Major": 2, - "Minor": 248, - "Patch": 1 + "Minor": 249, + "Patch": 6 }, "minimumAgentVersion": "2.0.0", "instanceNameFormat": "Azure CLI $(scriptPath)", @@ -230,7 +230,7 @@ "KeepingAzSessionActiveUnsupportedScheme": "The 'keepAzSessionActive' input might be used only for workload identity federation ARM service connection. The referenced service endpoint auth scheme was unexpected: %s. Change the scheme or remove 'keepAzSessionActive' input." }, "_buildConfigMapping": { - "Default": "2.248.0", - "Node20_229_2": "2.248.1" + "Default": "2.249.5", + "Node20_229_2": "2.249.6" } } \ No newline at end of file diff --git a/_generated/AzureCLIV2_Node20/task.loc.json b/_generated/AzureCLIV2_Node20/task.loc.json index 11a383571fd2..52dd51b0c7db 100644 --- a/_generated/AzureCLIV2_Node20/task.loc.json +++ b/_generated/AzureCLIV2_Node20/task.loc.json @@ -19,8 +19,8 @@ "demands": [], "version": { "Major": 2, - "Minor": 248, - "Patch": 1 + "Minor": 249, + "Patch": 6 }, "minimumAgentVersion": "2.0.0", "instanceNameFormat": "ms-resource:loc.instanceNameFormat", @@ -230,7 +230,7 @@ "KeepingAzSessionActiveUnsupportedScheme": "ms-resource:loc.messages.KeepingAzSessionActiveUnsupportedScheme" }, "_buildConfigMapping": { - "Default": "2.248.0", - "Node20_229_2": "2.248.1" + "Default": "2.249.5", + "Node20_229_2": "2.249.6" } } \ No newline at end of file