Skip to content

Commit

Permalink
fix(credential-provider-ini): pass role_arn to credential_source sour…
Browse files Browse the repository at this point in the history
…ce_profile
  • Loading branch information
kuhe committed May 30, 2024
1 parent ec2fc9a commit dced10c
Show file tree
Hide file tree
Showing 21 changed files with 98 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export type CognitoIdentityCredentialProvider = Provider<CognitoIdentityCredenti
*/
export function fromCognitoIdentity(parameters: FromCognitoIdentityParameters): CognitoIdentityCredentialProvider {
return async (): Promise<CognitoIdentityCredentials> => {
parameters.logger?.debug("@aws-sdk/credential-provider-cognito-identity", "fromCognitoIdentity");
parameters.logger?.debug("@aws-sdk/credential-provider-cognito-identity - fromCognitoIdentity");
const { GetCredentialsForIdentityCommand, CognitoIdentityClient } = await import("./loadCognitoIdentity");

const {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function fromCognitoIdentityPool({
logger,
parentClientConfig,
}: FromCognitoIdentityPoolParameters): CognitoIdentityCredentialProvider {
logger?.debug("@aws-sdk/credential-provider-cognito-identity", "fromCognitoIdentity");
logger?.debug("@aws-sdk/credential-provider-cognito-identity - fromCognitoIdentity");
const cacheKey: string | undefined = userIdentifier
? `aws:cognito-identity-credentials:${identityPoolId}:${userIdentifier}`
: undefined;
Expand Down
2 changes: 1 addition & 1 deletion packages/credential-provider-env/src/fromEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export const ENV_CREDENTIAL_SCOPE = "AWS_CREDENTIAL_SCOPE";
export const fromEnv =
(init?: FromEnvInit): AwsCredentialIdentityProvider =>
async () => {
init?.logger?.debug("@aws-sdk/credential-provider-env", "fromEnv");
init?.logger?.debug("@aws-sdk/credential-provider-env - fromEnv");
const accessKeyId: string | undefined = process.env[ENV_KEY];
const secretAccessKey: string | undefined = process.env[ENV_SECRET];
const sessionToken: string | undefined = process.env[ENV_SESSION];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { retryWrapper } from "./retry-wrapper";
* Creates a provider that gets credentials via HTTP request.
*/
export const fromHttp = (options: FromHttpOptions = {}): AwsCredentialIdentityProvider => {
options.logger?.debug("@aws-sdk/credential-provider-http", "fromHttp");
options.logger?.debug("@aws-sdk/credential-provider-http - fromHttp");
let host: string;

const full = options.credentialsFullUri;
Expand Down
2 changes: 1 addition & 1 deletion packages/credential-provider-http/src/fromHttp/fromHttp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const AWS_CONTAINER_AUTHORIZATION_TOKEN = "AWS_CONTAINER_AUTHORIZATION_TOKEN";
* Creates a provider that gets credentials via HTTP request.
*/
export const fromHttp = (options: FromHttpOptions = {}): AwsCredentialIdentityProvider => {
options.logger?.debug("@aws-sdk/credential-provider-http", "fromHttp");
options.logger?.debug("@aws-sdk/credential-provider-http - fromHttp");
let host: string;

const relative = options.awsContainerCredentialsRelativeUri ?? process.env[AWS_CONTAINER_CREDENTIALS_RELATIVE_URI];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ export async function getCredentials(response: HttpResponse, logger?: Logger): P
throw new CredentialsProviderError(
"HTTP credential provider response not of the required format, an object matching: " +
"{ AccessKeyId: string, SecretAccessKey: string, Token: string, Expiration: string(rfc3339) }",
void 0,
logger
{ logger }
);
}

Expand Down
2 changes: 1 addition & 1 deletion packages/credential-provider-ini/src/fromIni.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export interface FromIniInit extends SourceProfileInit, CredentialProviderOption
export const fromIni =
(init: FromIniInit = {}): AwsCredentialIdentityProvider =>
async () => {
init.logger?.debug("@aws-sdk/credential-provider-ini", "fromIni");
init.logger?.debug("@aws-sdk/credential-provider-ini - fromIni");
const profiles = await parseKnownFiles(init);
return resolveProfileData(getProfileName(init), profiles, init);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CredentialsProviderError } from "@smithy/property-provider";
import { getProfileName } from "@smithy/shared-ini-file-loader";
import { AwsCredentialIdentity, ParsedIniData, Profile } from "@smithy/types";
import { AwsCredentialIdentity, Logger, ParsedIniData, Profile } from "@smithy/types";

import { FromIniInit } from "./fromIni";
import { resolveCredentialSource } from "./resolveCredentialSource";
Expand Down Expand Up @@ -59,20 +59,42 @@ interface AssumeRoleWithProviderProfile extends Profile {
/**
* @internal
*/
export const isAssumeRoleProfile = (arg: any) =>
Boolean(arg) &&
typeof arg === "object" &&
typeof arg.role_arn === "string" &&
["undefined", "string"].indexOf(typeof arg.role_session_name) > -1 &&
["undefined", "string"].indexOf(typeof arg.external_id) > -1 &&
["undefined", "string"].indexOf(typeof arg.mfa_serial) > -1 &&
(isAssumeRoleWithSourceProfile(arg) || isAssumeRoleWithProviderProfile(arg));
export const isAssumeRoleProfile = (
arg: any,
{ profile = "default", logger }: { profile: string; logger?: Logger }
) => {
return (
Boolean(arg) &&
typeof arg === "object" &&
typeof arg.role_arn === "string" &&
["undefined", "string"].indexOf(typeof arg.role_session_name) > -1 &&
["undefined", "string"].indexOf(typeof arg.external_id) > -1 &&
["undefined", "string"].indexOf(typeof arg.mfa_serial) > -1 &&
(isAssumeRoleWithSourceProfile(arg, { profile, logger }) || isCredentialSourceProfile(arg, { profile, logger }))
);
};

const isAssumeRoleWithSourceProfile = (arg: any): arg is AssumeRoleWithSourceProfile =>
typeof arg.source_profile === "string" && typeof arg.credential_source === "undefined";
const isAssumeRoleWithSourceProfile = (
arg: any,
{ profile, logger }: { profile: string; logger?: Logger }
): arg is AssumeRoleWithSourceProfile => {
const withSourceProfile = typeof arg.source_profile === "string" && typeof arg.credential_source === "undefined";
if (withSourceProfile) {
logger?.debug?.(` ${profile} isAssumeRoleWithSourceProfile source_profile=${arg.source_profile}`);
}
return withSourceProfile;
};

const isAssumeRoleWithProviderProfile = (arg: any): arg is AssumeRoleWithProviderProfile =>
typeof arg.credential_source === "string" && typeof arg.source_profile === "undefined";
const isCredentialSourceProfile = (
arg: any,
{ profile, logger }: { profile: string; logger?: Logger }
): arg is AssumeRoleWithProviderProfile => {
const withProviderProfile = typeof arg.credential_source === "string" && typeof arg.source_profile === "undefined";
if (withProviderProfile) {
logger?.debug?.(` ${profile} isCredentialSourceProfile credential_source=${arg.credential_source}`);
}
return withProviderProfile;
};

/**
* @internal
Expand All @@ -83,7 +105,7 @@ export const resolveAssumeRoleCredentials = async (
options: FromIniInit,
visitedProfiles: Record<string, true> = {}
) => {
options.logger?.debug("@aws-sdk/credential-provider-ini", "resolveAssumeRoleCredentials (STS)");
options.logger?.debug("@aws-sdk/credential-provider-ini - resolveAssumeRoleCredentials (STS)");
const data = profiles[profileName];

if (!options.roleAssumer) {
Expand All @@ -109,11 +131,31 @@ export const resolveAssumeRoleCredentials = async (
);
}

options.logger?.debug(
`@aws-sdk/credential-provider-ini - finding credential resolver using ${
source_profile ? `source_profile=[${source_profile}]` : `profile=[${profileName}]`
}`
);

const sourceCredsProvider: Promise<AwsCredentialIdentity> = source_profile
? resolveProfileData(source_profile, profiles, options, {
...visitedProfiles,
[source_profile]: true,
})
? resolveProfileData(
source_profile,
{
...profiles,
[source_profile]: {
...profiles[source_profile],
// This assigns the role_arn of the "root" profile
// to the credential_source profile so this recursive call knows
// what role to assume.
role_arn: data.role_arn ?? profiles[source_profile].role_arn,
},
},
options,
{
...visitedProfiles,
[source_profile]: true,
}
)
: (await resolveCredentialSource(data.credential_source!, profileName, options.logger)(options))();

const params: AssumeRoleParams = {
Expand Down
18 changes: 9 additions & 9 deletions packages/credential-provider-ini/src/resolveCredentialSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@ export const resolveCredentialSource = (
EcsContainer: async (options?: CredentialProviderOptions) => {
const { fromHttp } = await import("@aws-sdk/credential-provider-http");
const { fromContainerMetadata } = await import("@smithy/credential-provider-imds");
logger?.debug("@aws-sdk/credential-provider-ini", "credential_source EcsContainer");
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is EcsContainer");
return chain(fromHttp(options ?? {}), fromContainerMetadata(options));
},
Ec2InstanceMetadata: (options?: CredentialProviderOptions) => {
logger?.debug("@aws-sdk/credential-provider-ini", "credential_source Ec2InstanceMetadata");
return import("@smithy/credential-provider-imds").then(({ fromInstanceMetadata }) =>
fromInstanceMetadata(options)
);
Ec2InstanceMetadata: async (options?: CredentialProviderOptions) => {
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Ec2InstanceMetadata");
const { fromInstanceMetadata } = await import("@smithy/credential-provider-imds");
return fromInstanceMetadata(options);
},
Environment: (options?: CredentialProviderOptions) => {
logger?.debug("@aws-sdk/credential-provider-ini", "credential_source Environment");
return import("@aws-sdk/credential-provider-env").then(({ fromEnv }) => fromEnv(options));
Environment: async (options?: CredentialProviderOptions) => {
logger?.debug("@aws-sdk/credential-provider-ini - credential_source is Environment");
const { fromEnv } = await import("@aws-sdk/credential-provider-env");
return fromEnv(options);
},
};
if (credentialSource in sourceProvidersMap) {
Expand Down
4 changes: 2 additions & 2 deletions packages/credential-provider-ini/src/resolveProfileData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const resolveProfileData = async (

// If this is the first profile visited, role assumption keys should be
// given precedence over static credentials.
if (isAssumeRoleProfile(data)) {
if (isAssumeRoleProfile(data, { profile: profileName, logger: options.logger })) {
return resolveAssumeRoleCredentials(profileName, profiles, options, visitedProfiles);
}

Expand Down Expand Up @@ -60,7 +60,7 @@ export const resolveProfileData = async (
// (whether via a parameter, an environment variable, or another profile's
// `source_profile` key).
throw new CredentialsProviderError(
`Profile ${profileName} could not be found or parsed in shared credentials file.`,
`Could not resolve credentials using profile: [${profileName}] in configuration/credentials file(s).`,
{ logger: options.logger }
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const resolveStaticCredentials = (
profile: StaticCredsProfile,
options?: FromIniInit
): Promise<AwsCredentialIdentity> => {
options?.logger?.debug("@aws-sdk/credential-provider-ini", "resolveStaticCredentials");
options?.logger?.debug("@aws-sdk/credential-provider-ini - resolveStaticCredentials");
return Promise.resolve({
accessKeyId: profile.aws_access_key_id,
secretAccessKey: profile.aws_secret_access_key,
Expand Down
12 changes: 6 additions & 6 deletions packages/credential-provider-node/src/defaultProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@ export const defaultProvider = (init: DefaultProviderInit = {}): MemoizedProvide
? []
: [
async () => {
init.logger?.debug("@aws-sdk/credential-provider-node", "defaultProvider::fromEnv");
init.logger?.debug("@aws-sdk/credential-provider-node - defaultProvider::fromEnv");
return fromEnv(init)();
},
]),
async () => {
init.logger?.debug("@aws-sdk/credential-provider-node", "defaultProvider::fromSSO");
init.logger?.debug("@aws-sdk/credential-provider-node - defaultProvider::fromSSO");
const { ssoStartUrl, ssoAccountId, ssoRegion, ssoRoleName, ssoSession } = init;
if (!ssoStartUrl && !ssoAccountId && !ssoRegion && !ssoRoleName && !ssoSession) {
throw new CredentialsProviderError(
Expand All @@ -77,22 +77,22 @@ export const defaultProvider = (init: DefaultProviderInit = {}): MemoizedProvide
return fromSSO(init)();
},
async () => {
init.logger?.debug("@aws-sdk/credential-provider-node", "defaultProvider::fromIni");
init.logger?.debug("@aws-sdk/credential-provider-node - defaultProvider::fromIni");
const { fromIni } = await import("@aws-sdk/credential-provider-ini");
return fromIni(init)();
},
async () => {
init.logger?.debug("@aws-sdk/credential-provider-node", "defaultProvider::fromProcess");
init.logger?.debug("@aws-sdk/credential-provider-node - defaultProvider::fromProcess");
const { fromProcess } = await import("@aws-sdk/credential-provider-process");
return fromProcess(init)();
},
async () => {
init.logger?.debug("@aws-sdk/credential-provider-node", "defaultProvider::fromTokenFile");
init.logger?.debug("@aws-sdk/credential-provider-node - defaultProvider::fromTokenFile");
const { fromTokenFile } = await import("@aws-sdk/credential-provider-web-identity");
return fromTokenFile(init)();
},
async () => {
init.logger?.debug("@aws-sdk/credential-provider-node", "defaultProvider::remoteProvider");
init.logger?.debug("@aws-sdk/credential-provider-node - defaultProvider::remoteProvider");
return (await remoteProvider(init))();
},
async () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/credential-provider-node/src/remoteProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export const remoteProvider = async (init: RemoteProviderInit): Promise<AwsCrede
);

if (process.env[ENV_CMDS_RELATIVE_URI] || process.env[ENV_CMDS_FULL_URI]) {
init.logger?.debug("@aws-sdk/credential-provider-node", "remoteProvider::fromHttp/fromContainerMetadata");
init.logger?.debug("@aws-sdk/credential-provider-node - remoteProvider::fromHttp/fromContainerMetadata");
const { fromHttp } = await import("@aws-sdk/credential-provider-http");
return chain(fromHttp(init), fromContainerMetadata(init));
}
Expand All @@ -27,6 +27,6 @@ export const remoteProvider = async (init: RemoteProviderInit): Promise<AwsCrede
};
}

init.logger?.debug("@aws-sdk/credential-provider-node", "remoteProvider::fromInstanceMetadata");
init.logger?.debug("@aws-sdk/credential-provider-node - remoteProvider::fromInstanceMetadata");
return fromInstanceMetadata(init);
};
2 changes: 1 addition & 1 deletion packages/credential-provider-process/src/fromProcess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface FromProcessInit extends SourceProfileInit, CredentialProviderOp
export const fromProcess =
(init: FromProcessInit = {}): AwsCredentialIdentityProvider =>
async () => {
init.logger?.debug("@aws-sdk/credential-provider-process", "fromProcess");
init.logger?.debug("@aws-sdk/credential-provider-process - fromProcess");
const profiles = await parseKnownFiles(init);
return resolveProcessCredentials(getProfileName(init), profiles, init.logger);
};
2 changes: 1 addition & 1 deletion packages/credential-provider-sso/src/fromSSO.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export interface FromSSOInit extends SourceProfileInit, CredentialProviderOption
export const fromSSO =
(init: FromSSOInit & Partial<SsoCredentialsParameters> = {}): AwsCredentialIdentityProvider =>
async () => {
init.logger?.debug("@aws-sdk/credential-provider-sso", "fromSSO");
init.logger?.debug("@aws-sdk/credential-provider-sso - fromSSO");
const { ssoStartUrl, ssoAccountId, ssoRegion, ssoRoleName, ssoSession } = init;
const { ssoClient } = init;
const profileName = getProfileName(init);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,10 @@ export const resolveSSOCredentials = async ({
})
);
} catch (e) {
throw CredentialsProviderError.from(e, SHOULD_FAIL_CREDENTIAL_CHAIN);
throw new CredentialsProviderError(e, {
tryNextLink: SHOULD_FAIL_CREDENTIAL_CHAIN,
logger,
});
}

const { roleCredentials: { accessKeyId, secretAccessKey, sessionToken, expiration, credentialScope } = {} } =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export interface FromTokenFileInit
export const fromTokenFile =
(init: FromTokenFileInit = {}): AwsCredentialIdentityProvider =>
async () => {
init.logger?.debug("@aws-sdk/credential-provider-web-identity", "fromTokenFile");
init.logger?.debug("@aws-sdk/credential-provider-web-identity - fromTokenFile");
const webIdentityTokenFile = init?.webIdentityTokenFile ?? process.env[ENV_TOKEN_FILE];
const roleArn = init?.roleArn ?? process.env[ENV_ROLE_ARN];
const roleSessionName = init?.roleSessionName ?? process.env[ENV_ROLE_SESSION_NAME];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export interface FromWebTokenInit
export const fromWebToken =
(init: FromWebTokenInit): AwsCredentialIdentityProvider =>
async () => {
init.logger?.debug("@aws-sdk/credential-provider-web-identity", "fromWebToken");
init.logger?.debug("@aws-sdk/credential-provider-web-identity - fromWebToken");
const { roleArn, roleSessionName, webIdentityToken, providerId, policyArns, policy, durationSeconds } = init;

let { roleAssumerWithWebIdentity } = init;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export interface FromTemporaryCredentialsOptions extends CredentialProviderOptio
export const fromTemporaryCredentials = (options: FromTemporaryCredentialsOptions): AwsCredentialIdentityProvider => {
let stsClient: STSClient;
return async (): Promise<AwsCredentialIdentity> => {
options.logger?.debug("@aws-sdk/credential-providers", "fromTemporaryCredentials (STS)");
options.logger?.debug("@aws-sdk/credential-providers - fromTemporaryCredentials (STS)");
const params = { ...options.params, RoleSessionName: options.params.RoleSessionName ?? "aws-sdk-js-" + Date.now() };
if (params?.SerialNumber) {
if (!options.mfaCodeProvider) {
Expand Down
2 changes: 1 addition & 1 deletion packages/token-providers/src/fromSso.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export interface FromSsoInit extends SourceProfileInit, CredentialProviderOption
export const fromSso =
(init: FromSsoInit = {}): TokenIdentityProvider =>
async () => {
init.logger?.debug("@aws-sdk/token-providers", "fromSso");
init.logger?.debug("@aws-sdk/token-providers - fromSso");

const profiles = await parseKnownFiles(init);
const profileName = getProfileName(init);
Expand Down
2 changes: 1 addition & 1 deletion packages/token-providers/src/fromStatic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export interface FromStaticInit extends CredentialProviderOptions {
export const fromStatic =
({ token, logger }: FromStaticInit): TokenIdentityProvider =>
async () => {
logger?.debug("@aws-sdk/token-providers", "fromStatic");
logger?.debug("@aws-sdk/token-providers - fromStatic");
if (!token || !token.token) {
throw new TokenProviderError(`Please pass a valid token to fromStatic`, false);
}
Expand Down

0 comments on commit dced10c

Please sign in to comment.