diff --git a/__tests__/PowerShell/ServicePrinicipalLogin.test.ts b/__tests__/PowerShell/ServicePrinicipalLogin.test.ts index f8fdbb24..33ddacda 100644 --- a/__tests__/PowerShell/ServicePrinicipalLogin.test.ts +++ b/__tests__/PowerShell/ServicePrinicipalLogin.test.ts @@ -5,7 +5,7 @@ jest.mock('../../src/PowerShell/Utilities/PowerShellToolRunner'); let spnlogin: ServicePrincipalLogin; beforeAll(() => { - spnlogin = new ServicePrincipalLogin("servicePrincipalID", "servicePrinicipalkey", "tenantId", "subscriptionId"); + spnlogin = new ServicePrincipalLogin("servicePrincipalID", "servicePrinicipalkey", "tenantId", "subscriptionId", null, null); }); afterEach(() => { diff --git a/action.yml b/action.yml index c166d10e..990ce9b3 100644 --- a/action.yml +++ b/action.yml @@ -9,6 +9,10 @@ inputs: description: 'Set this value to true to enable Azure PowerShell Login in addition to Az CLI login' required: false default: false + environment: + description: 'Name of the environment. Supported values are AzureStack, AzureCloud. Default being AzureCloud' + required: false + default: AzureCloud branding: icon: 'login.svg' color: 'blue' diff --git a/src/PowerShell/ServicePrincipalLogin.ts b/src/PowerShell/ServicePrincipalLogin.ts index 8aa293a4..93d6c000 100644 --- a/src/PowerShell/ServicePrincipalLogin.ts +++ b/src/PowerShell/ServicePrincipalLogin.ts @@ -6,19 +6,22 @@ import ScriptBuilder from './Utilities/ScriptBuilder'; import Constants from './Constants'; export class ServicePrincipalLogin implements IAzurePowerShellSession { - static readonly environment: string = Constants.AzureCloud; static readonly scopeLevel: string = Constants.Subscription; static readonly scheme: string = Constants.ServicePrincipal; + environment: string; servicePrincipalId: string; servicePrincipalKey: string; tenantId: string; subscriptionId: string; + resourceManagerEndpointUrl: string; - constructor(servicePrincipalId: string, servicePrincipalKey: string, tenantId: string, subscriptionId: string) { + constructor(servicePrincipalId: string, servicePrincipalKey: string, tenantId: string, subscriptionId: string, environment: string, resourceManagerEndpointUrl: string) { this.servicePrincipalId = servicePrincipalId; this.servicePrincipalKey = servicePrincipalKey; this.tenantId = tenantId; this.subscriptionId = subscriptionId; + this.environment = environment; + this.resourceManagerEndpointUrl = resourceManagerEndpointUrl; } async initialize() { @@ -41,8 +44,9 @@ export class ServicePrincipalLogin implements IAzurePowerShellSession { servicePrincipalId: this.servicePrincipalId, servicePrincipalKey: this.servicePrincipalKey, subscriptionId: this.subscriptionId, - environment: ServicePrincipalLogin.environment, - scopeLevel: ServicePrincipalLogin.scopeLevel + environment: this.environment, + scopeLevel: ServicePrincipalLogin.scopeLevel, + resourceManagerEndpointUrl: this.resourceManagerEndpointUrl, } const script: string = new ScriptBuilder().getAzPSLoginScript(ServicePrincipalLogin.scheme, this.tenantId, args); await PowerShellToolRunner.init(); diff --git a/src/PowerShell/Utilities/ScriptBuilder.ts b/src/PowerShell/Utilities/ScriptBuilder.ts index d43060e8..2fcb9410 100644 --- a/src/PowerShell/Utilities/ScriptBuilder.ts +++ b/src/PowerShell/Utilities/ScriptBuilder.ts @@ -9,6 +9,9 @@ export default class ScriptBuilder { let command = `Clear-AzContext -Scope Process; Clear-AzContext -Scope CurrentUser -Force -ErrorAction SilentlyContinue;`; if (scheme === Constants.ServicePrincipal) { + if (args.environment.toLowerCase() == "azurestack") { + command += `Add-AzEnvironment -Name ${args.environment} -ARMEndpoint ${args.resourceManagerEndpointUrl} | out-null;`; + } command += `Connect-AzAccount -ServicePrincipal -Tenant '${tenantId}' -Credential \ (New-Object System.Management.Automation.PSCredential('${args.servicePrincipalId}',(ConvertTo-SecureString '${args.servicePrincipalKey.replace("'", "''")}' -AsPlainText -Force))) \ -Environment '${args.environment}' | out-null;`; diff --git a/src/main.ts b/src/main.ts index cbe0b20e..3ae54117 100644 --- a/src/main.ts +++ b/src/main.ts @@ -30,18 +30,47 @@ async function main() { let servicePrincipalKey = secrets.getSecret("$.clientSecret", true); let tenantId = secrets.getSecret("$.tenantId", false); let subscriptionId = secrets.getSecret("$.subscriptionId", false); + let resourceManagerEndpointUrl = secrets.getSecret("$.resourceManagerEndpointUrl", false); + let environment = core.getInput("environment"); const enableAzPSSession = core.getInput('enable-AzPSSession').toLowerCase() === "true"; if (!servicePrincipalId || !servicePrincipalKey || !tenantId || !subscriptionId) { throw new Error("Not all values are present in the creds object. Ensure clientId, clientSecret, tenantId and subscriptionId are supplied."); } // Attempting Az cli login + if (environment.toLowerCase() == "azurestack") { + if (!resourceManagerEndpointUrl) { + throw new Error("resourceManagerEndpointUrl is a required parameter when environment is defined."); + } + console.log(`Unregistering cloud: "${environment}" first if it exists`); + try { + await executeAzCliCommand(`cloud set -n AzureCloud`, true); + await executeAzCliCommand(`cloud unregister -n "${environment}"`, false); + } catch (error) { + console.log(`Ignore cloud not registered error: "${error}"`); + } + console.log(`Registering cloud: "${environment}" with ARM endpoint: "${resourceManagerEndpointUrl}"`); + try { + let baseUri = resourceManagerEndpointUrl; + if (baseUri.endsWith('/')) { + baseUri = baseUri.substring(0, baseUri.length-1); // need to remove trailing / from resourceManagerEndpointUrl to correctly derive suffixes below + } + let suffixKeyvault = ".vault" + baseUri.substring(baseUri.indexOf('.')); // keyvault suffix starts with . + let suffixStorage = baseUri.substring(baseUri.indexOf('.')+1); // storage suffix starts without . + let profileVersion = "2019-03-01-hybrid"; + await executeAzCliCommand(`cloud register -n "${environment}" --endpoint-resource-manager "${resourceManagerEndpointUrl}" --suffix-keyvault-dns "${suffixKeyvault}" --suffix-storage-endpoint "${suffixStorage}" --profile "${profileVersion}"`, false); + } catch (error) { + core.error(`Error while trying to register cloud "${environment}": "${error}"`); + } + await executeAzCliCommand(`cloud set -n "${environment}"`, false); + console.log(`Done registering cloud: "${environment}"`); + } await executeAzCliCommand(`login --service-principal -u "${servicePrincipalId}" -p "${servicePrincipalKey}" --tenant "${tenantId}"`, true); await executeAzCliCommand(`account set --subscription "${subscriptionId}"`, true); isAzCLISuccess = true; if (enableAzPSSession) { // Attempting Az PS login console.log(`Running Azure PS Login`); - const spnlogin: ServicePrincipalLogin = new ServicePrincipalLogin(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId); + const spnlogin: ServicePrincipalLogin = new ServicePrincipalLogin(servicePrincipalId, servicePrincipalKey, tenantId, subscriptionId, environment, resourceManagerEndpointUrl); await spnlogin.initialize(); await spnlogin.login(); }