Skip to content
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

Merged
merged 48 commits into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
18604fb
added oidc support
BALAGA-GAYATRI Sep 28, 2021
ad1e1bc
changes
BALAGA-GAYATRI Sep 28, 2021
31413bf
changes
BALAGA-GAYATRI Sep 28, 2021
66969bb
added oidc support
BALAGA-GAYATRI Sep 28, 2021
6a8dff2
changes
BALAGA-GAYATRI Sep 28, 2021
7b59ab5
changes
BALAGA-GAYATRI Sep 28, 2021
c145ca6
debug
BALAGA-GAYATRI Sep 28, 2021
066acfd
changes
BALAGA-GAYATRI Sep 28, 2021
4dd34ea
chages
BALAGA-GAYATRI Sep 28, 2021
a897d9e
changes
BALAGA-GAYATRI Sep 28, 2021
c0f045f
Update main.ts
BALAGA-GAYATRI Sep 29, 2021
45e70a2
..
BALAGA-GAYATRI Sep 29, 2021
ade5ff8
changes
BALAGA-GAYATRI Oct 1, 2021
e7b55e8
end to end changes
BALAGA-GAYATRI Oct 5, 2021
62804f4
end to end changes
BALAGA-GAYATRI Oct 5, 2021
e3b2d7a
end to end changes
BALAGA-GAYATRI Oct 5, 2021
0393c28
end to end changes
BALAGA-GAYATRI Oct 5, 2021
bf7afc0
end to end changes
BALAGA-GAYATRI Oct 5, 2021
a72df0a
end to end changes
BALAGA-GAYATRI Oct 5, 2021
fa4c64b
end to end changes
BALAGA-GAYATRI Oct 5, 2021
762d20c
end to end changes
BALAGA-GAYATRI Oct 5, 2021
5da3d81
end to end changes
BALAGA-GAYATRI Oct 6, 2021
40fbf75
changes
BALAGA-GAYATRI Oct 6, 2021
c10c739
changes
BALAGA-GAYATRI Oct 6, 2021
424bdd8
changes in login actiom
BALAGA-GAYATRI Oct 6, 2021
dc8e4aa
changes
BALAGA-GAYATRI Oct 6, 2021
b329991
changes
BALAGA-GAYATRI Oct 6, 2021
5bb957b
changes
BALAGA-GAYATRI Oct 6, 2021
91541b5
changes
BALAGA-GAYATRI Oct 6, 2021
eb0e857
changes
BALAGA-GAYATRI Oct 6, 2021
73a3131
changes
BALAGA-GAYATRI Oct 6, 2021
367292f
changes
BALAGA-GAYATRI Oct 6, 2021
0ad76c5
changes
BALAGA-GAYATRI Oct 6, 2021
fb6172f
changes
BALAGA-GAYATRI Oct 6, 2021
693b3a1
changes
BALAGA-GAYATRI Oct 6, 2021
f6ea870
Update main.ts
BALAGA-GAYATRI Oct 6, 2021
8e289ca
changes
BALAGA-GAYATRI Oct 6, 2021
b2a6a0d
Merge branch 'oidc-support' of github.com:BALAGA-GAYATRI/login into o…
BALAGA-GAYATRI Oct 6, 2021
638cdd8
changes
BALAGA-GAYATRI Oct 6, 2021
a114662
updating js
Oct 7, 2021
d75607c
updating error messages
BALAGA-GAYATRI Oct 7, 2021
00b5c81
updating error messages
BALAGA-GAYATRI Oct 7, 2021
9fc877e
nit changes
BALAGA-GAYATRI Oct 7, 2021
6a28cf1
using common arguments
BALAGA-GAYATRI Oct 8, 2021
e2ba17e
using common arguments
BALAGA-GAYATRI Oct 8, 2021
21c0c36
refactoring code
BALAGA-GAYATRI Oct 11, 2021
f38bcfa
refactoring code
BALAGA-GAYATRI Oct 11, 2021
e0eb61a
refactoring code
BALAGA-GAYATRI Oct 11, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ description: 'Authenticate to Azure and run your Az CLI or Az
inputs:
creds:
description: 'Paste output of `az ad sp create-for-rbac` as value of secret variable: AZURE_CREDENTIALS'
required: true
required: false
client-id:
description: 'ClientId of the Azure Service principal created.'
required: false
tenant-id:
description: 'TenantId of the Azure Service principal created.'
required: false
subscription-id:
description: 'Azure subscriptionId'
required: false
enable-AzPSSession:
description: 'Set this value to true to enable Azure PowerShell Login in addition to Az CLI login'
required: false
Expand Down
27 changes: 20 additions & 7 deletions lib/PowerShell/ServicePrincipalLogin.js
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) {
Expand All @@ -8,17 +27,11 @@ 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;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServicePrincipalLogin = void 0;
const core = __importStar(require("@actions/core"));
const Utils_1 = __importDefault(require("./Utilities/Utils"));
const PowerShellToolRunner_1 = __importDefault(require("./Utilities/PowerShellToolRunner"));
Expand Down
26 changes: 19 additions & 7 deletions lib/PowerShell/Utilities/PowerShellToolRunner.js
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) {
Expand All @@ -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 io = __importStar(require("@actions/io"));
const exec = __importStar(require("@actions/exec"));
Expand Down
16 changes: 14 additions & 2 deletions lib/PowerShell/Utilities/ScriptBuilder.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
"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 (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
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 __importDefault = (this && this.__importDefault) || function (mod) {
Expand Down
26 changes: 19 additions & 7 deletions lib/PowerShell/Utilities/Utils.js
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) {
Expand All @@ -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;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Expand Down
141 changes: 110 additions & 31 deletions lib/main.js
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) {
Expand All @@ -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"));
Expand All @@ -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",
Expand All @@ -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 });
Copy link
Contributor

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

Copy link
Contributor Author

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.

var servicePrincipalKey = null;
var tenantId = core.getInput('tenant-id', { required: false });
Copy link
Contributor

Choose a reason for hiding this comment

The 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/";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this fixed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: please add newlines for formatting, readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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) {
Expand Down Expand Up @@ -106,22 +161,45 @@ function main() {
console.log(`Done setting cloud: "${environment}"`);
// Attempting Az cli login
if (allowNoSubscriptionsLogin) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (allowNoSubscriptionsLogin) {
if (allowNoSubscriptionsLogin) {
commonArgs = commonArgs.concat("--allow-no-subscriptions");
}
if (enableOIDC) {
commonArgs = commonArgs.concat("--federated-token", idToken);
}
else {
commonArgs = commonArgs.concat("-p", servicePrincipalKey);
}
yield executeAzCliCommand(`login`, true, {}, commonArgs);

Choose a reason for hiding this comment

The 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",
Expand Down Expand Up @@ -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) {
Expand Down
Loading