-
Notifications
You must be signed in to change notification settings - Fork 290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added OIDC support for login action #147
Changes from 43 commits
18604fb
ad1e1bc
31413bf
66969bb
6a8dff2
7b59ab5
c145ca6
066acfd
4dd34ea
a897d9e
c0f045f
45e70a2
ade5ff8
e7b55e8
62804f4
e3b2d7a
0393c28
bf7afc0
a72df0a
fa4c64b
762d20c
5da3d81
40fbf75
c10c739
424bdd8
dc8e4aa
b329991
5bb957b
91541b5
eb0e857
73a3131
367292f
0ad76c5
fb6172f
693b3a1
f6ea870
8e289ca
b2a6a0d
638cdd8
a114662
d75607c
00b5c81
9fc877e
6a28cf1
e2ba17e
21c0c36
f38bcfa
e0eb61a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,4 +1,23 @@ | ||||||||||||||||||||||||||
"use strict"; | ||||||||||||||||||||||||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||||||||||||||||||||||||||
if (k2 === undefined) k2 = k; | ||||||||||||||||||||||||||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||||||||||||||||||||||||||
}) : (function(o, m, k, k2) { | ||||||||||||||||||||||||||
if (k2 === undefined) k2 = k; | ||||||||||||||||||||||||||
o[k2] = m[k]; | ||||||||||||||||||||||||||
})); | ||||||||||||||||||||||||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { | ||||||||||||||||||||||||||
Object.defineProperty(o, "default", { enumerable: true, value: v }); | ||||||||||||||||||||||||||
}) : function(o, v) { | ||||||||||||||||||||||||||
o["default"] = v; | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
var __importStar = (this && this.__importStar) || function (mod) { | ||||||||||||||||||||||||||
if (mod && mod.__esModule) return mod; | ||||||||||||||||||||||||||
var result = {}; | ||||||||||||||||||||||||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||||||||||||||||||||||||||
__setModuleDefault(result, mod); | ||||||||||||||||||||||||||
return result; | ||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||||||||||||||||||||||||||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||||||||||||||||||||||||||
return new (P || (P = Promise))(function (resolve, reject) { | ||||||||||||||||||||||||||
|
@@ -8,13 +27,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge | |||||||||||||||||||||||||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||||||||||||||||||||||||||
}); | ||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
var __importStar = (this && this.__importStar) || function (mod) { | ||||||||||||||||||||||||||
if (mod && mod.__esModule) return mod; | ||||||||||||||||||||||||||
var result = {}; | ||||||||||||||||||||||||||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||||||||||||||||||||||||||
result["default"] = mod; | ||||||||||||||||||||||||||
return result; | ||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
Object.defineProperty(exports, "__esModule", { value: true }); | ||||||||||||||||||||||||||
const core = __importStar(require("@actions/core")); | ||||||||||||||||||||||||||
const exec = __importStar(require("@actions/exec")); | ||||||||||||||||||||||||||
|
@@ -36,6 +48,7 @@ function main() { | |||||||||||||||||||||||||
core.exportVariable('AZURE_HTTP_USER_AGENT', userAgentString); | ||||||||||||||||||||||||||
core.exportVariable('AZUREPS_HOST_ENVIRONMENT', azurePSHostEnv); | ||||||||||||||||||||||||||
azPath = yield io.which("az", true); | ||||||||||||||||||||||||||
core.debug(`az cli version used: ${azPath}`); | ||||||||||||||||||||||||||
let azureSupportedCloudName = new Set([ | ||||||||||||||||||||||||||
"azureusgovernment", | ||||||||||||||||||||||||||
"azurechinacloud", | ||||||||||||||||||||||||||
|
@@ -53,26 +66,68 @@ function main() { | |||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||
yield executeAzCliCommand("--version", true, execOptions); | ||||||||||||||||||||||||||
core.debug(`az cli version used:\n${output}`); | ||||||||||||||||||||||||||
let creds = core.getInput('creds', { required: true }); | ||||||||||||||||||||||||||
let secrets = new actions_secret_parser_1.SecretParser(creds, actions_secret_parser_1.FormatType.JSON); | ||||||||||||||||||||||||||
let servicePrincipalId = secrets.getSecret("$.clientId", false); | ||||||||||||||||||||||||||
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 creds = core.getInput('creds', { required: false }); | ||||||||||||||||||||||||||
let secrets = creds ? new actions_secret_parser_1.SecretParser(creds, actions_secret_parser_1.FormatType.JSON) : null; | ||||||||||||||||||||||||||
let environment = core.getInput("environment").toLowerCase(); | ||||||||||||||||||||||||||
const enableAzPSSession = core.getInput('enable-AzPSSession').toLowerCase() === "true"; | ||||||||||||||||||||||||||
const allowNoSubscriptionsLogin = core.getInput('allow-no-subscriptions').toLowerCase() === "true"; | ||||||||||||||||||||||||||
if (!servicePrincipalId || !servicePrincipalKey || !tenantId) { | ||||||||||||||||||||||||||
throw new Error("Not all values are present in the creds object. Ensure clientId, clientSecret and tenantId are supplied."); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//Check for the credentials in individual parameters in the workflow. | ||||||||||||||||||||||||||
var servicePrincipalId = core.getInput('client-id', { required: false }); | ||||||||||||||||||||||||||
var servicePrincipalKey = null; | ||||||||||||||||||||||||||
var tenantId = core.getInput('tenant-id', { required: false }); | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these also be individual secrets like in creds object? |
||||||||||||||||||||||||||
var subscriptionId = core.getInput('subscription-id', { required: false }); | ||||||||||||||||||||||||||
var resourceManagerEndpointUrl = "https://management.azure.com/"; | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this fixed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. For other clouds it is different. For public cloud it is constant. |
||||||||||||||||||||||||||
var enableOIDC = true; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// If any of the individual credentials (clent_id, tenat_id, subscription_id) are missing | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: please add newlines for formatting, readability. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added |
||||||||||||||||||||||||||
if (!servicePrincipalId || !tenantId || !(subscriptionId || allowNoSubscriptionsLogin)) { | ||||||||||||||||||||||||||
//If all of the individual credentials (clent_id, tenat_id, subscription_id) are missing in workflow inputs, checking for creds object. | ||||||||||||||||||||||||||
if (!servicePrincipalId && !tenantId && (!subscriptionId || !allowNoSubscriptionsLogin)) { | ||||||||||||||||||||||||||
if (creds) { | ||||||||||||||||||||||||||
core.debug('using creds JSON...'); | ||||||||||||||||||||||||||
enableOIDC = false; | ||||||||||||||||||||||||||
servicePrincipalId = secrets.getSecret("$.clientId", true); | ||||||||||||||||||||||||||
servicePrincipalKey = secrets.getSecret("$.clientSecret", true); | ||||||||||||||||||||||||||
tenantId = secrets.getSecret("$.tenantId", true); | ||||||||||||||||||||||||||
subscriptionId = secrets.getSecret("$.subscriptionId", true); | ||||||||||||||||||||||||||
resourceManagerEndpointUrl = secrets.getSecret("$.resourceManagerEndpointUrl", false); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||
throw new Error("Credentials are not passed for Login action."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
//If any few of the individual credentials are missing | ||||||||||||||||||||||||||
else | ||||||||||||||||||||||||||
throw new Error("Few credentials are missing.ClientId,tenantId are mandatory. SubscriptionId is also mandatory if allow-no-subscriptions is not set."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
//generic checks | ||||||||||||||||||||||||||
//servicePrincipalKey is only required in non-oidc scenario. | ||||||||||||||||||||||||||
if (!servicePrincipalId || !tenantId || !(servicePrincipalKey || enableOIDC)) { | ||||||||||||||||||||||||||
throw new Error("Not all values are present in the credentials. Ensure clientId, clientSecret and tenantId are supplied."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if (!subscriptionId && !allowNoSubscriptionsLogin) { | ||||||||||||||||||||||||||
throw new Error("Not all values are present in the creds object. Ensure subscriptionId is supplied."); | ||||||||||||||||||||||||||
throw new Error("Not all values are present in the credentials. Ensure subscriptionId is supplied."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
if (!azureSupportedCloudName.has(environment)) { | ||||||||||||||||||||||||||
throw new Error("Unsupported value for environment is passed.The list of supported values for environment are ‘azureusgovernment', ‘azurechinacloud’, ‘azuregermancloud’, ‘azurecloud’ or ’azurestack’"); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
// TODO: refactor this into an Azure stack specific utility. | ||||||||||||||||||||||||||
// OIDC specific checks | ||||||||||||||||||||||||||
if (enableOIDC) { | ||||||||||||||||||||||||||
console.log('Using OIDC authentication...'); | ||||||||||||||||||||||||||
//generating ID-token | ||||||||||||||||||||||||||
var idToken = yield core.getIDToken('api://AzureADTokenExchange'); | ||||||||||||||||||||||||||
kanika1894 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
if (!!idToken) { | ||||||||||||||||||||||||||
if (environment != "azurecloud") | ||||||||||||||||||||||||||
throw new Error(`Your current environment - "${environment}" is not supported for OIDC login.`); | ||||||||||||||||||||||||||
if (enableAzPSSession) | ||||||||||||||||||||||||||
throw new Error(`Powershell login is not supported with OIDC.`); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||
throw new Error("Could not get ID token for authentication."); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
// Attempting Az cli login | ||||||||||||||||||||||||||
if (environment == "azurestack") { | ||||||||||||||||||||||||||
if (!resourceManagerEndpointUrl) { | ||||||||||||||||||||||||||
|
@@ -106,22 +161,45 @@ function main() { | |||||||||||||||||||||||||
console.log(`Done setting cloud: "${environment}"`); | ||||||||||||||||||||||||||
// Attempting Az cli login | ||||||||||||||||||||||||||
if (allowNoSubscriptionsLogin) { | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about this @BALAGA-GAYATRI |
||||||||||||||||||||||||||
let args = [ | ||||||||||||||||||||||||||
"--allow-no-subscriptions", | ||||||||||||||||||||||||||
"--service-principal", | ||||||||||||||||||||||||||
"-u", servicePrincipalId, | ||||||||||||||||||||||||||
"-p", servicePrincipalKey, | ||||||||||||||||||||||||||
"--tenant", tenantId | ||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||
var args = []; | ||||||||||||||||||||||||||
if (enableOIDC) { | ||||||||||||||||||||||||||
args = [ | ||||||||||||||||||||||||||
"--allow-no-subscriptions", | ||||||||||||||||||||||||||
"--service-principal", | ||||||||||||||||||||||||||
"-u", servicePrincipalId, | ||||||||||||||||||||||||||
"--federated-token", idToken, | ||||||||||||||||||||||||||
"--tenant", tenantId | ||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||
args = [ | ||||||||||||||||||||||||||
"--allow-no-subscriptions", | ||||||||||||||||||||||||||
"--service-principal", | ||||||||||||||||||||||||||
"-u", servicePrincipalId, | ||||||||||||||||||||||||||
"-p", servicePrincipalKey, | ||||||||||||||||||||||||||
"--tenant", tenantId | ||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
yield executeAzCliCommand(`login`, true, {}, args); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||
let args = [ | ||||||||||||||||||||||||||
"--service-principal", | ||||||||||||||||||||||||||
"-u", servicePrincipalId, | ||||||||||||||||||||||||||
"-p", servicePrincipalKey, | ||||||||||||||||||||||||||
"--tenant", tenantId | ||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||
var args = []; | ||||||||||||||||||||||||||
if (enableOIDC) { | ||||||||||||||||||||||||||
args = [ | ||||||||||||||||||||||||||
"--service-principal", | ||||||||||||||||||||||||||
"-u", servicePrincipalId, | ||||||||||||||||||||||||||
"--federated-token", idToken, | ||||||||||||||||||||||||||
"--tenant", tenantId | ||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
else { | ||||||||||||||||||||||||||
args = [ | ||||||||||||||||||||||||||
"--service-principal", | ||||||||||||||||||||||||||
"-u", servicePrincipalId, | ||||||||||||||||||||||||||
"-p", servicePrincipalKey, | ||||||||||||||||||||||||||
"--tenant", tenantId | ||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
yield executeAzCliCommand(`login`, true, {}, args); | ||||||||||||||||||||||||||
args = [ | ||||||||||||||||||||||||||
"--subscription", | ||||||||||||||||||||||||||
|
@@ -159,6 +237,7 @@ function executeAzCliCommand(command, silent, execOptions = {}, args = []) { | |||||||||||||||||||||||||
return __awaiter(this, void 0, void 0, function* () { | ||||||||||||||||||||||||||
execOptions.silent = !!silent; | ||||||||||||||||||||||||||
try { | ||||||||||||||||||||||||||
core.debug(args); | ||||||||||||||||||||||||||
yield exec.exec(`"${azPath}" ${command}`, args, execOptions); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
catch (error) { | ||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we name this var as clientId only to be same as Input name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is as per previous design only. clientID is treated as serviceprincipalId and clientSecret as serviceprincipalKey.