From d70e976da29c704174e4fc77e1b8a9894f92f579 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Sat, 5 Nov 2022 13:24:43 +0000 Subject: [PATCH 1/9] Allow to pass inline session policy as a parameter Update the action file Regenerate the dist/ content Add test --- action.yml | 3 +++ dist/index.js | 10 ++++++++-- index.js | 10 ++++++++-- index.test.js | 21 +++++++++++++++++++++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/action.yml b/action.yml index ef82373b5..66389f9f0 100644 --- a/action.yml +++ b/action.yml @@ -61,6 +61,9 @@ inputs: role-chaining: description: 'Use existing credentials from the environment to assume a new role' required: false + inline-session-policy: + description: 'Inline session policy' + required: false outputs: aws-account-id: description: 'The AWS account ID for the provided credentials' diff --git a/dist/index.js b/dist/index.js index 93e62ace4..8ceb4dfb1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49145,7 +49145,8 @@ async function assumeRole(params) { region, roleSkipSessionTagging, webIdentityTokenFile, - webIdentityToken + webIdentityToken, + inlineSessionPolicy } = params; assert( [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), @@ -49209,6 +49210,9 @@ async function assumeRole(params) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; + if(isDefined(inlineSessionPolicy)) { + assumeRoleRequest.Policy = inlineSessionPolicy; + } assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); } else if(isDefined(webIdentityTokenFile)) { core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents."); @@ -49421,6 +49425,7 @@ async function run() { const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true'; const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); const proxyServer = core.getInput('http-proxy', { required: false }); + const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false }); if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); @@ -49487,7 +49492,8 @@ async function run() { roleSessionName, roleSkipSessionTagging, webIdentityTokenFile, - webIdentityToken + webIdentityToken, + inlineSessionPolicy }) }, true); exportCredentials(roleCredentials); // We need to validate the credentials in 2 of our use-cases diff --git a/index.js b/index.js index 418063980..af47fcad1 100644 --- a/index.js +++ b/index.js @@ -29,7 +29,8 @@ async function assumeRole(params) { region, roleSkipSessionTagging, webIdentityTokenFile, - webIdentityToken + webIdentityToken, + inlineSessionPolicy } = params; assert( [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), @@ -93,6 +94,9 @@ async function assumeRole(params) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; + if(isDefined(inlineSessionPolicy)) { + assumeRoleRequest.Policy = inlineSessionPolicy; + } assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); } else if(isDefined(webIdentityTokenFile)) { core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents."); @@ -305,6 +309,7 @@ async function run() { const roleSkipSessionTagging = roleSkipSessionTaggingInput.toLowerCase() === 'true'; const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); const proxyServer = core.getInput('http-proxy', { required: false }); + const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false }); if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); @@ -371,7 +376,8 @@ async function run() { roleSessionName, roleSkipSessionTagging, webIdentityTokenFile, - webIdentityToken + webIdentityToken, + inlineSessionPolicy }) }, true); exportCredentials(roleCredentials); // We need to validate the credentials in 2 of our use-cases diff --git a/index.test.js b/index.test.js index e6655adc7..cee409c45 100644 --- a/index.test.js +++ b/index.test.js @@ -664,6 +664,27 @@ describe('Configure AWS Credentials', () => { expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); }); + test('GH OIDC With custom session policy', async () => { + const CUSTOM_SESSION_POLICY = "{ super_secure_policy }"; + process.env.GITHUB_ACTIONS = 'true'; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'inline-session-policy': CUSTOM_SESSION_POLICY})); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', + RoleSessionName: 'GitHubActions', + DurationSeconds: 3600, + Policy: CUSTOM_SESSION_POLICY, + WebIdentityToken: 'testtoken' + }); + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); + }); + test('role assumption fails after maximun trials using OIDC Provider', async () => { process.env.GITHUB_ACTIONS = 'true'; process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; From 93c8291d524f11309f767a4cc8de7bb269c0be0f Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Thu, 1 Jun 2023 00:19:59 +0100 Subject: [PATCH 2/9] Fix typos --- dist/index.js | 6 +++--- index.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dist/index.js b/dist/index.js index 8ceb4dfb1..aee5a7fba 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49434,12 +49434,12 @@ async function run() { exportRegion(region); // This wraps the logic for deciding if we should rely on the GH OIDC provider since we may need to reference - // the decision in a few differennt places. Consolidating it here makes the logic clearer elsewhere. + // the decision in a few different places. Consolidating it here makes the logic clearer elsewhere. const useGitHubOIDCProvider = () => { // The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN` - // environment variable and they won't be providing a web idenity token file or access key either. + // environment variable, and they won't be providing a web identity token file or access key either. // V2 of the action might relax this a bit and create an explicit precedence for these so that customers - // can provide as much info as they want and we will follow the established credential loading precedence. + // can provide as much info as they want, and we will follow the established credential loading precedence. return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile && !roleChaining } diff --git a/index.js b/index.js index af47fcad1..171d79c13 100644 --- a/index.js +++ b/index.js @@ -318,12 +318,12 @@ async function run() { exportRegion(region); // This wraps the logic for deciding if we should rely on the GH OIDC provider since we may need to reference - // the decision in a few differennt places. Consolidating it here makes the logic clearer elsewhere. + // the decision in a few different places. Consolidating it here makes the logic clearer elsewhere. const useGitHubOIDCProvider = () => { // The assumption here is that self-hosted runners won't be populating the `ACTIONS_ID_TOKEN_REQUEST_TOKEN` - // environment variable and they won't be providing a web idenity token file or access key either. + // environment variable, and they won't be providing a web identity token file or access key either. // V2 of the action might relax this a bit and create an explicit precedence for these so that customers - // can provide as much info as they want and we will follow the established credential loading precedence. + // can provide as much info as they want, and we will follow the established credential loading precedence. return roleToAssume && process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN && !accessKeyId && !webIdentityTokenFile && !roleChaining } From a0581db82301635d7e13b3bba41155e272715237 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Thu, 1 Jun 2023 09:44:06 +0100 Subject: [PATCH 3/9] Fix stylistic error --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 171d79c13..f0a4acb7d 100644 --- a/index.js +++ b/index.js @@ -94,7 +94,7 @@ async function assumeRole(params) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; - if(isDefined(inlineSessionPolicy)) { + if (isDefined(inlineSessionPolicy)) { assumeRoleRequest.Policy = inlineSessionPolicy; } assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); From 070d8489c615c8ecc9abde5d04535347b8a4e751 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Fri, 2 Jun 2023 19:47:30 +0100 Subject: [PATCH 4/9] Move the inline policy logic to allow assumeRole to use it as well; Update and add tests --- index.js | 7 ++++--- index.test.js | 46 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index f0a4acb7d..7deef8046 100644 --- a/index.js +++ b/index.js @@ -87,6 +87,10 @@ async function assumeRole(params) { assumeRoleRequest.ExternalId = roleExternalId; } + if (isDefined(inlineSessionPolicy)) { + assumeRoleRequest.Policy = inlineSessionPolicy; + } + let assumeFunction = sts.assumeRole.bind(sts); // These are customizations needed for the GH OIDC Provider @@ -94,9 +98,6 @@ async function assumeRole(params) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; - if (isDefined(inlineSessionPolicy)) { - assumeRoleRequest.Policy = inlineSessionPolicy; - } assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); } else if(isDefined(webIdentityTokenFile)) { core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents."); diff --git a/index.test.js b/index.test.js index cee409c45..b78be887a 100644 --- a/index.test.js +++ b/index.test.js @@ -624,6 +624,26 @@ describe('Configure AWS Credentials', () => { }) }); + test('Web identity token file with a inline session policy', async () => { + const CUSTOM_SESSION_POLICY = "{ super_secure_policy }"; + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': '/fake/token/file', 'inline-session-policy': CUSTOM_SESSION_POLICY})); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', + RoleSessionName: 'GitHubActions', + DurationSeconds: 6 * 3600, + Policy: CUSTOM_SESSION_POLICY, + WebIdentityToken: 'testpayload' + }) + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_SESSION_TOKEN); + }); + test('only role arn and region provided to use GH OIDC Token', async () => { process.env.GITHUB_ACTIONS = 'true'; process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; @@ -664,7 +684,7 @@ describe('Configure AWS Credentials', () => { expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); }); - test('GH OIDC With custom session policy', async () => { + test('GH OIDC With inline session policy', async () => { const CUSTOM_SESSION_POLICY = "{ super_secure_policy }"; process.env.GITHUB_ACTIONS = 'true'; process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; @@ -725,6 +745,30 @@ describe('Configure AWS Credentials', () => { }) }); + test('inline session policy provided', async () => { + const CUSTOM_SESSION_POLICY = "{ super_secure_policy }"; + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'inline-session-policy': CUSTOM_SESSION_POLICY})); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: 'GitHubActions', + DurationSeconds: 6 * 3600, + Tags: [ + {Key: 'GitHub', Value: 'Actions'}, + {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, + {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, + {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, + {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, + {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, + {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, + ], + Policy: CUSTOM_SESSION_POLICY + }) + }); + test('workflow name sanitized in role assumption tags', async () => { core.getInput = jest .fn() From 9346e512a4f3924504dc435c4d0f758d91a03bd5 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Sat, 3 Jun 2023 00:55:19 +0100 Subject: [PATCH 5/9] Add an option for managed policies --- action.yml | 3 +++ index.js | 15 ++++++++++-- index.test.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index 66389f9f0..7b1fc8147 100644 --- a/action.yml +++ b/action.yml @@ -64,6 +64,9 @@ inputs: inline-session-policy: description: 'Inline session policy' required: false + managed-session-policies: + description: 'List of managed session policies' + required: false outputs: aws-account-id: description: 'The AWS account ID for the provided credentials' diff --git a/index.js b/index.js index 7deef8046..f6d5d0c88 100644 --- a/index.js +++ b/index.js @@ -30,7 +30,8 @@ async function assumeRole(params) { roleSkipSessionTagging, webIdentityTokenFile, webIdentityToken, - inlineSessionPolicy + inlineSessionPolicy, + managedSessionPolicies } = params; assert( [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), @@ -91,6 +92,14 @@ async function assumeRole(params) { assumeRoleRequest.Policy = inlineSessionPolicy; } + if (isDefined(managedSessionPolicies)) { + const policyArns = [] + for (const managedSessionPolicy of managedSessionPolicies) { + policyArns.push({arn: managedSessionPolicy}) + } + assumeRoleRequest.PolicyArns = policyArns; + } + let assumeFunction = sts.assumeRole.bind(sts); // These are customizations needed for the GH OIDC Provider @@ -311,6 +320,7 @@ async function run() { const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); const proxyServer = core.getInput('http-proxy', { required: false }); const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false }); + const managedSessionPolicies = core.getInput('managed-session-policies', { required: false }) if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); @@ -378,7 +388,8 @@ async function run() { roleSkipSessionTagging, webIdentityTokenFile, webIdentityToken, - inlineSessionPolicy + inlineSessionPolicy, + managedSessionPolicies }) }, true); exportCredentials(roleCredentials); // We need to validate the credentials in 2 of our use-cases diff --git a/index.test.js b/index.test.js index b78be887a..cbf2aba9f 100644 --- a/index.test.js +++ b/index.test.js @@ -644,6 +644,26 @@ describe('Configure AWS Credentials', () => { expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_SESSION_TOKEN); }); + test('Web identity token file with a managed session policies', async () => { + const MANAGED_SESSION_POLICIES = ["arn:aws:iam::111111111111:policy/foo", "arn:aws:iam::111111111111:policy/bar"]; + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': '/fake/token/file', 'managed-session-policies': MANAGED_SESSION_POLICIES})); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', + RoleSessionName: 'GitHubActions', + DurationSeconds: 6 * 3600, + PolicyArns: [{arn: MANAGED_SESSION_POLICIES[0]}, {arn: MANAGED_SESSION_POLICIES[1]}], + WebIdentityToken: 'testpayload' + }) + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_ACCOUNT_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(4, FAKE_STS_SESSION_TOKEN); + }); + test('only role arn and region provided to use GH OIDC Token', async () => { process.env.GITHUB_ACTIONS = 'true'; process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; @@ -705,6 +725,27 @@ describe('Configure AWS Credentials', () => { expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); }); + test('GH OIDC With managed session policy', async () => { + const MANAGED_SESSION_POLICIES = ["arn:aws:iam::111111111111:policy/foo", "arn:aws:iam::111111111111:policy/bar"]; + process.env.GITHUB_ACTIONS = 'true'; + process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'managed-session-policies': MANAGED_SESSION_POLICIES})); + + await run(); + expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ + RoleArn: 'arn:aws:iam::111111111111:role/MY-ROLE', + RoleSessionName: 'GitHubActions', + DurationSeconds: 3600, + PolicyArns: [{arn: MANAGED_SESSION_POLICIES[0]}, {arn: MANAGED_SESSION_POLICIES[1]}], + WebIdentityToken: 'testtoken' + }); + expect(core.setSecret).toHaveBeenNthCalledWith(1, FAKE_STS_ACCESS_KEY_ID); + expect(core.setSecret).toHaveBeenNthCalledWith(2, FAKE_STS_SECRET_ACCESS_KEY); + expect(core.setSecret).toHaveBeenNthCalledWith(3, FAKE_STS_SESSION_TOKEN); + }); + test('role assumption fails after maximun trials using OIDC Provider', async () => { process.env.GITHUB_ACTIONS = 'true'; process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; @@ -769,6 +810,30 @@ describe('Configure AWS Credentials', () => { }) }); + test('inline session policy provided', async () => { + const MANAGED_SESSION_POLICIES = ["arn:aws:iam::111111111111:policy/foo", "arn:aws:iam::111111111111:policy/bar"]; + core.getInput = jest + .fn() + .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'managed-session-policies': MANAGED_SESSION_POLICIES})); + + await run(); + expect(mockStsAssumeRole).toHaveBeenCalledWith({ + RoleArn: ROLE_ARN, + RoleSessionName: 'GitHubActions', + DurationSeconds: 6 * 3600, + Tags: [ + {Key: 'GitHub', Value: 'Actions'}, + {Key: 'Repository', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REPOSITORY}, + {Key: 'Workflow', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_WORKFLOW}, + {Key: 'Action', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_ACTION}, + {Key: 'Actor', Value: GITHUB_ACTOR_SANITIZED}, + {Key: 'Commit', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_SHA}, + {Key: 'Branch', Value: ENVIRONMENT_VARIABLE_OVERRIDES.GITHUB_REF}, + ], + PolicyArns: [{arn: MANAGED_SESSION_POLICIES[0]}, {arn: MANAGED_SESSION_POLICIES[1]}], + }) + }); + test('workflow name sanitized in role assumption tags', async () => { core.getInput = jest .fn() From e3e20b71b65a73bbfc95bf86d17bc9717c14ece7 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Sat, 3 Jun 2023 00:58:01 +0100 Subject: [PATCH 6/9] Regenerate the dist/ files --- dist/index.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/dist/index.js b/dist/index.js index aee5a7fba..0378fc50e 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49146,7 +49146,8 @@ async function assumeRole(params) { roleSkipSessionTagging, webIdentityTokenFile, webIdentityToken, - inlineSessionPolicy + inlineSessionPolicy, + managedSessionPolicies } = params; assert( [roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined), @@ -49203,6 +49204,18 @@ async function assumeRole(params) { assumeRoleRequest.ExternalId = roleExternalId; } + if (isDefined(inlineSessionPolicy)) { + assumeRoleRequest.Policy = inlineSessionPolicy; + } + + if (isDefined(managedSessionPolicies)) { + const policyArns = [] + for (const managedSessionPolicy of managedSessionPolicies) { + policyArns.push({arn: managedSessionPolicy}) + } + assumeRoleRequest.PolicyArns = policyArns; + } + let assumeFunction = sts.assumeRole.bind(sts); // These are customizations needed for the GH OIDC Provider @@ -49210,9 +49223,6 @@ async function assumeRole(params) { delete assumeRoleRequest.Tags; assumeRoleRequest.WebIdentityToken = webIdentityToken; - if(isDefined(inlineSessionPolicy)) { - assumeRoleRequest.Policy = inlineSessionPolicy; - } assumeFunction = sts.assumeRoleWithWebIdentity.bind(sts); } else if(isDefined(webIdentityTokenFile)) { core.debug("webIdentityTokenFile provided. Will call sts:AssumeRoleWithWebIdentity and take session tags from token contents."); @@ -49426,6 +49436,7 @@ async function run() { const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); const proxyServer = core.getInput('http-proxy', { required: false }); const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false }); + const managedSessionPolicies = core.getInput('managed-session-policies', { required: false }) if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); @@ -49493,7 +49504,8 @@ async function run() { roleSkipSessionTagging, webIdentityTokenFile, webIdentityToken, - inlineSessionPolicy + inlineSessionPolicy, + managedSessionPolicies }) }, true); exportCredentials(roleCredentials); // We need to validate the credentials in 2 of our use-cases From c4a067686da56886c1d499166b9b6aaa1700ad53 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Mon, 5 Jun 2023 23:53:52 +0100 Subject: [PATCH 7/9] Use multiline input for managed policies --- dist/index.js | 4 ++-- index.js | 4 ++-- index.test.js | 22 ++++++++++++++++++---- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/dist/index.js b/dist/index.js index 0378fc50e..0f1c7b507 100644 --- a/dist/index.js +++ b/dist/index.js @@ -49208,7 +49208,7 @@ async function assumeRole(params) { assumeRoleRequest.Policy = inlineSessionPolicy; } - if (isDefined(managedSessionPolicies)) { + if (managedSessionPolicies && managedSessionPolicies.length) { const policyArns = [] for (const managedSessionPolicy of managedSessionPolicies) { policyArns.push({arn: managedSessionPolicy}) @@ -49436,7 +49436,7 @@ async function run() { const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); const proxyServer = core.getInput('http-proxy', { required: false }); const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false }); - const managedSessionPolicies = core.getInput('managed-session-policies', { required: false }) + const managedSessionPolicies = core.getMultilineInput('managed-session-policies', { required: false }) if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); diff --git a/index.js b/index.js index f6d5d0c88..a67529d96 100644 --- a/index.js +++ b/index.js @@ -92,7 +92,7 @@ async function assumeRole(params) { assumeRoleRequest.Policy = inlineSessionPolicy; } - if (isDefined(managedSessionPolicies)) { + if (managedSessionPolicies && managedSessionPolicies.length) { const policyArns = [] for (const managedSessionPolicy of managedSessionPolicies) { policyArns.push({arn: managedSessionPolicy}) @@ -320,7 +320,7 @@ async function run() { const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false }); const proxyServer = core.getInput('http-proxy', { required: false }); const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false }); - const managedSessionPolicies = core.getInput('managed-session-policies', { required: false }) + const managedSessionPolicies = core.getMultilineInput('managed-session-policies', { required: false }) if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); diff --git a/index.test.js b/index.test.js index cbf2aba9f..0686b5edf 100644 --- a/index.test.js +++ b/index.test.js @@ -45,6 +45,7 @@ const DEFAULT_INPUTS = { 'aws-region': FAKE_REGION, 'mask-aws-account-id': 'TRUE' }; +const DEFAULT_MULTILINE_INPUTS = {} const ASSUME_ROLE_INPUTS = {...CREDS_INPUTS, 'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION}; const mockStsCallerIdentity = jest.fn(); @@ -90,6 +91,10 @@ describe('Configure AWS Credentials', () => { .fn() .mockImplementation(mockGetInput(DEFAULT_INPUTS)); + core.getMultilineInput = jest + .fn() + .mockImplementation(mockGetInput(DEFAULT_MULTILINE_INPUTS)); + core.getIDToken = jest .fn() .mockImplementation(() => { @@ -648,7 +653,10 @@ describe('Configure AWS Credentials', () => { const MANAGED_SESSION_POLICIES = ["arn:aws:iam::111111111111:policy/foo", "arn:aws:iam::111111111111:policy/bar"]; core.getInput = jest .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': '/fake/token/file', 'managed-session-policies': MANAGED_SESSION_POLICIES})); + .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'web-identity-token-file': '/fake/token/file'})); + core.getMultilineInput = jest + .fn() + .mockImplementation(mockGetInput({'managed-session-policies': MANAGED_SESSION_POLICIES})) await run(); expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ @@ -731,7 +739,10 @@ describe('Configure AWS Credentials', () => { process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'test-token'; core.getInput = jest .fn() - .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION, 'managed-session-policies': MANAGED_SESSION_POLICIES})); + .mockImplementation(mockGetInput({'role-to-assume': ROLE_ARN, 'aws-region': FAKE_REGION})); + core.getMultilineInput = jest + .fn() + .mockImplementation(mockGetInput({'managed-session-policies': MANAGED_SESSION_POLICIES})) await run(); expect(mockStsAssumeRoleWithWebIdentity).toHaveBeenCalledWith({ @@ -810,11 +821,14 @@ describe('Configure AWS Credentials', () => { }) }); - test('inline session policy provided', async () => { + test('managed session policy provided', async () => { const MANAGED_SESSION_POLICIES = ["arn:aws:iam::111111111111:policy/foo", "arn:aws:iam::111111111111:policy/bar"]; core.getInput = jest .fn() - .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS, 'managed-session-policies': MANAGED_SESSION_POLICIES})); + .mockImplementation(mockGetInput({...ASSUME_ROLE_INPUTS})); + core.getMultilineInput = jest + .fn() + .mockImplementation(mockGetInput({'managed-session-policies': MANAGED_SESSION_POLICIES})) await run(); expect(mockStsAssumeRole).toHaveBeenCalledWith({ From bddf76d6f8fa5a8c5ff6004fd562c53393f6d01c Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Tue, 6 Jun 2023 00:29:32 +0100 Subject: [PATCH 8/9] Update readme --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index d3a9afc70..b791133bf 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,51 @@ within the Action. You can skip this session tagging by providing role-skip-session-tagging: true ``` +### Inline session policy +The inline session policy is an IAM policy in stringified JSON format that you +want to use as an inline session policy. Depending on preferences, the JSON could be +written on a single line like this: +```yaml + uses: aws-actions/configure-aws-credentials@v2 + with: + inline-session-policy: '{"Version":"2012-10-17","Statement":[{"Sid":"Stmt1","Effect":"Allow","Action":"s3:List*","Resource":"*"}]}' +``` +Or we can have a nicely formatted JSON as well: +```yaml + uses: aws-actions/configure-aws-credentials@v2 + with: + inline-session-policy: >- + { + "Version": "2012-10-17", + "Statement": [ + { + "Sid":"Stmt1", + "Effect":"Allow", + "Action":"s3:List*", + "Resource":"*" + } + ] + } +``` + +### Managed session policies +The managed session policies are Amazon Resource Names (ARNs) of the IAM managed policies +that you want to use as managed session policies. The policies must exist in the same account as the role. +You can pass a single managed policy like this: +```yaml + uses: aws-actions/configure-aws-credentials@v2 + with: + managed-session-policies: arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess +``` +And we can pass multiple managed policies likes this: +```yaml + uses: aws-actions/configure-aws-credentials@v2 + with: + managed-session-policies: | + arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess + arn:aws:iam::aws:policy/AmazonS3OutpostsReadOnlyAccess +``` + ## Self-Hosted Runners If you run your GitHub Actions in a From de58fe7f28900bcebd1df83367cbd88aaec00894 Mon Sep 17 00:00:00 2001 From: dimitar-hristov Date: Tue, 6 Jun 2023 00:32:28 +0100 Subject: [PATCH 9/9] Update readme --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b791133bf..5c487f4c2 100644 --- a/README.md +++ b/README.md @@ -321,9 +321,8 @@ within the Action. You can skip this session tagging by providing ``` ### Inline session policy -The inline session policy is an IAM policy in stringified JSON format that you -want to use as an inline session policy. Depending on preferences, the JSON could be -written on a single line like this: +An IAM policy in stringified JSON format that you want to use as an inline session policy. +Depending on preferences, the JSON could be written on a single line like this: ```yaml uses: aws-actions/configure-aws-credentials@v2 with: @@ -348,9 +347,8 @@ Or we can have a nicely formatted JSON as well: ``` ### Managed session policies -The managed session policies are Amazon Resource Names (ARNs) of the IAM managed policies -that you want to use as managed session policies. The policies must exist in the same account as the role. -You can pass a single managed policy like this: +The Amazon Resource Names (ARNs) of the IAM managed policies that you want to use as managed session policies. +The policies must exist in the same account as the role. You can pass a single managed policy like this: ```yaml uses: aws-actions/configure-aws-credentials@v2 with: