Skip to content

Allow inline session policies for assuming role #739

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

Merged
merged 10 commits into from
Jun 14, 2023
Merged
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
16 changes: 11 additions & 5 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49145,7 +49145,8 @@ async function assumeRole(params) {
region,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken
webIdentityToken,
inlineSessionPolicy
} = params;
assert(
[roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined),
Expand Down Expand Up @@ -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.");
Expand Down Expand Up @@ -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}`);
Expand All @@ -49429,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
}
Expand Down Expand Up @@ -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
Expand Down
16 changes: 11 additions & 5 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ async function assumeRole(params) {
region,
roleSkipSessionTagging,
webIdentityTokenFile,
webIdentityToken
webIdentityToken,
inlineSessionPolicy
} = params;
assert(
[roleToAssume, roleDurationSeconds, roleSessionName, region].every(isDefined),
Expand Down Expand Up @@ -93,6 +94,9 @@ async function assumeRole(params) {
delete assumeRoleRequest.Tags;

assumeRoleRequest.WebIdentityToken = webIdentityToken;
if (isDefined(inlineSessionPolicy)) {
Copy link
Contributor

@peterwoodworth peterwoodworth Jun 1, 2023

Choose a reason for hiding this comment

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

If this is placed here, then it will only add the policy if the role is to be assumed with OIDC. If you want to add this feature for all methods of assuming a role (which is supported), we'll need to do something similar to lines 86-88 with the externalID prop.

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.");
Expand Down Expand Up @@ -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}`);
Expand All @@ -313,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
}
Expand Down Expand Up @@ -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
Expand Down
21 changes: 21 additions & 0 deletions index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down