Skip to content

Commit f23b101

Browse files
Add "-certificate" param support for azcli (version 2.66.0 and above) (#20698)
Co-authored-by: Uladzimir Tratsiakou <[email protected]>
1 parent 9aadabd commit f23b101

File tree

11 files changed

+137
-28
lines changed

11 files changed

+137
-28
lines changed

Tasks/AzureCLIV2/azureclitask.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,37 @@ export class azureclitask {
193193
private static federatedToken: string = null;
194194
private static tenantId: string = null;
195195

196+
private static isAzVersionGreaterOrEqual(versionToCompare) {
197+
try {
198+
const result = tl.execSync("az", "--version");
199+
const versionMatch = result.stdout.match(/azure-cli\s+(\d+\.\d+\.\d+)/);
200+
201+
if (!versionMatch || versionMatch.length < 2) {
202+
tl.error(`Can't parse az version from: ${result}`);
203+
return false;
204+
}
205+
206+
const currentVersion = versionMatch[1];
207+
tl.debug(`Current Azure CLI version: ${currentVersion}`);
208+
209+
// Parse both versions into major, minor, patch components
210+
const [currentMajor, currentMinor, currentPatch] = currentVersion.split('.').map(Number);
211+
const [compareMajor, compareMinor, comparePatch] = versionToCompare.split('.').map(Number);
212+
213+
// Compare versions
214+
if (currentMajor > compareMajor) return true;
215+
if (currentMajor < compareMajor) return false;
216+
217+
if (currentMinor > compareMinor) return true;
218+
if (currentMinor < compareMinor) return false;
219+
220+
return currentPatch >= comparePatch;
221+
} catch (error) {
222+
tl.error(`Error checking Azure CLI version: ${error.message}`);
223+
return false;
224+
}
225+
}
226+
196227
private static async loginAzureRM(connectedService: string):Promise<void> {
197228
var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
198229
var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true);
@@ -223,6 +254,7 @@ export class azureclitask {
223254
else if (authScheme.toLowerCase() == "serviceprincipal") {
224255
let authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true);
225256
let cliPassword: string = null;
257+
let authParam: string = "--password";
226258
var servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, "serviceprincipalid", false);
227259
var tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, "tenantid", false);
228260

@@ -231,6 +263,9 @@ export class azureclitask {
231263

232264
if (authType == "spnCertificate") {
233265
tl.debug('certificate based endpoint');
266+
if(azureclitask.isAzVersionGreaterOrEqual("2.66.0")) {
267+
authParam = "--certificate";
268+
}
234269
let certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, "servicePrincipalCertificate", false);
235270
cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem');
236271
fs.writeFileSync(cliPassword, certificateContent);
@@ -246,10 +281,10 @@ export class azureclitask {
246281
tl.setSecret(escapedCliPassword.replace(/\\/g, '\"'));
247282
//login using svn
248283
if (visibleAzLogin) {
249-
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed"));
284+
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed"));
250285
}
251286
else {
252-
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed"));
287+
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed"));
253288
}
254289
}
255290
else if(authScheme.toLowerCase() == "managedserviceidentity") {

Tasks/AzureCLIV2/task.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"demands": [],
2020
"version": {
2121
"Major": 2,
22-
"Minor": 248,
23-
"Patch": 0
22+
"Minor": 249,
23+
"Patch": 5
2424
},
2525
"minimumAgentVersion": "2.0.0",
2626
"instanceNameFormat": "Azure CLI $(scriptPath)",

Tasks/AzureCLIV2/task.loc.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"demands": [],
2020
"version": {
2121
"Major": 2,
22-
"Minor": 248,
23-
"Patch": 0
22+
"Minor": 249,
23+
"Patch": 5
2424
},
2525
"minimumAgentVersion": "2.0.0",
2626
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",

_generated/AzureCLIV2.versionmap.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Default|2.248.0
2-
Node20_229_2|2.248.1
1+
Default|2.249.5
2+
Node20_229_2|2.249.6

_generated/AzureCLIV2/azureclitask.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,37 @@ export class azureclitask {
181181
private static federatedToken: string = null;
182182
private static tenantId: string = null;
183183

184+
private static isAzVersionGreaterOrEqual(versionToCompare) {
185+
try {
186+
const result = tl.execSync("az", "--version");
187+
const versionMatch = result.stdout.match(/azure-cli\s+(\d+\.\d+\.\d+)/);
188+
189+
if (!versionMatch || versionMatch.length < 2) {
190+
tl.error(`Can't parse az version from: ${result}`);
191+
return false;
192+
}
193+
194+
const currentVersion = versionMatch[1];
195+
tl.debug(`Current Azure CLI version: ${currentVersion}`);
196+
197+
// Parse both versions into major, minor, patch components
198+
const [currentMajor, currentMinor, currentPatch] = currentVersion.split('.').map(Number);
199+
const [compareMajor, compareMinor, comparePatch] = versionToCompare.split('.').map(Number);
200+
201+
// Compare versions
202+
if (currentMajor > compareMajor) return true;
203+
if (currentMajor < compareMajor) return false;
204+
205+
if (currentMinor > compareMinor) return true;
206+
if (currentMinor < compareMinor) return false;
207+
208+
return currentPatch >= comparePatch;
209+
} catch (error) {
210+
tl.error(`Error checking Azure CLI version: ${error.message}`);
211+
return false;
212+
}
213+
}
214+
184215
private static async loginAzureRM(connectedService: string):Promise<void> {
185216
var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
186217
var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true);
@@ -211,6 +242,7 @@ export class azureclitask {
211242
else if (authScheme.toLowerCase() == "serviceprincipal") {
212243
let authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true);
213244
let cliPassword: string = null;
245+
let authParam: string = "--password";
214246
var servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, "serviceprincipalid", false);
215247
var tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, "tenantid", false);
216248

@@ -219,6 +251,9 @@ export class azureclitask {
219251

220252
if (authType == "spnCertificate") {
221253
tl.debug('certificate based endpoint');
254+
if(azureclitask.isAzVersionGreaterOrEqual("2.66.0")) {
255+
authParam = "--certificate";
256+
}
222257
let certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, "servicePrincipalCertificate", false);
223258
cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem');
224259
fs.writeFileSync(cliPassword, certificateContent);
@@ -234,10 +269,10 @@ export class azureclitask {
234269
tl.setSecret(escapedCliPassword.replace(/\\/g, '\"'));
235270
//login using svn
236271
if (visibleAzLogin) {
237-
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed"));
272+
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed"));
238273
}
239274
else {
240-
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed"));
275+
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed"));
241276
}
242277
}
243278
else if(authScheme.toLowerCase() == "managedserviceidentity") {

_generated/AzureCLIV2/task.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"demands": [],
2020
"version": {
2121
"Major": 2,
22-
"Minor": 248,
23-
"Patch": 0
22+
"Minor": 249,
23+
"Patch": 5
2424
},
2525
"minimumAgentVersion": "2.0.0",
2626
"instanceNameFormat": "Azure CLI $(scriptPath)",
@@ -226,7 +226,7 @@
226226
"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."
227227
},
228228
"_buildConfigMapping": {
229-
"Default": "2.248.0",
230-
"Node20_229_2": "2.248.1"
229+
"Default": "2.249.5",
230+
"Node20_229_2": "2.249.6"
231231
}
232232
}

_generated/AzureCLIV2/task.loc.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"demands": [],
2020
"version": {
2121
"Major": 2,
22-
"Minor": 248,
23-
"Patch": 0
22+
"Minor": 249,
23+
"Patch": 5
2424
},
2525
"minimumAgentVersion": "2.0.0",
2626
"instanceNameFormat": "ms-resource:loc.instanceNameFormat",
@@ -226,7 +226,7 @@
226226
"KeepingAzSessionActiveUnsupportedScheme": "ms-resource:loc.messages.KeepingAzSessionActiveUnsupportedScheme"
227227
},
228228
"_buildConfigMapping": {
229-
"Default": "2.248.0",
230-
"Node20_229_2": "2.248.1"
229+
"Default": "2.249.5",
230+
"Node20_229_2": "2.249.6"
231231
}
232232
}

_generated/AzureCLIV2_Node20/.npmrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
scripts-prepend-node-path=true
2+
3+
registry=https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/
4+
5+
always-auth=true

_generated/AzureCLIV2_Node20/azureclitask.ts

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,37 @@ export class azureclitask {
191191
private static federatedToken: string = null;
192192
private static tenantId: string = null;
193193

194+
private static isAzVersionGreaterOrEqual(versionToCompare) {
195+
try {
196+
const result = tl.execSync("az", "--version");
197+
const versionMatch = result.stdout.match(/azure-cli\s+(\d+\.\d+\.\d+)/);
198+
199+
if (!versionMatch || versionMatch.length < 2) {
200+
tl.error(`Can't parse az version from: ${result}`);
201+
return false;
202+
}
203+
204+
const currentVersion = versionMatch[1];
205+
tl.debug(`Current Azure CLI version: ${currentVersion}`);
206+
207+
// Parse both versions into major, minor, patch components
208+
const [currentMajor, currentMinor, currentPatch] = currentVersion.split('.').map(Number);
209+
const [compareMajor, compareMinor, comparePatch] = versionToCompare.split('.').map(Number);
210+
211+
// Compare versions
212+
if (currentMajor > compareMajor) return true;
213+
if (currentMajor < compareMajor) return false;
214+
215+
if (currentMinor > compareMinor) return true;
216+
if (currentMinor < compareMinor) return false;
217+
218+
return currentPatch >= comparePatch;
219+
} catch (error) {
220+
tl.error(`Error checking Azure CLI version: ${error.message}`);
221+
return false;
222+
}
223+
}
224+
194225
private static async loginAzureRM(connectedService: string):Promise<void> {
195226
var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
196227
var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true);
@@ -221,6 +252,7 @@ export class azureclitask {
221252
else if (authScheme.toLowerCase() == "serviceprincipal") {
222253
let authType: string = tl.getEndpointAuthorizationParameter(connectedService, 'authenticationType', true);
223254
let cliPassword: string = null;
255+
let authParam: string = "--password";
224256
var servicePrincipalId: string = tl.getEndpointAuthorizationParameter(connectedService, "serviceprincipalid", false);
225257
var tenantId: string = tl.getEndpointAuthorizationParameter(connectedService, "tenantid", false);
226258

@@ -229,6 +261,9 @@ export class azureclitask {
229261

230262
if (authType == "spnCertificate") {
231263
tl.debug('certificate based endpoint');
264+
if(azureclitask.isAzVersionGreaterOrEqual("2.66.0")) {
265+
authParam = "--certificate";
266+
}
232267
let certificateContent: string = tl.getEndpointAuthorizationParameter(connectedService, "servicePrincipalCertificate", false);
233268
cliPassword = path.join(tl.getVariable('Agent.TempDirectory') || tl.getVariable('system.DefaultWorkingDirectory'), 'spnCert.pem');
234269
fs.writeFileSync(cliPassword, certificateContent);
@@ -244,10 +279,10 @@ export class azureclitask {
244279
tl.setSecret(escapedCliPassword.replace(/\\/g, '\"'));
245280
//login using svn
246281
if (visibleAzLogin) {
247-
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed"));
282+
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions`), tl.loc("LoginFailed"));
248283
}
249284
else {
250-
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" --password="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed"));
285+
Utility.throwIfError(tl.execSync("az", `login --service-principal -u "${servicePrincipalId}" ${authParam}="${escapedCliPassword}" --tenant "${tenantId}" --allow-no-subscriptions --output none`), tl.loc("LoginFailed"));
251286
}
252287
}
253288
else if(authScheme.toLowerCase() == "managedserviceidentity") {

_generated/AzureCLIV2_Node20/task.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
"demands": [],
2020
"version": {
2121
"Major": 2,
22-
"Minor": 248,
23-
"Patch": 1
22+
"Minor": 249,
23+
"Patch": 6
2424
},
2525
"minimumAgentVersion": "2.0.0",
2626
"instanceNameFormat": "Azure CLI $(scriptPath)",
@@ -230,7 +230,7 @@
230230
"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."
231231
},
232232
"_buildConfigMapping": {
233-
"Default": "2.248.0",
234-
"Node20_229_2": "2.248.1"
233+
"Default": "2.249.5",
234+
"Node20_229_2": "2.249.6"
235235
}
236236
}

0 commit comments

Comments
 (0)