diff --git a/README.md b/README.md index 0031689..a32aa2b 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,8 @@ See [action.yml](./action.yml) for more detail. | transitive-tag-keys | Define a list of transitive tag keys to pass when assuming a role. | No | | inline-session-policy | You may further restrict the assumed role policy by defining an inline policy here. | No | | managed-session-policies | You may further restrict the assumed role policy by specifying a managed policy here. | No | -| output-credentials | When set, outputs fetched credentials as action step output. (Outputs aws-access-key-id, aws-secret-access-key, aws-session-token, and aws-account-id). Defaults to false. | No | +| output-credentials | When set, outputs fetched credentials as action step output. (Outputs access-key-id, secret-access-key, session-token, and expiration). Defaults to false. | No | +| output-env-credentials | When set, exports fetched credentials as environment variables (AWS_REGION, AWS_DEFAULT_REGION, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN). Defaults to true. Set to false if you need to avoid setting/changing env variables. (You'd probably want to use output-credentials if you disable this). | No | | unset-current-credentials | When set, attempts to unset any existing credentials in your action runner. | No | | disable-retry | Disabled retry/backoff logic for assume role calls. By default, retries are enabled. | No | | retry-max-attempts | Limits the number of retry attempts before giving up. Defaults to 12. | No | diff --git a/action.yml b/action.yml index d792ae3..15cfbc8 100644 --- a/action.yml +++ b/action.yml @@ -64,6 +64,10 @@ inputs: output-credentials: description: Whether to set credentials as step output required: false + output-env-credentials: + description: Whether to export credentials as environment variables. If you set this to false, you probably want to use output-credentials. + required: false + default: true unset-current-credentials: description: Whether to unset the existing credentials in your runner. May be useful if you run this action multiple times in the same job required: false @@ -87,3 +91,5 @@ outputs: description: The AWS secret access key for the provided credentials aws-session-token: description: The AWS session token for the provided credentials + aws-expiration: + description: The expiration time for the provided credentials diff --git a/src/cleanup/index.ts b/src/cleanup/index.ts index 60db8e1..5cf2fe7 100644 --- a/src/cleanup/index.ts +++ b/src/cleanup/index.ts @@ -13,18 +13,21 @@ import { errorMessage } from '../helpers'; */ export function cleanup() { - try { - // The GitHub Actions toolkit does not have an option to completely unset - // environment variables, so we overwrite the current value with an empty - // string. The AWS CLI and AWS SDKs will behave correctly: they treat an - // empty string value as if the environment variable does not exist. - core.exportVariable('AWS_ACCESS_KEY_ID', ''); - core.exportVariable('AWS_SECRET_ACCESS_KEY', ''); - core.exportVariable('AWS_SESSION_TOKEN', ''); - core.exportVariable('AWS_DEFAULT_REGION', ''); - core.exportVariable('AWS_REGION', ''); - } catch (error) { - core.setFailed(errorMessage(error)); + const outputEnvCredentialsInput = core.getInput('output-env-credentials', { required: false }) || 'true'; + if (outputEnvCredentialsInput === 'true') { + try { + // The GitHub Actions toolkit does not have an option to completely unset + // environment variables, so we overwrite the current value with an empty + // string. The AWS CLI and AWS SDKs will behave correctly: they treat an + // empty string value as if the environment variable does not exist. + core.exportVariable('AWS_ACCESS_KEY_ID', ''); + core.exportVariable('AWS_SECRET_ACCESS_KEY', ''); + core.exportVariable('AWS_SESSION_TOKEN', ''); + core.exportVariable('AWS_DEFAULT_REGION', ''); + core.exportVariable('AWS_REGION', ''); + } catch (error) { + core.setFailed(errorMessage(error)); + } } } /* c8 ignore start */ diff --git a/src/helpers.ts b/src/helpers.ts index e15de92..81656d9 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -39,23 +39,25 @@ export function translateEnvVariables() { // Configure the AWS CLI and AWS SDKs using environment variables and set them as secrets. // Setting the credentials as secrets masks them in Github Actions logs -export function exportCredentials(creds?: Partial, outputCredentials?: boolean) { - if (creds?.AccessKeyId) { - core.setSecret(creds.AccessKeyId); - core.exportVariable('AWS_ACCESS_KEY_ID', creds.AccessKeyId); - } +export function exportCredentials(creds?: Partial, outputCredentials?: boolean, outputEnvCredentials?: boolean) { + if (outputEnvCredentials) { + if (creds?.AccessKeyId) { + core.setSecret(creds.AccessKeyId); + core.exportVariable('AWS_ACCESS_KEY_ID', creds.AccessKeyId); + } - if (creds?.SecretAccessKey) { - core.setSecret(creds.SecretAccessKey); - core.exportVariable('AWS_SECRET_ACCESS_KEY', creds.SecretAccessKey); - } + if (creds?.SecretAccessKey) { + core.setSecret(creds.SecretAccessKey); + core.exportVariable('AWS_SECRET_ACCESS_KEY', creds.SecretAccessKey); + } - if (creds?.SessionToken) { - core.setSecret(creds.SessionToken); - core.exportVariable('AWS_SESSION_TOKEN', creds.SessionToken); - } else if (process.env.AWS_SESSION_TOKEN) { - // clear session token from previous credentials action - core.exportVariable('AWS_SESSION_TOKEN', ''); + if (creds?.SessionToken) { + core.setSecret(creds.SessionToken); + core.exportVariable('AWS_SESSION_TOKEN', creds.SessionToken); + } else if (process.env.AWS_SESSION_TOKEN) { + // clear session token from previous credentials action + core.exportVariable('AWS_SESSION_TOKEN', ''); + } } if (outputCredentials) { @@ -74,17 +76,21 @@ export function exportCredentials(creds?: Partial, outputCredential } } -export function unsetCredentials() { - core.exportVariable('AWS_ACCESS_KEY_ID', ''); - core.exportVariable('AWS_SECRET_ACCESS_KEY', ''); - core.exportVariable('AWS_SESSION_TOKEN', ''); - core.exportVariable('AWS_REGION', ''); - core.exportVariable('AWS_DEFAULT_REGION', ''); +export function unsetCredentials(outputEnvCredentials?: boolean) { + if (outputEnvCredentials) { + core.exportVariable('AWS_ACCESS_KEY_ID', ''); + core.exportVariable('AWS_SECRET_ACCESS_KEY', ''); + core.exportVariable('AWS_SESSION_TOKEN', ''); + core.exportVariable('AWS_REGION', ''); + core.exportVariable('AWS_DEFAULT_REGION', ''); + } } -export function exportRegion(region: string) { - core.exportVariable('AWS_DEFAULT_REGION', region); - core.exportVariable('AWS_REGION', region); +export function exportRegion(region: string, outputEnvCredentials?: boolean) { + if (outputEnvCredentials) { + core.exportVariable('AWS_DEFAULT_REGION', region); + core.exportVariable('AWS_REGION', region); + } } // Obtains account ID from STS Client and sets it as output diff --git a/src/index.ts b/src/index.ts index 33f29e1..921fd70 100644 --- a/src/index.ts +++ b/src/index.ts @@ -57,6 +57,8 @@ export async function run() { const roleChaining = roleChainingInput.toLowerCase() === 'true'; const outputCredentialsInput = core.getInput('output-credentials', { required: false }) || 'false'; const outputCredentials = outputCredentialsInput.toLowerCase() === 'true'; + const outputEnvCredentialsInput = core.getInput('output-env-credentials', { required: false }) || 'true'; + const outputEnvCredentials = outputEnvCredentialsInput.toLowerCase() === 'true'; const unsetCurrentCredentialsInput = core.getInput('unset-current-credentials', { required: false }) || 'false'; const unsetCurrentCredentials = unsetCurrentCredentialsInput.toLowerCase() === 'true'; const disableRetryInput = core.getInput('disable-retry', { required: false }) || 'false'; @@ -109,13 +111,13 @@ export async function run() { }; if (unsetCurrentCredentials) { - unsetCredentials(); + unsetCredentials(outputEnvCredentials); } if (!region.match(REGION_REGEX)) { throw new Error(`Region is not valid: ${region}`); } - exportRegion(region); + exportRegion(region, outputEnvCredentials); // Instantiate credentials client const credentialsClient = new CredentialsClient({ region, proxyServer }); @@ -154,7 +156,7 @@ export async function run() { // Plus, in the assume role case, if the AssumeRole call fails, we want // the source credentials to already be masked as secrets // in any error messages. - exportCredentials({ AccessKeyId, SecretAccessKey, SessionToken }); + exportCredentials({ AccessKeyId, SecretAccessKey, SessionToken }, outputCredentials, outputEnvCredentials); } else if (!webIdentityTokenFile && !roleChaining) { // Proceed only if credentials can be picked up await credentialsClient.validateCredentials(); @@ -195,7 +197,7 @@ export async function run() { ); } while (specialCharacterWorkaround && !verifyKeys(roleCredentials.Credentials)); core.info(`Authenticated as assumedRoleId ${roleCredentials.AssumedRoleUser?.AssumedRoleId}`); - exportCredentials(roleCredentials.Credentials, outputCredentials); + exportCredentials(roleCredentials.Credentials, outputCredentials, outputEnvCredentials); // We need to validate the credentials in 2 of our use-cases // First: self-hosted runners. If the GITHUB_ACTIONS environment variable // is set to `true` then we are NOT in a self-hosted runner.