From f5f46df07723e29a0e1c53e34fc919a1a3a3d4ba Mon Sep 17 00:00:00 2001 From: ubaid-ansari21 Date: Thu, 24 Aug 2023 13:53:51 +0530 Subject: [PATCH 1/7] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6266a294..439aef616 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ with the `role-duration-seconds` input. - By default, your account ID will not be masked in workflow logs. This was changed from being masked by default in the previous version. AWS does consider account IDs as sensitive information, so this change reflects that stance. You -can rever to the old default and mask your account ID in workflow logs by +can revert to the old default and mask your account ID in workflow logs by setting the `mask-aws-account-id` input to `true`. **New features** From fbbf3856572651519d3cce38635ca41a2e5aecc8 Mon Sep 17 00:00:00 2001 From: Tom Keller <1083460+kellertk@users.noreply.github.com> Date: Thu, 24 Aug 2023 13:05:29 -0700 Subject: [PATCH 2/7] feat: add config option for special character handling (#795) --- README.md | 9 +++++ action.yml | 3 ++ src/assumeRole.ts | 5 +-- src/helpers.ts | 9 +++-- src/index.ts | 62 ++++++++++++++++++++----------- test/index.test.ts | 91 +++++++++++++++++++++++----------------------- 6 files changed, 105 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index d6266a294..8423a1c82 100644 --- a/README.md +++ b/README.md @@ -268,6 +268,15 @@ Your account ID is not masked by default in workflow logs since it's not conside #### Unset current credentials Sometimes, existing credentials in your runner can get in the way of the intended outcome, and the recommended solution is to include another step in your workflow which unsets the environment variables set by this action. Now if you set the `unset-current-credentials` input to `true`, the workaround is made eaiser +#### Special characters in AWS_SECRET_ACCESS_KEY +Some edge cases are unable to properly parse an `AWS_SECRET_ACCESS_KEY` if it +contains special characters. For more information, please see the +[AWS CLI documentation](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-troubleshooting.html#tshoot-signature-does-not-match). +If you set the `special-characters-workaround` option, this action will +continually retry fetching credentials until we get one that does not have +special characters. This option overrides the `disable-retry` and +`retry-max-attempts` options. + ## OIDC We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services) to get short-lived AWS credentials needed for your actions. When using OIDC, this action will create a JWT unique to the workflow run, and it will use this JWT to assume the role. For this action to create the JWT, it is required for your workflow to have the `id-token: write` permission: diff --git a/action.yml b/action.yml index f4cff8099..b6ef5ddfd 100644 --- a/action.yml +++ b/action.yml @@ -70,6 +70,9 @@ inputs: retry-max-attempts: description: The maximum number of attempts it will attempt to retry the assume role call. By default it will retry 12 times required: false + special-characters-workaround: + description: Some environments do not support special characters in AWS_SECRET_ACCESS_KEY. This option will retry fetching credentials until the secret access key does not contain special characters. This option overrides disable-retry and retry-max-attempts. This option is disabled by default + required: false outputs: aws-account-id: description: The AWS account ID for the provided credentials diff --git a/src/assumeRole.ts b/src/assumeRole.ts index e756ace7f..4e6bd7d41 100644 --- a/src/assumeRole.ts +++ b/src/assumeRole.ts @@ -5,7 +5,7 @@ import * as core from '@actions/core'; import type { AssumeRoleCommandInput, STSClient, Tag } from '@aws-sdk/client-sts'; import { AssumeRoleCommand, AssumeRoleWithWebIdentityCommand } from '@aws-sdk/client-sts'; import type { CredentialsClient } from './CredentialsClient'; -import { errorMessage, isDefined, sanitizeGitHubVariables, verifyKeys } from './helpers'; +import { errorMessage, isDefined, sanitizeGitHubVariables } from './helpers'; async function assumeRoleWithOIDC(params: AssumeRoleCommandInput, client: STSClient, webIdentityToken: string) { delete params.Tags; @@ -17,7 +17,6 @@ async function assumeRoleWithOIDC(params: AssumeRoleCommandInput, client: STSCli WebIdentityToken: webIdentityToken, }) ); - verifyKeys(creds.Credentials); return creds; } catch (error) { throw new Error(`Could not assume role with OIDC: ${errorMessage(error)}`); @@ -49,7 +48,6 @@ async function assumeRoleWithWebIdentityTokenFile( WebIdentityToken: webIdentityToken, }) ); - verifyKeys(creds.Credentials); return creds; } catch (error) { throw new Error(`Could not assume role with web identity token file: ${errorMessage(error)}`); @@ -60,7 +58,6 @@ async function assumeRoleWithCredentials(params: AssumeRoleCommandInput, client: core.info('Assuming role with user credentials'); try { const creds = await client.send(new AssumeRoleCommand({ ...params })); - verifyKeys(creds.Credentials); return creds; } catch (error) { throw new Error(`Could not assume role with user credentials: ${errorMessage(error)}`); diff --git a/src/helpers.ts b/src/helpers.ts index 988ef3930..08e19e73f 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -93,18 +93,21 @@ export function reset() { export function verifyKeys(creds: Partial | undefined) { if (!creds) { - return; + return false; } if (creds.AccessKeyId) { if (SPECIAL_CHARS_REGEX.test(creds.AccessKeyId)) { - throw new Error('AccessKeyId contains special characters.'); + core.debug('AccessKeyId contains special characters.'); + return false; } } if (creds.SecretAccessKey) { if (SPECIAL_CHARS_REGEX.test(creds.SecretAccessKey)) { - throw new Error('SecretAccessKey contains special characters.'); + core.debug('SecretAccessKey contains special characters.'); + return false; } } + return true; } // Retries the promise with exponential backoff if the error isRetryable up to maxRetries time. diff --git a/src/index.ts b/src/index.ts index 6c80d3cf6..a3668560c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import * as core from '@actions/core'; +import type { AssumeRoleCommandOutput } from '@aws-sdk/client-sts'; import { assumeRole } from './assumeRole'; import { CredentialsClient } from './CredentialsClient'; import { @@ -8,6 +9,7 @@ import { exportCredentials, exportAccountId, unsetCredentials, + verifyKeys, } from './helpers'; const DEFAULT_ROLE_DURATION = 3600; // One hour (seconds) @@ -43,10 +45,20 @@ export async function run() { const unsetCurrentCredentialsInput = core.getInput('unset-current-credentials', { required: false }) || 'false'; const unsetCurrentCredentials = unsetCurrentCredentialsInput.toLowerCase() === 'true'; const disableRetryInput = core.getInput('disable-retry', { required: false }) || 'false'; - const disableRetry = disableRetryInput.toLowerCase() === 'true'; + let disableRetry = disableRetryInput.toLowerCase() === 'true'; + const specialCharacterWorkaroundInput = + core.getInput('special-characters-workaround', { required: false }) || 'false'; + const specialCharacterWorkaround = specialCharacterWorkaroundInput.toLowerCase() === 'true'; let maxRetries = parseInt(core.getInput('retry-max-attempts', { required: false })) || 12; - if (maxRetries < 1) { - maxRetries = 1; + switch (true) { + case specialCharacterWorkaround: + // 😳 + maxRetries = Number.MAX_SAFE_INTEGER; + disableRetry = false; + break; + case maxRetries < 1: + maxRetries = 1; + break; } for (const managedSessionPolicy of managedSessionPoliciesInput) { managedSessionPolicies.push({ arn: managedSessionPolicy }); @@ -129,25 +141,30 @@ export async function run() { // Get role credentials if configured to do so if (roleToAssume) { - const roleCredentials = await retryAndBackoff( - async () => { - return assumeRole({ - credentialsClient, - sourceAccountId, - roleToAssume, - roleExternalId, - roleDuration, - roleSessionName, - roleSkipSessionTagging, - webIdentityTokenFile, - webIdentityToken, - inlineSessionPolicy, - managedSessionPolicies, - }); - }, - !disableRetry, - maxRetries - ); + let roleCredentials: AssumeRoleCommandOutput; + do { + // eslint-disable-next-line no-await-in-loop + roleCredentials = await retryAndBackoff( + async () => { + return assumeRole({ + credentialsClient, + sourceAccountId, + roleToAssume, + roleExternalId, + roleDuration, + roleSessionName, + roleSkipSessionTagging, + webIdentityTokenFile, + webIdentityToken, + inlineSessionPolicy, + managedSessionPolicies, + }); + }, + !disableRetry, + maxRetries + ); + // eslint-disable-next-line no-unmodified-loop-condition + } while (specialCharacterWorkaround && !verifyKeys(roleCredentials.Credentials)); core.info(`Authenticated as assumedRoleId ${roleCredentials.AssumedRoleUser!.AssumedRoleId!}`); exportCredentials(roleCredentials.Credentials, outputCredentials); // We need to validate the credentials in 2 of our use-cases @@ -173,6 +190,7 @@ export async function run() { } /* c8 ignore start */ +/* istanbul ignore next */ if (require.main === module) { (async () => { await run(); diff --git a/test/index.test.ts b/test/index.test.ts index 4b83bceb3..50a88dd69 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -556,61 +556,62 @@ describe('Configure AWS Credentials', () => { expect(mockedSTS.commandCalls(AssumeRoleWithWebIdentityCommand).length).toEqual(1); }); - test('role assumption fails if access key id contains special characters', async () => { - jest.spyOn(core, 'getInput').mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS })); - - mockedSTS.on(AssumeRoleCommand).resolves({ - Credentials: { - AccessKeyId: 'asdf+', - SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, - SessionToken: FAKE_STS_SESSION_TOKEN, - Expiration: new Date(8640000000000000), - }, - }); - - await run(); - - expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(12); - expect(core.setFailed).toHaveBeenCalledWith( - 'Could not assume role with user credentials: AccessKeyId contains special characters.' - ); - }); - - test('role assumption fails if secret access key contains special characters', async () => { - jest.spyOn(core, 'getInput').mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS })); + test('special character workaround works for AWS_ACCESS_KEY_ID', async () => { + jest + .spyOn(core, 'getInput') + .mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'special-characters-workaround': 'true' })); - mockedSTS.on(AssumeRoleCommand).resolves({ - Credentials: { - AccessKeyId: FAKE_STS_ACCESS_KEY_ID, - SecretAccessKey: 'asdf+', - SessionToken: FAKE_STS_SESSION_TOKEN, - Expiration: new Date(8640000000000000), - }, - }); + mockedSTS + .on(AssumeRoleCommand) + .resolvesOnce({ + Credentials: { + AccessKeyId: FAKE_STS_ACCESS_KEY_ID, + SecretAccessKey: 'asdf+', + SessionToken: FAKE_STS_SESSION_TOKEN, + Expiration: new Date(8640000000000000), + }, + }) + .resolves({ + Credentials: { + AccessKeyId: FAKE_STS_ACCESS_KEY_ID, + SecretAccessKey: 'asdf', + SessionToken: FAKE_STS_SESSION_TOKEN, + Expiration: new Date(8640000000000000), + }, + }); await run(); - expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(12); - expect(core.setFailed).toHaveBeenCalledWith( - 'Could not assume role with user credentials: SecretAccessKey contains special characters.' - ); + expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(2); }); - test('role assumption succeeds if keys have no special characters', async () => { - jest.spyOn(core, 'getInput').mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS })); + test('special character workaround works for AWS_SECRET_ACCESS_KEY', async () => { + jest + .spyOn(core, 'getInput') + .mockImplementation(mockGetInput({ ...ASSUME_ROLE_INPUTS, 'special-characters-workaround': 'true' })); - mockedSTS.on(AssumeRoleCommand).resolves({ - Credentials: { - AccessKeyId: FAKE_STS_ACCESS_KEY_ID, - SecretAccessKey: FAKE_STS_SECRET_ACCESS_KEY, - SessionToken: FAKE_STS_SESSION_TOKEN, - Expiration: new Date(8640000000000000), - }, - }); + mockedSTS + .on(AssumeRoleCommand) + .resolvesOnce({ + Credentials: { + AccessKeyId: FAKE_STS_ACCESS_KEY_ID, + SecretAccessKey: 'asdf+', + SessionToken: FAKE_STS_SESSION_TOKEN, + Expiration: new Date(8640000000000000), + }, + }) + .resolves({ + Credentials: { + AccessKeyId: FAKE_STS_ACCESS_KEY_ID, + SecretAccessKey: 'asdf', + SessionToken: FAKE_STS_SESSION_TOKEN, + Expiration: new Date(8640000000000000), + }, + }); await run(); - expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(1); + expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(2); }); test('max retries is configurable', async () => { From a96263310b5fbb05581ca9399ad02dac21664aff Mon Sep 17 00:00:00 2001 From: Tom Keller <1083460+kellertk@users.noreply.github.com> Date: Thu, 24 Aug 2023 13:58:54 -0700 Subject: [PATCH 3/7] feat: special character check (#797) * feat: add config option for special character handling * chore: update dist files --- dist/cleanup/index.js | 9 +++-- dist/cleanup/src/helpers.d.ts | 2 +- dist/index.js | 63 ++++++++++++++++++++++------------- src/index.ts | 2 +- 4 files changed, 47 insertions(+), 29 deletions(-) diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 1b0dd75c2..d5105a28d 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -20748,18 +20748,21 @@ function reset() { exports.reset = reset; function verifyKeys(creds) { if (!creds) { - return; + return false; } if (creds.AccessKeyId) { if (SPECIAL_CHARS_REGEX.test(creds.AccessKeyId)) { - throw new Error('AccessKeyId contains special characters.'); + core.debug('AccessKeyId contains special characters.'); + return false; } } if (creds.SecretAccessKey) { if (SPECIAL_CHARS_REGEX.test(creds.SecretAccessKey)) { - throw new Error('SecretAccessKey contains special characters.'); + core.debug('SecretAccessKey contains special characters.'); + return false; } } + return true; } exports.verifyKeys = verifyKeys; // Retries the promise with exponential backoff if the error isRetryable up to maxRetries time. diff --git a/dist/cleanup/src/helpers.d.ts b/dist/cleanup/src/helpers.d.ts index 1df20f04b..350f3ed45 100644 --- a/dist/cleanup/src/helpers.d.ts +++ b/dist/cleanup/src/helpers.d.ts @@ -9,7 +9,7 @@ export declare function defaultSleep(ms: number): Promise; declare let sleep: typeof defaultSleep; export declare function withsleep(s: typeof sleep): void; export declare function reset(): void; -export declare function verifyKeys(creds: Partial | undefined): void; +export declare function verifyKeys(creds: Partial | undefined): boolean; export declare function retryAndBackoff(fn: () => Promise, isRetryable: boolean, maxRetries?: number, retries?: number, base?: number): Promise; export declare function errorMessage(error: unknown): string; export declare function isDefined(i: T | undefined | null): i is T; diff --git a/dist/index.js b/dist/index.js index ca5eefa0d..a384a2c78 100644 --- a/dist/index.js +++ b/dist/index.js @@ -113,7 +113,6 @@ async function assumeRoleWithOIDC(params, client, webIdentityToken) { ...params, WebIdentityToken: webIdentityToken, })); - (0, helpers_1.verifyKeys)(creds.Credentials); return creds; } catch (error) { @@ -136,7 +135,6 @@ async function assumeRoleWithWebIdentityTokenFile(params, client, webIdentityTok ...params, WebIdentityToken: webIdentityToken, })); - (0, helpers_1.verifyKeys)(creds.Credentials); return creds; } catch (error) { @@ -147,7 +145,6 @@ async function assumeRoleWithCredentials(params, client) { core.info('Assuming role with user credentials'); try { const creds = await client.send(new client_sts_1.AssumeRoleCommand({ ...params })); - (0, helpers_1.verifyKeys)(creds.Credentials); return creds; } catch (error) { @@ -337,18 +334,21 @@ function reset() { exports.reset = reset; function verifyKeys(creds) { if (!creds) { - return; + return false; } if (creds.AccessKeyId) { if (SPECIAL_CHARS_REGEX.test(creds.AccessKeyId)) { - throw new Error('AccessKeyId contains special characters.'); + core.debug('AccessKeyId contains special characters.'); + return false; } } if (creds.SecretAccessKey) { if (SPECIAL_CHARS_REGEX.test(creds.SecretAccessKey)) { - throw new Error('SecretAccessKey contains special characters.'); + core.debug('SecretAccessKey contains special characters.'); + return false; } } + return true; } exports.verifyKeys = verifyKeys; // Retries the promise with exponential backoff if the error isRetryable up to maxRetries time. @@ -450,10 +450,19 @@ async function run() { const unsetCurrentCredentialsInput = core.getInput('unset-current-credentials', { required: false }) || 'false'; const unsetCurrentCredentials = unsetCurrentCredentialsInput.toLowerCase() === 'true'; const disableRetryInput = core.getInput('disable-retry', { required: false }) || 'false'; - const disableRetry = disableRetryInput.toLowerCase() === 'true'; + let disableRetry = disableRetryInput.toLowerCase() === 'true'; + const specialCharacterWorkaroundInput = core.getInput('special-characters-workaround', { required: false }) || 'false'; + const specialCharacterWorkaround = specialCharacterWorkaroundInput.toLowerCase() === 'true'; let maxRetries = parseInt(core.getInput('retry-max-attempts', { required: false })) || 12; - if (maxRetries < 1) { - maxRetries = 1; + switch (true) { + case specialCharacterWorkaround: + // 😳 + disableRetry = false; + maxRetries = 12; + break; + case maxRetries < 1: + maxRetries = 1; + break; } for (const managedSessionPolicy of managedSessionPoliciesInput) { managedSessionPolicies.push({ arn: managedSessionPolicy }); @@ -522,21 +531,26 @@ async function run() { } // Get role credentials if configured to do so if (roleToAssume) { - const roleCredentials = await (0, helpers_1.retryAndBackoff)(async () => { - return (0, assumeRole_1.assumeRole)({ - credentialsClient, - sourceAccountId, - roleToAssume, - roleExternalId, - roleDuration, - roleSessionName, - roleSkipSessionTagging, - webIdentityTokenFile, - webIdentityToken, - inlineSessionPolicy, - managedSessionPolicies, - }); - }, !disableRetry, maxRetries); + let roleCredentials; + do { + // eslint-disable-next-line no-await-in-loop + roleCredentials = await (0, helpers_1.retryAndBackoff)(async () => { + return (0, assumeRole_1.assumeRole)({ + credentialsClient, + sourceAccountId, + roleToAssume, + roleExternalId, + roleDuration, + roleSessionName, + roleSkipSessionTagging, + webIdentityTokenFile, + webIdentityToken, + inlineSessionPolicy, + managedSessionPolicies, + }); + }, !disableRetry, maxRetries); + // eslint-disable-next-line no-unmodified-loop-condition + } while (specialCharacterWorkaround && !(0, helpers_1.verifyKeys)(roleCredentials.Credentials)); core.info(`Authenticated as assumedRoleId ${roleCredentials.AssumedRoleUser.AssumedRoleId}`); (0, helpers_1.exportCredentials)(roleCredentials.Credentials, outputCredentials); // We need to validate the credentials in 2 of our use-cases @@ -562,6 +576,7 @@ async function run() { } exports.run = run; /* c8 ignore start */ +/* istanbul ignore next */ if (require.main === require.cache[eval('__filename')]) { (async () => { await run(); diff --git a/src/index.ts b/src/index.ts index a3668560c..2db4e03a9 100644 --- a/src/index.ts +++ b/src/index.ts @@ -53,8 +53,8 @@ export async function run() { switch (true) { case specialCharacterWorkaround: // 😳 - maxRetries = Number.MAX_SAFE_INTEGER; disableRetry = false; + maxRetries = 12; break; case maxRetries < 1: maxRetries = 1; From 76997ececd8d4785d64ed4d607e79638a36bebf6 Mon Sep 17 00:00:00 2001 From: Peter Woodworth <44349620+peterwoodworth@users.noreply.github.com> Date: Thu, 24 Aug 2023 14:38:12 -0700 Subject: [PATCH 4/7] fix: action fails when intending to use existing credentials (#796) * fix: action fails when intending to use existing credentials * fix: action fails when intending to use existing credentials * fix: action fails when intending to use existing credentials * fix: action fails when intending to use existing credentials * fix: action fails when intending to use existing credentials * fix: action fails when intending to use existing credentials --------- Co-authored-by: Tom Keller <1083460+kellertk@users.noreply.github.com> --- .github/workflows/tests-integ.yml | 22 ++++++++++++++++++++++ README.md | 16 +++++++++------- dist/index.js | 9 ++++++--- src/index.ts | 11 ++++++++--- test/index.test.ts | 22 +++++++++++++++++++++- 5 files changed, 66 insertions(+), 14 deletions(-) diff --git a/.github/workflows/tests-integ.yml b/.github/workflows/tests-integ.yml index 0ed6c2e3e..84dd38466 100644 --- a/.github/workflows/tests-integ.yml +++ b/.github/workflows/tests-integ.yml @@ -48,6 +48,28 @@ jobs: role-to-assume: ${{ secrets.SECRETS_AWS_ROLE_TO_ASSUME }} role-session-name: IntegAccessKeysAssumeRole role-external-id: ${{ secrets.SECRETS_AWS_ROLE_EXTERNAL_ID }} + integ-access-keys-env: + strategy: + fail-fast: false + matrix: + os: [[self-hosted, linux-fargate], windows-latest, ubuntu-latest, macos-latest] + node: [14, 16, 18] + name: Run access key from env integ tests + runs-on: ${{ matrix.os }} + timeout-minutes: 30 + steps: + - name: "Checkout repository" + uses: actions/checkout@v3 + - name: Integ test for access keys + uses: ./ + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + with: + aws-region: us-west-2 + role-to-assume: ${{ secrets.SECRETS_AWS_ROLE_TO_ASSUME }} + role-session-name: IntegAccessKeysAssumeRole + role-external-id: ${{ secrets.SECRETS_AWS_ROLE_EXTERNAL_ID }} integ-iam-user: strategy: fail-fast: false diff --git a/README.md b/README.md index 8423a1c82..7c51facd1 100644 --- a/README.md +++ b/README.md @@ -161,13 +161,15 @@ We recommend using [GitHub's OIDC provider](https://docs.github.com/en/actions/d The following table describes which method is used based on which values are supplied to the Action: -| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` | `role-chaining` | -| --------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- | - | -| [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | | | -| IAM User | ✔ | | | | -| Assume Role using IAM User credentials | ✔ | ✔ | | | -| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ | | -| Assume Role using existing credentials | | ✔ | | ✔ | +| **Identity Used** | `aws-access-key-id` | `role-to-assume` | `web-identity-token-file` | `role-chaining` | `id-token` permission +| --------------------------------------------------------------- | ------------------- | ---------------- | ------------------------- | - | - | +| [✅ Recommended] Assume Role directly using GitHub OIDC provider | | ✔ | | | ✔ | +| IAM User | ✔ | | | | | +| Assume Role using IAM User credentials | ✔ | ✔ | | | | +| Assume Role using WebIdentity Token File credentials | | ✔ | ✔ | | | +| Assume Role using existing credentials | | ✔ | | ✔ | | + +*Note: `role-chaining` is not necessary to use existing credentials in every use case. If you're getting a "Credentials loaded by the SDK do not match" error, try enabling this prop. ### Credential Lifetime The default session duration is **1 hour**. diff --git a/dist/index.js b/dist/index.js index a384a2c78..660921077 100644 --- a/dist/index.js +++ b/dist/index.js @@ -478,7 +478,8 @@ async function run() { !AccessKeyId && !process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] && !roleChaining) { - core.info('It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?'); + core.info('It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission? ' + + 'If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.'); } return (!!roleToAssume && !!process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] && @@ -519,10 +520,12 @@ async function run() { // in any error messages. (0, helpers_1.exportCredentials)({ AccessKeyId, SecretAccessKey, SessionToken }); } - else if (!webIdentityTokenFile && !roleChaining) { + else if (!webIdentityTokenFile && + !roleChaining && + !(process.env['AWS_ACCESS_KEY_ID'] && process.env['AWS_SECRET_ACCESS_KEY'])) { throw new Error('Could not determine how to assume credentials. Please check your inputs and try again.'); } - if (AccessKeyId || roleChaining) { + if (AccessKeyId || roleChaining || (process.env['AWS_ACCESS_KEY_ID'] && process.env['AWS_SECRET_ACCESS_KEY'])) { // Validate that the SDK can actually pick up credentials. // This validates cases where this action is using existing environment credentials, // and cases where the user intended to provide input credentials but the secrets inputs resolved to empty strings. diff --git a/src/index.ts b/src/index.ts index 2db4e03a9..cc24be861 100644 --- a/src/index.ts +++ b/src/index.ts @@ -78,7 +78,8 @@ export async function run() { !roleChaining ) { core.info( - 'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?' + 'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission? ' + + 'If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.' ); } return ( @@ -127,11 +128,15 @@ export async function run() { // the source credentials to already be masked as secrets // in any error messages. exportCredentials({ AccessKeyId, SecretAccessKey, SessionToken }); - } else if (!webIdentityTokenFile && !roleChaining) { + } else if ( + !webIdentityTokenFile && + !roleChaining && + !(process.env['AWS_ACCESS_KEY_ID'] && process.env['AWS_SECRET_ACCESS_KEY']) + ) { throw new Error('Could not determine how to assume credentials. Please check your inputs and try again.'); } - if (AccessKeyId || roleChaining) { + if (AccessKeyId || roleChaining || (process.env['AWS_ACCESS_KEY_ID'] && process.env['AWS_SECRET_ACCESS_KEY'])) { // Validate that the SDK can actually pick up credentials. // This validates cases where this action is using existing environment credentials, // and cases where the user intended to provide input credentials but the secrets inputs resolved to empty strings. diff --git a/test/index.test.ts b/test/index.test.ts index 50a88dd69..a2951d7d5 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -519,13 +519,33 @@ describe('Configure AWS Credentials', () => { await run(); expect(core.info).toHaveBeenCalledWith( - 'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?' + 'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?' + + ' If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.' ); expect(core.setFailed).toHaveBeenCalledWith( 'Could not determine how to assume credentials. Please check your inputs and try again.' ); }); + test('Assume role with existing credentials if nothing else set', async () => { + process.env['AWS_ACCESS_KEY_ID'] = FAKE_ACCESS_KEY_ID; + process.env['AWS_SECRET_ACCESS_KEY'] = FAKE_SECRET_ACCESS_KEY; + jest.spyOn(core, 'getInput').mockImplementation( + mockGetInput({ + 'role-to-assume': ROLE_ARN, + 'aws-region': FAKE_REGION, + }) + ); + + await run(); + + expect(core.info).toHaveBeenCalledWith( + 'It looks like you might be trying to authenticate with OIDC. Did you mean to set the `id-token` permission?' + + ' If you are not trying to authenticate with OIDC and the action is working successfully, you can ignore this message.' + ); + expect(mockedSTS.commandCalls(AssumeRoleCommand).length).toEqual(1); + }); + test('role assumption fails after maximum trials using OIDC provider', async () => { process.env['GITHUB_ACTIONS'] = 'true'; process.env['ACTIONS_ID_TOKEN_REQUEST_TOKEN'] = 'test-token'; From 3a12f318be21ee4f49a0ba3e5ff403de32902c78 Mon Sep 17 00:00:00 2001 From: Tom Keller <1083460+kellertk@users.noreply.github.com> Date: Thu, 24 Aug 2023 14:45:24 -0700 Subject: [PATCH 5/7] CHANGELOG.md for 3.0.1 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc1dc0939..140a7a5ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.0.1](https://github.com/aws-actions/configure-aws-credentials/compare/v3.0.0...v3.0.1) (2023-08024) + +### Features +* Can configure `special-characters-workaround` to keep retrying credentials if the returned + credentials have special characters (Fixes #599) + +### Bug Fixes +* Fixes #792: V3 breaks by somehow assuming the use of OIDC +* Minor typo fix from @ubaid-ansari21 + +### Changes to existing functionality +* Special characters are now allowed in returned credential variables unless you configure the + `special-characters-workaround` option + ## [3.0.0](https://github.com/aws-actions/configure-aws-credentials/compare/v2.2.0...v3.0.0) (2023-08-21) ### Features From 346430985610c4a909f61343db2f72814a6682cc Mon Sep 17 00:00:00 2001 From: Tom Keller <1083460+kellertk@users.noreply.github.com> Date: Thu, 24 Aug 2023 14:48:11 -0700 Subject: [PATCH 6/7] chore: update CHANGELOG.md for v3.0.1 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 140a7a5ae..ad9baf715 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -## [3.0.1](https://github.com/aws-actions/configure-aws-credentials/compare/v3.0.0...v3.0.1) (2023-08024) +## [3.0.1](https://github.com/aws-actions/configure-aws-credentials/compare/v3.0.0...v3.0.1) (2023-08-24) ### Features * Can configure `special-characters-workaround` to keep retrying credentials if the returned From a2b0094a4d101ce7f5ca3eb26879bea365ac071b Mon Sep 17 00:00:00 2001 From: peterwoodworth Date: Thu, 24 Aug 2023 14:49:22 -0700 Subject: [PATCH 7/7] change bugfix description --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ad9baf715..9e6eff3d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ All notable changes to this project will be documented in this file. See [standa credentials have special characters (Fixes #599) ### Bug Fixes -* Fixes #792: V3 breaks by somehow assuming the use of OIDC +* Fixes #792: Action fails when intending to use existing credentials * Minor typo fix from @ubaid-ansari21 ### Changes to existing functionality