feat: Add the ability to use a web identity token file (#240)

* feat: Add the ability to use a web identity token file

* mark web identity token file as not required

* fix indentation

* better docs and added support for relative vs absolute paths

* bind sts context and adjust fs calls

* exclude tags if using web identity token file

* fix readme aand adjust tag removal logic

* undo re-ordering of lines

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
This commit is contained in:
Michael Nesta
2021-08-03 16:35:25 -04:00
committed by GitHub
parent ef6b971eca
commit 8053174404
4 changed files with 110 additions and 11 deletions
+40 -11
View File
@@ -1,6 +1,8 @@
const core = require('@actions/core');
const aws = require('aws-sdk');
const assert = require('assert');
const fs = require('fs');
const path = require('path');
// The max time that a GitHub action is allowed to run is 6 hours.
// That seems like a reasonable default to use if no role duration is defined.
@@ -22,7 +24,8 @@ async function assumeRole(params) {
roleDurationSeconds,
roleSessionName,
region,
roleSkipSessionTagging
roleSkipSessionTagging,
webIdentityTokenFile
} = params;
assert(
[sourceAccountId, roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined),
@@ -42,6 +45,7 @@ async function assumeRole(params) {
// Supports only 'aws' partition. Customers in other partitions ('aws-cn') will need to provide full ARN
roleArn = `arn:aws:iam::${sourceAccountId}:role/${roleArn}`;
}
const tagArray = [
{Key: 'GitHub', Value: 'Actions'},
{Key: 'Repository', Value: GITHUB_REPOSITORY},
@@ -74,15 +78,38 @@ async function assumeRole(params) {
assumeRoleRequest.ExternalId = roleExternalId;
}
return sts.assumeRole(assumeRoleRequest)
.promise()
.then(function (data) {
return {
accessKeyId: data.Credentials.AccessKeyId,
secretAccessKey: data.Credentials.SecretAccessKey,
sessionToken: data.Credentials.SessionToken,
};
});
let assumeFunction = sts.assumeRole.bind(sts);
if(isDefined(webIdentityTokenFile)) {
core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents.")
delete assumeRoleRequest.Tags;
const webIdentityTokenFilePath = path.isAbsolute(webIdentityTokenFile) ?
webIdentityTokenFile :
path.join(process.env.GITHUB_WORKSPACE, webIdentityTokenFile);
if (!fs.existsSync(webIdentityTokenFilePath)) {
throw new Error(`Web identity token file does not exist: ${webIdentityTokenFilePath}`);
}
try {
assumeRoleRequest.WebIdentityToken = await fs.promises.readFile(webIdentityTokenFilePath, 'utf8');
assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts);
} catch(error) {
throw new Error(`Web identity token file could not be read: ${error.message}`);
}
}
return assumeFunction(assumeRoleRequest)
.promise()
.then(function (data) {
return {
accessKeyId: data.Credentials.AccessKeyId,
secretAccessKey: data.Credentials.SecretAccessKey,
sessionToken: data.Credentials.SessionToken,
};
});
}
function sanitizeGithubActor(actor) {
@@ -211,6 +238,7 @@ async function run() {
const roleSessionName = core.getInput('role-session-name', { required: false }) || ROLE_SESSION_NAME;
const roleSkipSessionTaggingInput = core.getInput('role-skip-session-tagging', { required: false })|| 'false';
const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true';
const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false })
if (!region.match(REGION_REGEX)) {
throw new Error(`Region is not valid: ${region}`);
@@ -249,7 +277,8 @@ async function run() {
roleExternalId,
roleDurationSeconds,
roleSessionName,
roleSkipSessionTagging
roleSkipSessionTagging,
webIdentityTokenFile
});
exportCredentials(roleCredentials);
await validateCredentials(roleCredentials.accessKeyId);