Skip to content

Commit

Permalink
Add "-certificate" param support for azcli (version 2.66.0 and above) (
Browse files Browse the repository at this point in the history
…#20698)

Co-authored-by: Uladzimir Tratsiakou <utratsiakou@microsoft.com>
  • Loading branch information
wawanawna and wawanawna1984 authored Nov 28, 2024
1 parent 9aadabd commit f23b101
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 28 deletions.
39 changes: 37 additions & 2 deletions Tasks/AzureCLIV2/azureclitask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true);
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand All @@ -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") {
Expand Down
4 changes: 2 additions & 2 deletions Tasks/AzureCLIV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"demands": [],
"version": {
"Major": 2,
"Minor": 248,
"Patch": 0
"Minor": 249,
"Patch": 5
},
"minimumAgentVersion": "2.0.0",
"instanceNameFormat": "Azure CLI $(scriptPath)",
Expand Down
4 changes: 2 additions & 2 deletions Tasks/AzureCLIV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions _generated/AzureCLIV2.versionmap.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Default|2.248.0
Node20_229_2|2.248.1
Default|2.249.5
Node20_229_2|2.249.6
39 changes: 37 additions & 2 deletions _generated/AzureCLIV2/azureclitask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true);
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand All @@ -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") {
Expand Down
8 changes: 4 additions & 4 deletions _generated/AzureCLIV2/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"demands": [],
"version": {
"Major": 2,
"Minor": 248,
"Patch": 0
"Minor": 249,
"Patch": 5
},
"minimumAgentVersion": "2.0.0",
"instanceNameFormat": "Azure CLI $(scriptPath)",
Expand Down Expand Up @@ -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"
}
}
8 changes: 4 additions & 4 deletions _generated/AzureCLIV2/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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"
}
}
4 changes: 4 additions & 0 deletions _generated/AzureCLIV2_Node20/.npmrc
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
scripts-prepend-node-path=true

registry=https://pkgs.dev.azure.com/mseng/PipelineTools/_packaging/PipelineTools_PublicPackages/npm/registry/

always-auth=true
39 changes: 37 additions & 2 deletions _generated/AzureCLIV2_Node20/azureclitask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
var authScheme: string = tl.getEndpointAuthorizationScheme(connectedService, true);
var subscriptionID: string = tl.getEndpointDataParameter(connectedService, "SubscriptionID", true);
Expand Down Expand Up @@ -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);

Expand All @@ -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);
Expand All @@ -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") {
Expand Down
8 changes: 4 additions & 4 deletions _generated/AzureCLIV2_Node20/task.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"demands": [],
"version": {
"Major": 2,
"Minor": 248,
"Patch": 1
"Minor": 249,
"Patch": 6
},
"minimumAgentVersion": "2.0.0",
"instanceNameFormat": "Azure CLI $(scriptPath)",
Expand Down Expand Up @@ -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"
}
}
8 changes: 4 additions & 4 deletions _generated/AzureCLIV2_Node20/task.loc.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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"
}
}

0 comments on commit f23b101

Please sign in to comment.