mirror of
https://github.com/aws-actions/configure-aws-credentials.git
synced 2026-03-12 18:07:10 -04:00
fix webIdentityTokenFile option, rearrange validation logic
This commit is contained in:
2
dist/cleanup/src/helpers.d.ts
generated
vendored
2
dist/cleanup/src/helpers.d.ts
generated
vendored
@@ -2,7 +2,7 @@ import type { Credentials } from '@aws-sdk/client-sts';
|
|||||||
import type { CredentialsClient } from './CredentialsClient';
|
import type { CredentialsClient } from './CredentialsClient';
|
||||||
export declare function exportCredentials(creds?: Partial<Credentials>): void;
|
export declare function exportCredentials(creds?: Partial<Credentials>): void;
|
||||||
export declare function exportRegion(region: string): void;
|
export declare function exportRegion(region: string): void;
|
||||||
export declare function exportAccountId(credentialsClient: CredentialsClient, maskAccountId?: string): Promise<string>;
|
export declare function exportAccountId(credentialsClient: CredentialsClient, maskAccountId?: boolean): Promise<string>;
|
||||||
export declare function sanitizeGitHubVariables(name: string): string;
|
export declare function sanitizeGitHubVariables(name: string): string;
|
||||||
export declare function defaultSleep(ms: number): Promise<unknown>;
|
export declare function defaultSleep(ms: number): Promise<unknown>;
|
||||||
declare let sleep: typeof defaultSleep;
|
declare let sleep: typeof defaultSleep;
|
||||||
|
|||||||
58
dist/index.js
generated
vendored
58
dist/index.js
generated
vendored
@@ -149,7 +149,7 @@ async function assumeRoleWithCredentials(params, client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function assumeRole(params) {
|
async function assumeRole(params) {
|
||||||
const { credentialsClient, sourceAccountId, roleToAssume, roleExternalId, roleDuration, roleSessionName, roleSkipSessionTagging, webIdentityTokenFile, webIdentityToken, inlineSessionPolicy, managedSessionPolicies } = { ...params };
|
const { credentialsClient, sourceAccountId, roleToAssume, roleExternalId, roleDuration, roleSessionName, roleSkipSessionTagging, webIdentityTokenFile, webIdentityToken, inlineSessionPolicy, managedSessionPolicies, } = { ...params };
|
||||||
// Load GitHub environment variables
|
// Load GitHub environment variables
|
||||||
const { GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA, GITHUB_WORKSPACE } = process.env;
|
const { GITHUB_REPOSITORY, GITHUB_WORKFLOW, GITHUB_ACTION, GITHUB_ACTOR, GITHUB_SHA, GITHUB_WORKSPACE } = process.env;
|
||||||
if (!GITHUB_REPOSITORY || !GITHUB_WORKFLOW || !GITHUB_ACTION || !GITHUB_ACTOR || !GITHUB_SHA || !GITHUB_WORKSPACE) {
|
if (!GITHUB_REPOSITORY || !GITHUB_WORKFLOW || !GITHUB_ACTION || !GITHUB_ACTOR || !GITHUB_SHA || !GITHUB_WORKSPACE) {
|
||||||
@@ -188,7 +188,7 @@ async function assumeRole(params) {
|
|||||||
Tags: tags ? tags : undefined,
|
Tags: tags ? tags : undefined,
|
||||||
ExternalId: roleExternalId ? roleExternalId : undefined,
|
ExternalId: roleExternalId ? roleExternalId : undefined,
|
||||||
Policy: inlineSessionPolicy ? inlineSessionPolicy : undefined,
|
Policy: inlineSessionPolicy ? inlineSessionPolicy : undefined,
|
||||||
PolicyArns: managedSessionPolicies ? managedSessionPolicies : undefined,
|
PolicyArns: managedSessionPolicies?.length ? managedSessionPolicies : undefined,
|
||||||
};
|
};
|
||||||
const keys = Object.keys(commonAssumeRoleParams);
|
const keys = Object.keys(commonAssumeRoleParams);
|
||||||
keys.forEach((k) => commonAssumeRoleParams[k] === undefined && delete commonAssumeRoleParams[k]);
|
keys.forEach((k) => commonAssumeRoleParams[k] === undefined && delete commonAssumeRoleParams[k]);
|
||||||
@@ -389,7 +389,7 @@ async function run() {
|
|||||||
const region = core.getInput('aws-region', { required: true });
|
const region = core.getInput('aws-region', { required: true });
|
||||||
const roleToAssume = core.getInput('role-to-assume', { required: false });
|
const roleToAssume = core.getInput('role-to-assume', { required: false });
|
||||||
const audience = core.getInput('audience', { required: false });
|
const audience = core.getInput('audience', { required: false });
|
||||||
const maskAccountId = core.getInput('mask-aws-account-id', { required: false });
|
const maskAccountId = core.getBooleanInput('mask-aws-account-id', { required: false });
|
||||||
const roleExternalId = core.getInput('role-external-id', { required: false });
|
const roleExternalId = core.getInput('role-external-id', { required: false });
|
||||||
const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false });
|
const webIdentityTokenFile = core.getInput('web-identity-token-file', { required: false });
|
||||||
const roleDuration = parseInt(core.getInput('role-duration-seconds', { required: false })) || DEFAULT_ROLE_DURATION;
|
const roleDuration = parseInt(core.getInput('role-duration-seconds', { required: false })) || DEFAULT_ROLE_DURATION;
|
||||||
@@ -401,11 +401,11 @@ async function run() {
|
|||||||
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
|
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
|
||||||
const managedSessionPoliciesInput = core.getMultilineInput('managed-session-policies', { required: false });
|
const managedSessionPoliciesInput = core.getMultilineInput('managed-session-policies', { required: false });
|
||||||
const managedSessionPolicies = [];
|
const managedSessionPolicies = [];
|
||||||
|
const roleChainingInput = core.getInput('role-chaining', { required: false }) || 'false';
|
||||||
|
const roleChaining = roleChainingInput.toLowerCase() === 'true';
|
||||||
for (const managedSessionPolicy of managedSessionPoliciesInput) {
|
for (const managedSessionPolicy of managedSessionPoliciesInput) {
|
||||||
managedSessionPolicies.push({ arn: managedSessionPolicy });
|
managedSessionPolicies.push({ arn: managedSessionPolicy });
|
||||||
}
|
}
|
||||||
const roleChainingInput = core.getInput('role-chaining', { required: false }) || 'false';
|
|
||||||
const roleChaining = roleChainingInput.toLowerCase() === 'true';
|
|
||||||
// Logic to decide whether to attempt to use OIDC or not
|
// Logic to decide whether to attempt to use OIDC or not
|
||||||
const useGitHubOIDCProvider = () => {
|
const useGitHubOIDCProvider = () => {
|
||||||
// The `ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variable is set when the `id-token` permission is granted.
|
// The `ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variable is set when the `id-token` permission is granted.
|
||||||
@@ -427,40 +427,36 @@ async function run() {
|
|||||||
!disableOIDC &&
|
!disableOIDC &&
|
||||||
!roleChaining);
|
!roleChaining);
|
||||||
};
|
};
|
||||||
// Validate and export region
|
if (!region.match(REGION_REGEX)) {
|
||||||
if (region) {
|
throw new Error(`Region is not valid: ${region}`);
|
||||||
if (!region.match(REGION_REGEX)) {
|
|
||||||
throw new Error(`Region is not valid: ${region}`);
|
|
||||||
}
|
|
||||||
(0, helpers_1.exportRegion)(region);
|
|
||||||
}
|
}
|
||||||
|
(0, helpers_1.exportRegion)(region);
|
||||||
// Instantiate credentials client
|
// Instantiate credentials client
|
||||||
const credentialsClient = new CredentialsClient_1.CredentialsClient({ region, proxyServer });
|
const credentialsClient = new CredentialsClient_1.CredentialsClient({ region, proxyServer });
|
||||||
// Always export the source credentials and account ID.
|
let sourceAccountId;
|
||||||
// The STS client for calling AssumeRole pulls creds from the environment.
|
let webIdentityToken;
|
||||||
// Plus, in the assume role case, if the AssumeRole call fails, we want
|
// If OIDC is being used, generate token
|
||||||
// the source credentials and account ID to already be masked as secrets
|
// Else, validate that the SDK can pick up credentials
|
||||||
// in any error messages.
|
if (useGitHubOIDCProvider()) {
|
||||||
if (AccessKeyId) {
|
webIdentityToken = await core.getIDToken(audience);
|
||||||
|
}
|
||||||
|
else if (AccessKeyId) {
|
||||||
if (!SecretAccessKey) {
|
if (!SecretAccessKey) {
|
||||||
throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
|
throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
|
||||||
}
|
}
|
||||||
|
// The STS client for calling AssumeRole pulls creds from the environment.
|
||||||
|
// Plus, in the assume role case, if the AssumeRole call fails, we want
|
||||||
|
// the source credentials and account ID to already be masked as secrets
|
||||||
|
// in any error messages.
|
||||||
(0, helpers_1.exportCredentials)({ AccessKeyId, SecretAccessKey, SessionToken });
|
(0, helpers_1.exportCredentials)({ AccessKeyId, SecretAccessKey, SessionToken });
|
||||||
}
|
}
|
||||||
// If OIDC is being used, generate token
|
else if (!webIdentityTokenFile && !roleChaining) {
|
||||||
// Else, validate that the SDK can pick up credentials
|
throw new Error('Could not determine how to assume credentials. Please check your inputs and try again.');
|
||||||
let sourceAccountId;
|
|
||||||
let webIdentityToken;
|
|
||||||
if (useGitHubOIDCProvider()) {
|
|
||||||
webIdentityToken = await core.getIDToken(audience);
|
|
||||||
// Implement #359
|
|
||||||
}
|
}
|
||||||
else {
|
if (AccessKeyId || roleChaining) {
|
||||||
// Regardless of whether any source credentials were provided as inputs,
|
// Validate that the SDK can actually pick up credentials.
|
||||||
// validate that the SDK can actually pick up credentials. This validates
|
// This validates cases where this action is using existing environment credentials,
|
||||||
// cases where this action is on a self-hosted runner that doesn't have credentials
|
// and cases where the user intended to provide input credentials but the secrets inputs resolved to empty strings.
|
||||||
// configured correctly, and cases where the user intended to provide input
|
|
||||||
// credentials but the secrets inputs resolved to empty strings.
|
|
||||||
await credentialsClient.validateCredentials(AccessKeyId, roleChaining);
|
await credentialsClient.validateCredentials(AccessKeyId, roleChaining);
|
||||||
sourceAccountId = await (0, helpers_1.exportAccountId)(credentialsClient, maskAccountId);
|
sourceAccountId = await (0, helpers_1.exportAccountId)(credentialsClient, maskAccountId);
|
||||||
}
|
}
|
||||||
@@ -491,10 +487,8 @@ async function run() {
|
|||||||
await credentialsClient.validateCredentials(roleCredentials.Credentials?.AccessKeyId);
|
await credentialsClient.validateCredentials(roleCredentials.Credentials?.AccessKeyId);
|
||||||
}
|
}
|
||||||
await (0, helpers_1.exportAccountId)(credentialsClient, maskAccountId);
|
await (0, helpers_1.exportAccountId)(credentialsClient, maskAccountId);
|
||||||
// implement #432
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// implement #370
|
|
||||||
core.info('Proceeding with IAM user credentials');
|
core.info('Proceeding with IAM user credentials');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
56
src/index.ts
56
src/index.ts
@@ -29,11 +29,11 @@ export async function run() {
|
|||||||
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
|
const inlineSessionPolicy = core.getInput('inline-session-policy', { required: false });
|
||||||
const managedSessionPoliciesInput = core.getMultilineInput('managed-session-policies', { required: false });
|
const managedSessionPoliciesInput = core.getMultilineInput('managed-session-policies', { required: false });
|
||||||
const managedSessionPolicies: any[] = [];
|
const managedSessionPolicies: any[] = [];
|
||||||
|
const roleChainingInput = core.getInput('role-chaining', { required: false }) || 'false';
|
||||||
|
const roleChaining = roleChainingInput.toLowerCase() === 'true';
|
||||||
for (const managedSessionPolicy of managedSessionPoliciesInput) {
|
for (const managedSessionPolicy of managedSessionPoliciesInput) {
|
||||||
managedSessionPolicies.push({ arn: managedSessionPolicy });
|
managedSessionPolicies.push({ arn: managedSessionPolicy });
|
||||||
}
|
}
|
||||||
const roleChainingInput = core.getInput('role-chaining', { required: false }) || 'false';
|
|
||||||
const roleChaining = roleChainingInput.toLowerCase() === 'true';
|
|
||||||
|
|
||||||
// Logic to decide whether to attempt to use OIDC or not
|
// Logic to decide whether to attempt to use OIDC or not
|
||||||
const useGitHubOIDCProvider = () => {
|
const useGitHubOIDCProvider = () => {
|
||||||
@@ -63,44 +63,38 @@ export async function run() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate and export region
|
if (!region.match(REGION_REGEX)) {
|
||||||
if (region) {
|
throw new Error(`Region is not valid: ${region}`);
|
||||||
if (!region.match(REGION_REGEX)) {
|
|
||||||
throw new Error(`Region is not valid: ${region}`);
|
|
||||||
}
|
|
||||||
exportRegion(region);
|
|
||||||
}
|
}
|
||||||
|
exportRegion(region);
|
||||||
|
|
||||||
// Instantiate credentials client
|
// Instantiate credentials client
|
||||||
const credentialsClient = new CredentialsClient({ region, proxyServer });
|
const credentialsClient = new CredentialsClient({ region, proxyServer });
|
||||||
|
let sourceAccountId: string;
|
||||||
// Always export the source credentials and account ID.
|
let webIdentityToken: string;
|
||||||
// The STS client for calling AssumeRole pulls creds from the environment.
|
|
||||||
// Plus, in the assume role case, if the AssumeRole call fails, we want
|
|
||||||
// the source credentials and account ID to already be masked as secrets
|
|
||||||
// in any error messages.
|
|
||||||
if (AccessKeyId) {
|
|
||||||
if (!SecretAccessKey) {
|
|
||||||
throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
|
|
||||||
}
|
|
||||||
exportCredentials({ AccessKeyId, SecretAccessKey, SessionToken });
|
|
||||||
}
|
|
||||||
|
|
||||||
// If OIDC is being used, generate token
|
// If OIDC is being used, generate token
|
||||||
// Else, validate that the SDK can pick up credentials
|
// Else, validate that the SDK can pick up credentials
|
||||||
let sourceAccountId: string;
|
|
||||||
let webIdentityToken: string;
|
|
||||||
if (useGitHubOIDCProvider()) {
|
if (useGitHubOIDCProvider()) {
|
||||||
webIdentityToken = await core.getIDToken(audience);
|
webIdentityToken = await core.getIDToken(audience);
|
||||||
// Implement #359
|
} else if (AccessKeyId) {
|
||||||
} else {
|
if (!SecretAccessKey) {
|
||||||
// Regardless of whether any source credentials were provided as inputs,
|
throw new Error("'aws-secret-access-key' must be provided if 'aws-access-key-id' is provided");
|
||||||
// validate that the SDK can actually pick up credentials. This validates
|
}
|
||||||
// cases where this action is on a self-hosted runner that doesn't have credentials
|
// The STS client for calling AssumeRole pulls creds from the environment.
|
||||||
// configured correctly, and cases where the user intended to provide input
|
// Plus, in the assume role case, if the AssumeRole call fails, we want
|
||||||
// credentials but the secrets inputs resolved to empty strings.
|
// the source credentials and account ID to already be masked as secrets
|
||||||
await credentialsClient.validateCredentials(AccessKeyId, roleChaining);
|
// in any error messages.
|
||||||
|
exportCredentials({ AccessKeyId, SecretAccessKey, SessionToken });
|
||||||
|
} else if (!webIdentityTokenFile && !roleChaining) {
|
||||||
|
throw new Error('Could not determine how to assume credentials. Please check your inputs and try again.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AccessKeyId || roleChaining) {
|
||||||
|
// 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.
|
||||||
|
await credentialsClient.validateCredentials(AccessKeyId, roleChaining);
|
||||||
sourceAccountId = await exportAccountId(credentialsClient, maskAccountId);
|
sourceAccountId = await exportAccountId(credentialsClient, maskAccountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,9 +125,7 @@ export async function run() {
|
|||||||
await credentialsClient.validateCredentials(roleCredentials.Credentials?.AccessKeyId);
|
await credentialsClient.validateCredentials(roleCredentials.Credentials?.AccessKeyId);
|
||||||
}
|
}
|
||||||
await exportAccountId(credentialsClient, maskAccountId);
|
await exportAccountId(credentialsClient, maskAccountId);
|
||||||
// implement #432
|
|
||||||
} else {
|
} else {
|
||||||
// implement #370
|
|
||||||
core.info('Proceeding with IAM user credentials');
|
core.info('Proceeding with IAM user credentials');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -171,19 +171,6 @@ describe('Configure AWS Credentials', () => {
|
|||||||
expect(core.setFailed).toHaveBeenCalledTimes(0);
|
expect(core.setFailed).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('hosted runners can pull creds from a self-hosted environment', async () => {
|
|
||||||
const mockInputs = { 'aws-region': FAKE_REGION };
|
|
||||||
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
|
|
||||||
|
|
||||||
await run();
|
|
||||||
|
|
||||||
expect(mockedSTS.commandCalls(AssumeRoleCommand)).toHaveLength(0);
|
|
||||||
expect(core.exportVariable).toHaveBeenCalledTimes(2);
|
|
||||||
expect(core.exportVariable).toHaveBeenCalledWith('AWS_DEFAULT_REGION', FAKE_REGION);
|
|
||||||
expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', FAKE_REGION);
|
|
||||||
expect(core.setOutput).toHaveBeenCalledWith('aws-account-id', FAKE_ACCOUNT_ID);
|
|
||||||
});
|
|
||||||
|
|
||||||
test('action with no accessible credentials fails', async () => {
|
test('action with no accessible credentials fails', async () => {
|
||||||
const mockInputs = { 'aws-region': FAKE_REGION };
|
const mockInputs = { 'aws-region': FAKE_REGION };
|
||||||
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
|
jest.spyOn(core, 'getInput').mockImplementation(mockGetInput(mockInputs));
|
||||||
@@ -195,7 +182,7 @@ describe('Configure AWS Credentials', () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
'Credentials could not be loaded, please check your action inputs: Could not load credentials from any providers'
|
'Could not determine how to assume credentials. Please check your inputs and try again.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -210,7 +197,7 @@ describe('Configure AWS Credentials', () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(core.setFailed).toHaveBeenCalledWith(
|
expect(core.setFailed).toHaveBeenCalledWith(
|
||||||
'Credentials could not be loaded, please check your action inputs: Access key ID empty after loading credentials'
|
'Could not determine how to assume credentials. Please check your inputs and try again.'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user