diff --git a/clients/client-cognito-identity/src/CognitoIdentityClient.ts b/clients/client-cognito-identity/src/CognitoIdentityClient.ts index dc39b104f6ac..cd21dd257250 100644 --- a/clients/client-cognito-identity/src/CognitoIdentityClient.ts +++ b/clients/client-cognito-identity/src/CognitoIdentityClient.ts @@ -267,6 +267,25 @@ export interface ClientDefaults extends Partial<__SmithyConfiguration<__HttpHand */ region?: string | __Provider; + /** + * Setting a client profile is similar to setting a value for the + * AWS_PROFILE environment variable. Setting a profile on a client + * in code only affects the single client instance, unlike AWS_PROFILE. + * + * When set, and only for environments where an AWS configuration + * file exists, fields configurable by this file will be retrieved + * from the specified profile within that file. + * Conflicting code configuration and environment variables will + * still have higher priority. + * + * For client credential resolution that involves checking the AWS + * configuration file, the client's profile (this value) will be + * used unless a different profile is set in the credential + * provider options. + * + */ + profile?: string; + /** * The provider populating default tracking information to be sent with `user-agent`, `x-amz-user-agent` header * @internal diff --git a/clients/client-cognito-identity/src/runtimeConfig.ts b/clients/client-cognito-identity/src/runtimeConfig.ts index 6142036599db..eb69c09be7da 100644 --- a/clients/client-cognito-identity/src/runtimeConfig.ts +++ b/clients/client-cognito-identity/src/runtimeConfig.ts @@ -32,6 +32,7 @@ export const getRuntimeConfig = (config: CognitoIdentityClientConfig) => { const defaultConfigProvider = () => defaultsMode().then(loadConfigsForDefaultMode); const clientSharedValues = getSharedRuntimeConfig(config); awsCheckVersion(process.version); + const profileConfig = { profile: config?.profile }; return { ...clientSharedValues, ...config, @@ -42,19 +43,25 @@ export const getRuntimeConfig = (config: CognitoIdentityClientConfig) => { defaultUserAgentProvider: config?.defaultUserAgentProvider ?? createDefaultUserAgentProvider({ serviceId: clientSharedValues.serviceId, clientVersion: packageInfo.version }), - maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS), - region: config?.region ?? loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS), + maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config), + region: + config?.region ?? + loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, { ...NODE_REGION_CONFIG_FILE_OPTIONS, ...profileConfig }), requestHandler: RequestHandler.create(config?.requestHandler ?? defaultConfigProvider), retryMode: config?.retryMode ?? - loadNodeConfig({ - ...NODE_RETRY_MODE_CONFIG_OPTIONS, - default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, - }), + loadNodeConfig( + { + ...NODE_RETRY_MODE_CONFIG_OPTIONS, + default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, + }, + config + ), sha256: config?.sha256 ?? Hash.bind(null, "sha256"), streamCollector: config?.streamCollector ?? streamCollector, - useDualstackEndpoint: config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS), - useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS), - userAgentAppId: config?.userAgentAppId ?? loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS), + useDualstackEndpoint: + config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, profileConfig), + useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, profileConfig), + userAgentAppId: config?.userAgentAppId ?? loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS, profileConfig), }; }; diff --git a/clients/client-s3/src/S3Client.ts b/clients/client-s3/src/S3Client.ts index 48562a08d79a..3874ccac881c 100644 --- a/clients/client-s3/src/S3Client.ts +++ b/clients/client-s3/src/S3Client.ts @@ -658,6 +658,25 @@ export interface ClientDefaults extends Partial<__SmithyConfiguration<__HttpHand */ region?: string | __Provider; + /** + * Setting a client profile is similar to setting a value for the + * AWS_PROFILE environment variable. Setting a profile on a client + * in code only affects the single client instance, unlike AWS_PROFILE. + * + * When set, and only for environments where an AWS configuration + * file exists, fields configurable by this file will be retrieved + * from the specified profile within that file. + * Conflicting code configuration and environment variables will + * still have higher priority. + * + * For client credential resolution that involves checking the AWS + * configuration file, the client's profile (this value) will be + * used unless a different profile is set in the credential + * provider options. + * + */ + profile?: string; + /** * The provider populating default tracking information to be sent with `user-agent`, `x-amz-user-agent` header * @internal diff --git a/clients/client-s3/src/models/models_0.ts b/clients/client-s3/src/models/models_0.ts index 866224ca210e..b331d509fcec 100644 --- a/clients/client-s3/src/models/models_0.ts +++ b/clients/client-s3/src/models/models_0.ts @@ -1,6 +1,5 @@ // smithy-typescript generated code import { ExceptionOptionType as __ExceptionOptionType, SENSITIVE_STRING } from "@smithy/smithy-client"; - import { StreamingBlobTypes } from "@smithy/types"; import { S3ServiceException as __BaseException } from "./S3ServiceException"; diff --git a/clients/client-s3/src/models/models_1.ts b/clients/client-s3/src/models/models_1.ts index 8401d87df86c..c05693432dbb 100644 --- a/clients/client-s3/src/models/models_1.ts +++ b/clients/client-s3/src/models/models_1.ts @@ -1,6 +1,5 @@ // smithy-typescript generated code import { ExceptionOptionType as __ExceptionOptionType, SENSITIVE_STRING } from "@smithy/smithy-client"; - import { StreamingBlobTypes } from "@smithy/types"; import { @@ -40,7 +39,6 @@ import { Tag, TransitionDefaultMinimumObjectSize, } from "./models_0"; - import { S3ServiceException as __BaseException } from "./S3ServiceException"; /** diff --git a/clients/client-s3/src/runtimeConfig.ts b/clients/client-s3/src/runtimeConfig.ts index dba642220c78..6798863166de 100644 --- a/clients/client-s3/src/runtimeConfig.ts +++ b/clients/client-s3/src/runtimeConfig.ts @@ -41,6 +41,7 @@ export const getRuntimeConfig = (config: S3ClientConfig) => { const defaultConfigProvider = () => defaultsMode().then(loadConfigsForDefaultMode); const clientSharedValues = getSharedRuntimeConfig(config); awsCheckVersion(process.version); + const profileConfig = { profile: config?.profile }; return { ...clientSharedValues, ...config, @@ -52,30 +53,39 @@ export const getRuntimeConfig = (config: S3ClientConfig) => { config?.defaultUserAgentProvider ?? createDefaultUserAgentProvider({ serviceId: clientSharedValues.serviceId, clientVersion: packageInfo.version }), disableS3ExpressSessionAuth: - config?.disableS3ExpressSessionAuth ?? loadNodeConfig(NODE_DISABLE_S3_EXPRESS_SESSION_AUTH_OPTIONS), + config?.disableS3ExpressSessionAuth ?? + loadNodeConfig(NODE_DISABLE_S3_EXPRESS_SESSION_AUTH_OPTIONS, profileConfig), eventStreamSerdeProvider: config?.eventStreamSerdeProvider ?? eventStreamSerdeProvider, - maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS), + maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config), md5: config?.md5 ?? Hash.bind(null, "md5"), - region: config?.region ?? loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS), + region: + config?.region ?? + loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, { ...NODE_REGION_CONFIG_FILE_OPTIONS, ...profileConfig }), requestChecksumCalculation: - config?.requestChecksumCalculation ?? loadNodeConfig(NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS), + config?.requestChecksumCalculation ?? + loadNodeConfig(NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS, profileConfig), requestHandler: RequestHandler.create(config?.requestHandler ?? defaultConfigProvider), responseChecksumValidation: - config?.responseChecksumValidation ?? loadNodeConfig(NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS), + config?.responseChecksumValidation ?? + loadNodeConfig(NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS, profileConfig), retryMode: config?.retryMode ?? - loadNodeConfig({ - ...NODE_RETRY_MODE_CONFIG_OPTIONS, - default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, - }), + loadNodeConfig( + { + ...NODE_RETRY_MODE_CONFIG_OPTIONS, + default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, + }, + config + ), sha1: config?.sha1 ?? Hash.bind(null, "sha1"), sha256: config?.sha256 ?? Hash.bind(null, "sha256"), - sigv4aSigningRegionSet: config?.sigv4aSigningRegionSet ?? loadNodeConfig(NODE_SIGV4A_CONFIG_OPTIONS), + sigv4aSigningRegionSet: config?.sigv4aSigningRegionSet ?? loadNodeConfig(NODE_SIGV4A_CONFIG_OPTIONS, profileConfig), streamCollector: config?.streamCollector ?? streamCollector, streamHasher: config?.streamHasher ?? streamHasher, - useArnRegion: config?.useArnRegion ?? loadNodeConfig(NODE_USE_ARN_REGION_CONFIG_OPTIONS), - useDualstackEndpoint: config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS), - useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS), - userAgentAppId: config?.userAgentAppId ?? loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS), + useArnRegion: config?.useArnRegion ?? loadNodeConfig(NODE_USE_ARN_REGION_CONFIG_OPTIONS, profileConfig), + useDualstackEndpoint: + config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, profileConfig), + useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, profileConfig), + userAgentAppId: config?.userAgentAppId ?? loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS, profileConfig), }; }; diff --git a/clients/client-sts/src/STSClient.ts b/clients/client-sts/src/STSClient.ts index 4fb5bfb439da..7aa6e66d5928 100644 --- a/clients/client-sts/src/STSClient.ts +++ b/clients/client-sts/src/STSClient.ts @@ -198,6 +198,25 @@ export interface ClientDefaults extends Partial<__SmithyConfiguration<__HttpHand */ region?: string | __Provider; + /** + * Setting a client profile is similar to setting a value for the + * AWS_PROFILE environment variable. Setting a profile on a client + * in code only affects the single client instance, unlike AWS_PROFILE. + * + * When set, and only for environments where an AWS configuration + * file exists, fields configurable by this file will be retrieved + * from the specified profile within that file. + * Conflicting code configuration and environment variables will + * still have higher priority. + * + * For client credential resolution that involves checking the AWS + * configuration file, the client's profile (this value) will be + * used unless a different profile is set in the credential + * provider options. + * + */ + profile?: string; + /** * The provider populating default tracking information to be sent with `user-agent`, `x-amz-user-agent` header * @internal diff --git a/clients/client-sts/src/runtimeConfig.ts b/clients/client-sts/src/runtimeConfig.ts index 215609bb5d02..ac32e4bde481 100644 --- a/clients/client-sts/src/runtimeConfig.ts +++ b/clients/client-sts/src/runtimeConfig.ts @@ -34,6 +34,7 @@ export const getRuntimeConfig = (config: STSClientConfig) => { const defaultConfigProvider = () => defaultsMode().then(loadConfigsForDefaultMode); const clientSharedValues = getSharedRuntimeConfig(config); awsCheckVersion(process.version); + const profileConfig = { profile: config?.profile }; return { ...clientSharedValues, ...config, @@ -59,19 +60,25 @@ export const getRuntimeConfig = (config: STSClientConfig) => { signer: new NoAuthSigner(), }, ], - maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS), - region: config?.region ?? loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS), + maxAttempts: config?.maxAttempts ?? loadNodeConfig(NODE_MAX_ATTEMPT_CONFIG_OPTIONS, config), + region: + config?.region ?? + loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, { ...NODE_REGION_CONFIG_FILE_OPTIONS, ...profileConfig }), requestHandler: RequestHandler.create(config?.requestHandler ?? defaultConfigProvider), retryMode: config?.retryMode ?? - loadNodeConfig({ - ...NODE_RETRY_MODE_CONFIG_OPTIONS, - default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, - }), + loadNodeConfig( + { + ...NODE_RETRY_MODE_CONFIG_OPTIONS, + default: async () => (await defaultConfigProvider()).retryMode || DEFAULT_RETRY_MODE, + }, + config + ), sha256: config?.sha256 ?? Hash.bind(null, "sha256"), streamCollector: config?.streamCollector ?? streamCollector, - useDualstackEndpoint: config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS), - useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS), - userAgentAppId: config?.userAgentAppId ?? loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS), + useDualstackEndpoint: + config?.useDualstackEndpoint ?? loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, profileConfig), + useFipsEndpoint: config?.useFipsEndpoint ?? loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, profileConfig), + userAgentAppId: config?.userAgentAppId ?? loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS, profileConfig), }; }; diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAccountIdEndpointModeRuntimeConfig.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAccountIdEndpointModeRuntimeConfig.java index 7a1c9b95f96e..2836a291c1c1 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAccountIdEndpointModeRuntimeConfig.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAccountIdEndpointModeRuntimeConfig.java @@ -89,7 +89,7 @@ public Map> getRuntimeConfigWriters( null, AwsDependency.AWS_SDK_CORE, "/account-id-endpoint"); writer.write( - "loadNodeConfig(NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS)"); + "loadNodeConfig(NODE_ACCOUNT_ID_ENDPOINT_MODE_CONFIG_OPTIONS, profileConfig)"); }); break; default: diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java index c514a2a94714..a44b33ebb39c 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddAwsRuntimeConfig.java @@ -99,6 +99,26 @@ public void addConfigInterfaceFields( ? "The AWS region to which this client will send requests" : "The AWS region to use as signing region for AWS Auth") .write("region?: string | __Provider;\n"); + + + writer.writeDocs( + """ + Setting a client profile is similar to setting a value for the + AWS_PROFILE environment variable. Setting a profile on a client + in code only affects the single client instance, unlike AWS_PROFILE. + + When set, and only for environments where an AWS configuration + file exists, fields configurable by this file will be retrieved + from the specified profile within that file. + Conflicting code configuration and environment variables will + still have higher priority. + + For client credential resolution that involves checking the AWS + configuration file, the client's profile (this value) will be + used unless a different profile is set in the credential + provider options. + """) + .write("profile?: string;\n"); } } @@ -145,6 +165,7 @@ public void prepareCustomizations( writer.addDependency(AwsDependency.AWS_SDK_CORE); writer.addImport("emitWarningIfUnsupportedVersion", "awsCheckVersion", AwsDependency.AWS_SDK_CORE); writer.write("awsCheckVersion(process.version);"); + writer.write("const profileConfig = { profile: config?.profile };"); } } @@ -173,7 +194,7 @@ private Map> getDefaultConfig( writer.addImport("NODE_REGION_CONFIG_FILE_OPTIONS", "NODE_REGION_CONFIG_FILE_OPTIONS", TypeScriptDependency.CONFIG_RESOLVER); writer.write( - "loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS)"); + "loadNodeConfig(NODE_REGION_CONFIG_OPTIONS, {...NODE_REGION_CONFIG_FILE_OPTIONS, ...profileConfig})"); }); default: return Collections.emptyMap(); @@ -216,7 +237,7 @@ private Map> getEndpointConfigWriters( writer.addImport("NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS", "NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS", TypeScriptDependency.CONFIG_RESOLVER); - writer.write("loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_USE_DUALSTACK_ENDPOINT_CONFIG_OPTIONS, profileConfig)"); }, "useFipsEndpoint", writer -> { writer.addDependency(TypeScriptDependency.NODE_CONFIG_PROVIDER); @@ -226,7 +247,7 @@ private Map> getEndpointConfigWriters( writer.addImport("NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS", "NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS", TypeScriptDependency.CONFIG_RESOLVER); - writer.write("loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_USE_FIPS_ENDPOINT_CONFIG_OPTIONS, profileConfig)"); } ); default: diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddEndpointDiscoveryPlugin.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddEndpointDiscoveryPlugin.java index e87bd321b2c2..648e0cf2c076 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddEndpointDiscoveryPlugin.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddEndpointDiscoveryPlugin.java @@ -126,7 +126,7 @@ public Map> getRuntimeConfigWriters( writer.addImport("NODE_ENDPOINT_DISCOVERY_CONFIG_OPTIONS", "NODE_ENDPOINT_DISCOVERY_CONFIG_OPTIONS", AwsDependency.MIDDLEWARE_ENDPOINT_DISCOVERY); - writer.write("loadNodeConfig(NODE_ENDPOINT_DISCOVERY_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_ENDPOINT_DISCOVERY_CONFIG_OPTIONS, profileConfig)"); } ); default: diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddHttpChecksumDependency.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddHttpChecksumDependency.java index 60cc445817a8..c29e0e6301a7 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddHttpChecksumDependency.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddHttpChecksumDependency.java @@ -141,7 +141,7 @@ public Map> getRuntimeConfigWriters( TypeScriptDependency.NODE_CONFIG_PROVIDER); writer.addImport("NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS", null, AwsDependency.FLEXIBLE_CHECKSUMS_MIDDLEWARE); - writer.write("loadNodeConfig(NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_REQUEST_CHECKSUM_CALCULATION_CONFIG_OPTIONS, profileConfig)"); }, "responseChecksumValidation", writer -> { writer.addDependency(TypeScriptDependency.NODE_CONFIG_PROVIDER); @@ -149,7 +149,7 @@ public Map> getRuntimeConfigWriters( TypeScriptDependency.NODE_CONFIG_PROVIDER); writer.addImport("NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS", null, AwsDependency.FLEXIBLE_CHECKSUMS_MIDDLEWARE); - writer.write("loadNodeConfig(NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_RESPONSE_CHECKSUM_VALIDATION_CONFIG_OPTIONS, profileConfig)"); } ); case BROWSER: diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java index bf899d38dc3b..1dc06723f962 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java @@ -256,7 +256,7 @@ public Map> getRuntimeConfigWriters( .addDependency(AwsDependency.BUCKET_ENDPOINT_MIDDLEWARE) .addImport("NODE_USE_ARN_REGION_CONFIG_OPTIONS", "NODE_USE_ARN_REGION_CONFIG_OPTIONS", AwsDependency.BUCKET_ENDPOINT_MIDDLEWARE) - .write("loadNodeConfig(NODE_USE_ARN_REGION_CONFIG_OPTIONS)"); + .write("loadNodeConfig(NODE_USE_ARN_REGION_CONFIG_OPTIONS, profileConfig)"); }, "disableS3ExpressSessionAuth", writer -> { writer.addDependency(TypeScriptDependency.NODE_CONFIG_PROVIDER) @@ -268,7 +268,7 @@ public Map> getRuntimeConfigWriters( "NODE_DISABLE_S3_EXPRESS_SESSION_AUTH_OPTIONS", AwsDependency.S3_MIDDLEWARE ) - .write("loadNodeConfig(NODE_DISABLE_S3_EXPRESS_SESSION_AUTH_OPTIONS)"); + .write("loadNodeConfig(NODE_DISABLE_S3_EXPRESS_SESSION_AUTH_OPTIONS, profileConfig)"); } ); default: diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddUserAgentDependency.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddUserAgentDependency.java index b3be00673bbb..b2a8e5c78c9c 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddUserAgentDependency.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddUserAgentDependency.java @@ -84,7 +84,7 @@ public Map> getRuntimeConfigWriters( writer.addDependency(AwsDependency.AWS_SDK_UTIL_USER_AGENT_NODE); writer.addImport("NODE_APP_ID_CONFIG_OPTIONS", "NODE_APP_ID_CONFIG_OPTIONS", AwsDependency.AWS_SDK_UTIL_USER_AGENT_NODE); - writer.write("loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_APP_ID_CONFIG_OPTIONS, profileConfig)"); } ); case BROWSER: diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/auth/http/integration/AwsSdkCustomizeSigV4Auth.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/auth/http/integration/AwsSdkCustomizeSigV4Auth.java index 156853ea1839..70a33414509d 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/auth/http/integration/AwsSdkCustomizeSigV4Auth.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/auth/http/integration/AwsSdkCustomizeSigV4Auth.java @@ -133,7 +133,7 @@ public Map> getRuntimeConfigWriters( null, AwsDependency.AWS_SDK_CORE ); - writer.write("loadNodeConfig(NODE_SIGV4A_CONFIG_OPTIONS)"); + writer.write("loadNodeConfig(NODE_SIGV4A_CONFIG_OPTIONS, profileConfig)"); } ); } diff --git a/packages/credential-provider-cognito-identity/src/fromCognitoIdentity.ts b/packages/credential-provider-cognito-identity/src/fromCognitoIdentity.ts index 13b75764b7d9..ddc82a9b7eaf 100644 --- a/packages/credential-provider-cognito-identity/src/fromCognitoIdentity.ts +++ b/packages/credential-provider-cognito-identity/src/fromCognitoIdentity.ts @@ -33,6 +33,11 @@ export function fromCognitoIdentity(parameters: FromCognitoIdentityParameters): parameters.logger?.debug("@aws-sdk/credential-provider-cognito-identity - fromCognitoIdentity"); const { GetCredentialsForIdentityCommand, CognitoIdentityClient } = await import("./loadCognitoIdentity"); + const fromConfigs = (property: "region" | "profile"): any => + parameters.clientConfig?.[property] ?? + parameters.parentClientConfig?.[property] ?? + awsIdentityProperties?.callerClientConfig?.[property]; + const { Credentials: { AccessKeyId = throwOnMissingAccessKeyId(parameters.logger), @@ -44,10 +49,8 @@ export function fromCognitoIdentity(parameters: FromCognitoIdentityParameters): parameters.client ?? new CognitoIdentityClient( Object.assign({}, parameters.clientConfig ?? {}, { - region: - parameters.clientConfig?.region ?? - parameters.parentClientConfig?.region ?? - awsIdentityProperties?.callerClientConfig?.region, + region: fromConfigs("region"), + profile: fromConfigs("profile"), }) ) ).send( diff --git a/packages/credential-provider-cognito-identity/src/fromCognitoIdentityPool.ts b/packages/credential-provider-cognito-identity/src/fromCognitoIdentityPool.ts index 2cf4d5f12293..b1ff0dbba3da 100644 --- a/packages/credential-provider-cognito-identity/src/fromCognitoIdentityPool.ts +++ b/packages/credential-provider-cognito-identity/src/fromCognitoIdentityPool.ts @@ -37,12 +37,18 @@ export function fromCognitoIdentityPool({ let provider: CognitoIdentityCredentialProvider = async (awsIdentityProperties?: AwsIdentityProperties) => { const { GetIdCommand, CognitoIdentityClient } = await import("./loadCognitoIdentity"); + + const fromConfigs = (property: "region" | "profile"): any => + clientConfig?.[property] ?? + parentClientConfig?.[property] ?? + awsIdentityProperties?.callerClientConfig?.[property]; + const _client = client ?? new CognitoIdentityClient( Object.assign({}, clientConfig ?? {}, { - region: - clientConfig?.region ?? parentClientConfig?.region ?? awsIdentityProperties?.callerClientConfig?.region, + region: fromConfigs("region"), + profile: fromConfigs("profile"), }) ); diff --git a/packages/credential-provider-ini/src/fromIni.ts b/packages/credential-provider-ini/src/fromIni.ts index d505746de1b6..31c245c9e890 100644 --- a/packages/credential-provider-ini/src/fromIni.ts +++ b/packages/credential-provider-ini/src/fromIni.ts @@ -60,14 +60,18 @@ export const fromIni = async ({ callerClientConfig } = {}) => { const init: FromIniInit = { ..._init, - }; - if (callerClientConfig?.region) { - init.parentClientConfig = { - region: callerClientConfig.region, + parentClientConfig: { + ...callerClientConfig, ..._init.parentClientConfig, - }; - } + }, + }; init.logger?.debug("@aws-sdk/credential-provider-ini - fromIni"); const profiles = await parseKnownFiles(init); - return resolveProfileData(getProfileName(init), profiles, init); + return resolveProfileData( + getProfileName({ + profile: _init.profile ?? callerClientConfig?.profile, + }), + profiles, + init + ); }; diff --git a/packages/credential-provider-node/src/credential-provider-node.integ.spec.ts b/packages/credential-provider-node/src/credential-provider-node.integ.spec.ts index b2ac2def6744..1555b6e72bb8 100644 --- a/packages/credential-provider-node/src/credential-provider-node.integ.spec.ts +++ b/packages/credential-provider-node/src/credential-provider-node.integ.spec.ts @@ -1,10 +1,10 @@ import { STS } from "@aws-sdk/client-sts"; import * as credentialProviderHttp from "@aws-sdk/credential-provider-http"; import { fromCognitoIdentity, fromCognitoIdentityPool, fromIni, fromWebToken } from "@aws-sdk/credential-providers"; -import { fromSso } from "@aws-sdk/token-providers"; import { HttpResponse } from "@smithy/protocol-http"; -import type { SourceProfileInit } from "@smithy/shared-ini-file-loader"; -import type { HttpRequest, NodeHttpHandlerOptions, ParsedIniData } from "@smithy/types"; +import type { SharedConfigInit, SourceProfileInit } from "@smithy/shared-ini-file-loader"; +import type { HttpRequest, NodeHttpHandlerOptions, ParsedIniData, SharedConfigFiles } from "@smithy/types"; +import { AdaptiveRetryStrategy, StandardRetryStrategy } from "@smithy/util-retry"; import { PassThrough } from "stream"; import { defaultProvider } from "./defaultProvider"; @@ -41,6 +41,12 @@ jest.mock("@smithy/shared-ini-file-loader", () => { async parseKnownFiles(init: SourceProfileInit): Promise { return iniProfileData; }, + async loadSharedConfigFiles(init: SharedConfigInit): Promise { + return { + configFile: iniProfileData, + credentialsFile: iniProfileData, + }; + }, async getSSOTokenFromFile() { return { accessToken: "mock_sso_token", @@ -69,7 +75,7 @@ jest.mock("@smithy/node-http-handler", () => { assumeRoleArns.push(request.body.match(/RoleArn=(.*?)&/)?.[1]); } - const region = (request.hostname.match(/(sts|cognito-identity)\.(.*?)\./) || [, , "unknown"])[2]; + const region = (request.hostname.match(/(sts|cognito-identity|portal\.sso)\.(.*?)\./) || [, , "unknown"])[2]; if (request.headers.Authorization === "container-authorization") { body.write( @@ -86,7 +92,7 @@ jest.mock("@smithy/node-http-handler", () => { roleCredentials: { accessKeyId: "SSO_ACCESS_KEY_ID", secretAccessKey: "SSO_SECRET_ACCESS_KEY", - sessionToken: "SSO_SESSION_TOKEN", + sessionToken: `SSO_SESSION_TOKEN_${region}`, expiration: "3000-01-01T00:00:00.000Z", }, }) @@ -353,7 +359,7 @@ describe("credential-provider-node integration test", () => { expect(credentials).toEqual({ accessKeyId: "SSO_ACCESS_KEY_ID", secretAccessKey: "SSO_SECRET_ACCESS_KEY", - sessionToken: "SSO_SESSION_TOKEN", + sessionToken: "SSO_SESSION_TOKEN_us-sso-region-1", expiration: new Date("3000-01-01T00:00:00.000Z"), $source: { CREDENTIALS_CODE: "e", @@ -547,7 +553,7 @@ describe("credential-provider-node integration test", () => { expect(credentials).toEqual({ accessKeyId: "SSO_ACCESS_KEY_ID", secretAccessKey: "SSO_SECRET_ACCESS_KEY", - sessionToken: "SSO_SESSION_TOKEN", + sessionToken: "SSO_SESSION_TOKEN_us-sso-region-1", expiration: new Date("3000-01-01T00:00:00.000Z"), $source: { CREDENTIALS_PROFILE_SSO: "r", @@ -910,6 +916,327 @@ describe("credential-provider-node integration test", () => { ); }); + describe("client-scoped code configuration of AWS profile", () => { + it("should allow clients to resolve credentials from different profiles", async () => { + iniProfileData.aaa = { + aws_access_key_id: "aaa", + aws_secret_access_key: "aaa", + aws_session_token: "aaa", + region: "ap-northeast-1", + }; + iniProfileData.bbb = { + aws_access_key_id: "bbb", + aws_secret_access_key: "bbb", + aws_session_token: "bbb", + region: "us-east-1", + }; + + const clientA = new STS({ + profile: "aaa", + }); + const clientB = new STS({ + profile: "bbb", + }); + + await clientA.getCallerIdentity(); + await clientB.getCallerIdentity(); + + expect(await clientA.config.credentials()).toEqual({ + $source: { + CREDENTIALS_PROFILE: "n", + }, + accessKeyId: "aaa", + secretAccessKey: "aaa", + sessionToken: "aaa", + }); + expect(await clientB.config.credentials()).toEqual({ + $source: { + CREDENTIALS_PROFILE: "n", + }, + accessKeyId: "bbb", + secretAccessKey: "bbb", + sessionToken: "bbb", + }); + }); + it("should load various configuration properties from different profiles", async () => { + // set AWS_PROFILE to show that client code-level profile takes priority over env. + process.env.AWS_PROFILE = "default"; + iniProfileData.aaa = { + aws_access_key_id: "aaa", + aws_secret_access_key: "aaa", + aws_session_token: "aaa", + region: "ap-northeast-1", + retry_mode: "adaptive", + max_attempts: "33", + use_fips_endpoint: "true", + use_dualstack_endpoint: "true", + }; + iniProfileData.bbb = { + aws_access_key_id: "bbb", + aws_secret_access_key: "bbb", + aws_session_token: "bbb", + region: "us-east-1", + retry_mode: "standard", + max_attempts: "12", + use_fips_endpoint: "false", + use_dualstack_endpoint: "false", + }; + + const clientA = new STS({ + profile: "aaa", + }); + const clientB = new STS({ + profile: "bbb", + }); + + await clientA.getCallerIdentity(); + await clientB.getCallerIdentity(); + + expect(await clientA.config.region()).toEqual(iniProfileData.aaa.region); + expect(await clientA.config.retryStrategy()).toBeInstanceOf(AdaptiveRetryStrategy); + expect(await clientA.config.maxAttempts()).toEqual(Number(iniProfileData.aaa.max_attempts)); + expect(await clientA.config.useFipsEndpoint()).toEqual(iniProfileData.aaa.use_fips_endpoint === "true"); + expect(await clientA.config.useDualstackEndpoint()).toEqual(iniProfileData.aaa.use_dualstack_endpoint === "true"); + + expect(await clientB.config.region()).toEqual(iniProfileData.bbb.region); + expect(await clientB.config.retryStrategy()).toBeInstanceOf(StandardRetryStrategy); + expect(await clientB.config.maxAttempts()).toEqual(Number(iniProfileData.bbb.max_attempts)); + expect(await clientB.config.useFipsEndpoint()).toEqual(iniProfileData.bbb.use_fips_endpoint === "true"); + expect(await clientB.config.useDualstackEndpoint()).toEqual(iniProfileData.bbb.use_dualstack_endpoint === "true"); + }); + + it("should allow client profile to control fromIni init profile in implicit (default) credentials provider", async () => { + sts = new STS({ + profile: "assume", + }); + iniProfileData.static = { + aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY", + aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY", + }; + iniProfileData.assume = { + region: "eu-west-1", + role_arn: "ROLE_ARN", + role_session_name: "ROLE_SESSION_NAME", + external_id: "EXTERNAL_ID", + source_profile: "static", + }; + await sts.getCallerIdentity({}); + const credentials = await sts.config.credentials(); + expect(credentials).toEqual({ + accessKeyId: "STS_AR_ACCESS_KEY_ID", + secretAccessKey: "STS_AR_SECRET_ACCESS_KEY", + sessionToken: "STS_AR_SESSION_TOKEN_eu-west-1", + expiration: new Date("3000-01-01T00:00:00.000Z"), + $source: { + CREDENTIALS_PROFILE_SOURCE_PROFILE: "o", + CREDENTIALS_STS_ASSUME_ROLE: "i", + }, + }); + }); + + it( + "should allow client profile to control fromIni init profile in explicit credentials provider " + + "without requiring redundant setting of profile or region on the provider factory", + async () => { + sts = new STS({ + profile: "assume", + // no profile is given to fromIni(), but it is used in + // the context of this client and should fall back to the client's + // profile. + credentials: fromIni(), + }); + const sts2 = new STS({}); + Object.assign(iniProfileData.default, { + aws_access_key_id: "DEFAULT", + aws_secret_access_key: "DEFAULT", + }); + iniProfileData.static = { + aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY", + aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY", + }; + iniProfileData.assume = { + region: "ap-northeast-1", + role_arn: "ROLE_ARN", + role_session_name: "ROLE_SESSION_NAME", + external_id: "EXTERNAL_ID", + source_profile: "static", + }; + await sts.getCallerIdentity({}); + const credentials = await sts.config.credentials(); + expect(credentials).toEqual({ + accessKeyId: "STS_AR_ACCESS_KEY_ID", + secretAccessKey: "STS_AR_SECRET_ACCESS_KEY", + sessionToken: "STS_AR_SESSION_TOKEN_ap-northeast-1", + expiration: new Date("3000-01-01T00:00:00.000Z"), + $source: { + CREDENTIALS_CODE: "e", + CREDENTIALS_PROFILE_SOURCE_PROFILE: "o", + CREDENTIALS_STS_ASSUME_ROLE: "i", + }, + }); + expect(await sts2.config.credentials()).toEqual({ + accessKeyId: "DEFAULT", + secretAccessKey: "DEFAULT", + sessionToken: undefined, + $source: { + CREDENTIALS_PROFILE: "n", + }, + }); + } + ); + + it("credential provider factory init still overrides profile setting", async () => { + sts = new STS({ + profile: "assume", + credentials: fromIni({ + profile: "default", + }), + }); + Object.assign(iniProfileData.default, { + aws_access_key_id: "DEFAULT", + aws_secret_access_key: "DEFAULT", + region: "us-east-1", + }); + iniProfileData.static = { + aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY", + aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY", + }; + iniProfileData.assume = { + region: "ap-northeast-1", + role_arn: "ROLE_ARN", + role_session_name: "ROLE_SESSION_NAME", + external_id: "EXTERNAL_ID", + source_profile: "static", + }; + await sts.getCallerIdentity({}); + const credentials = await sts.config.credentials(); + expect(credentials).toEqual({ + accessKeyId: "DEFAULT", + secretAccessKey: "DEFAULT", + sessionToken: undefined, + $source: { + CREDENTIALS_CODE: "e", + CREDENTIALS_PROFILE: "n", + }, + }); + expect(await sts.config.region()).toEqual("ap-northeast-1"); + }); + + describe("sso", () => { + it( + "should allow SSO region to be used in the SSO client request if " + + "a profile includes a region but also SSO credentials", + async () => { + sts = new STS({ + profile: "sso_root", + }); + iniProfileData["sso-session.ssoNew"] = { + sso_region: "us-sso-region-2", + sso_start_url: "SSO_START_URL", + sso_registration_scopes: "sso:account:access", + }; + iniProfileData.sso_root = { + sso_region: "us-sso-region-1", + sso_session: "ssoNew", + sso_account_id: "1234", + sso_role_name: "integration-test", + region: "ap-northeast-1", + }; + await sts.getCallerIdentity({}); + const credentials = await sts.config.credentials(); + expect(credentials).toEqual({ + accessKeyId: "SSO_ACCESS_KEY_ID", + secretAccessKey: "SSO_SECRET_ACCESS_KEY", + sessionToken: "SSO_SESSION_TOKEN_us-sso-region-2", + expiration: new Date("3000-01-01T00:00:00.000Z"), + $source: { + CREDENTIALS_PROFILE_SSO: "r", + CREDENTIALS_SSO: "s", + }, + }); + expect(await sts.config.region()).toEqual("ap-northeast-1"); + } + ); + it( + "should allow SSO region to be used in the SSO client request if " + + "a client has set a region in code but selects a profile with SSO creds", + async () => { + sts = new STS({ + region: "eu-west-1", + credentials: fromIni({ + profile: "sso_root", + }), + }); + iniProfileData["sso-session.ssoNew"] = { + sso_region: "us-sso-region-2", + sso_start_url: "SSO_START_URL", + sso_registration_scopes: "sso:account:access", + }; + iniProfileData.sso_root = { + sso_region: "us-sso-region-1", + sso_session: "ssoNew", + sso_account_id: "1234", + sso_role_name: "integration-test", + region: "ap-northeast-1", + }; + await sts.getCallerIdentity({}); + const credentials = await sts.config.credentials(); + expect(credentials).toEqual({ + accessKeyId: "SSO_ACCESS_KEY_ID", + secretAccessKey: "SSO_SECRET_ACCESS_KEY", + sessionToken: "SSO_SESSION_TOKEN_us-sso-region-2", + expiration: new Date("3000-01-01T00:00:00.000Z"), + $source: { + CREDENTIALS_CODE: "e", + CREDENTIALS_PROFILE_SSO: "r", + CREDENTIALS_SSO: "s", + }, + }); + expect(await sts.config.region()).toEqual("eu-west-1"); + } + ); + }); + + it("source_profile does not bring over any client configuration options", async () => { + sts = new STS({ + profile: "assume", + }); + iniProfileData.static = { + aws_access_key_id: "ASSUME_STATIC_ACCESS_KEY", + aws_secret_access_key: "ASSUME_STATIC_SECRET_KEY", + region: "us-west-2", + retry_mode: "adaptive", + max_attempts: "33", + use_fips_endpoint: "true", + use_dualstack_endpoint: "true", + }; + iniProfileData.assume = { + region: "ap-northeast-1", + role_arn: "ROLE_ARN", + role_session_name: "ROLE_SESSION_NAME", + external_id: "EXTERNAL_ID", + source_profile: "static", + }; + await sts.getCallerIdentity({}); + const credentials = await sts.config.credentials(); + expect(credentials).toEqual({ + accessKeyId: "STS_AR_ACCESS_KEY_ID", + secretAccessKey: "STS_AR_SECRET_ACCESS_KEY", + sessionToken: "STS_AR_SESSION_TOKEN_ap-northeast-1", + expiration: new Date("3000-01-01T00:00:00.000Z"), + $source: { + CREDENTIALS_PROFILE_SOURCE_PROFILE: "o", + CREDENTIALS_STS_ASSUME_ROLE: "i", + }, + }); + expect(await sts.config.region()).toEqual("ap-northeast-1"); + expect(await sts.config.retryStrategy()).toBeInstanceOf(StandardRetryStrategy); + expect(await sts.config.maxAttempts()).toEqual(3); + expect(await sts.config.useFipsEndpoint()).toEqual(false); + expect(await sts.config.useDualstackEndpoint()).toEqual(false); + }); + }); + describe("No credentials available", () => { it("should throw CredentialsProviderError", async () => { process.env.AWS_EC2_METADATA_DISABLED = "true"; diff --git a/packages/credential-provider-process/src/fromProcess.ts b/packages/credential-provider-process/src/fromProcess.ts index ec03d36ac8c8..bd211153ef7c 100644 --- a/packages/credential-provider-process/src/fromProcess.ts +++ b/packages/credential-provider-process/src/fromProcess.ts @@ -1,6 +1,5 @@ -import type { CredentialProviderOptions } from "@aws-sdk/types"; +import type { CredentialProviderOptions, RuntimeConfigAwsCredentialIdentityProvider } from "@aws-sdk/types"; import { getProfileName, parseKnownFiles, SourceProfileInit } from "@smithy/shared-ini-file-loader"; -import { AwsCredentialIdentityProvider } from "@smithy/types"; import { resolveProcessCredentials } from "./resolveProcessCredentials"; @@ -16,9 +15,15 @@ export interface FromProcessInit extends SourceProfileInit, CredentialProviderOp * in ini files. */ export const fromProcess = - (init: FromProcessInit = {}): AwsCredentialIdentityProvider => - async () => { + (init: FromProcessInit = {}): RuntimeConfigAwsCredentialIdentityProvider => + async ({ callerClientConfig } = {}) => { init.logger?.debug("@aws-sdk/credential-provider-process - fromProcess"); const profiles = await parseKnownFiles(init); - return resolveProcessCredentials(getProfileName(init), profiles, init.logger); + return resolveProcessCredentials( + getProfileName({ + profile: init.profile ?? callerClientConfig?.profile, + }), + profiles, + init.logger + ); }; diff --git a/packages/credential-provider-sso/src/fromSSO.ts b/packages/credential-provider-sso/src/fromSSO.ts index 1960b4855b63..c6e53fe707ef 100644 --- a/packages/credential-provider-sso/src/fromSSO.ts +++ b/packages/credential-provider-sso/src/fromSSO.ts @@ -1,4 +1,4 @@ -import type { CredentialProviderOptions } from "@aws-sdk/types"; +import type { CredentialProviderOptions, RuntimeConfigAwsCredentialIdentityProvider } from "@aws-sdk/types"; import { CredentialsProviderError } from "@smithy/property-provider"; import { getProfileName, loadSsoSessionData, parseKnownFiles, SourceProfileInit } from "@smithy/shared-ini-file-loader"; import { AwsCredentialIdentityProvider } from "@smithy/types"; @@ -79,12 +79,14 @@ export interface FromSSOInit extends SourceProfileInit, CredentialProviderOption * ``` */ export const fromSSO = - (init: FromSSOInit & Partial = {}): AwsCredentialIdentityProvider => - async () => { + (init: FromSSOInit & Partial = {}): RuntimeConfigAwsCredentialIdentityProvider => + async ({ callerClientConfig } = {}) => { init.logger?.debug("@aws-sdk/credential-provider-sso - fromSSO"); const { ssoStartUrl, ssoAccountId, ssoRegion, ssoRoleName, ssoSession } = init; const { ssoClient } = init; - const profileName = getProfileName(init); + const profileName = getProfileName({ + profile: init.profile ?? callerClientConfig?.profile, + }); if (!ssoStartUrl && !ssoAccountId && !ssoRegion && !ssoRoleName && !ssoSession) { // Load the SSO config from shared AWS config file. diff --git a/packages/credential-provider-web-identity/src/fromWebToken.ts b/packages/credential-provider-web-identity/src/fromWebToken.ts index 41489ce7467c..f18555bf74a3 100644 --- a/packages/credential-provider-web-identity/src/fromWebToken.ts +++ b/packages/credential-provider-web-identity/src/fromWebToken.ts @@ -169,14 +169,10 @@ export const fromWebToken = { ...init.clientConfig, credentialProviderLogger: init.logger, - ...(awsIdentityProperties?.callerClientConfig?.region || init.parentClientConfig - ? { - parentClientConfig: { - region: awsIdentityProperties?.callerClientConfig?.region, - ...init.parentClientConfig, - }, - } - : {}), + parentClientConfig: { + ...awsIdentityProperties?.callerClientConfig, + ...init.parentClientConfig, + }, }, init.clientPlugins ); diff --git a/packages/dsql-signer/src/Signer.ts b/packages/dsql-signer/src/Signer.ts index 070fb955132b..ba3604f990ba 100644 --- a/packages/dsql-signer/src/Signer.ts +++ b/packages/dsql-signer/src/Signer.ts @@ -12,7 +12,8 @@ type DsqlSignerAction = "DbConnect" | "DbConnectAdmin"; export interface DsqlSignerConfig { /** - * The AWS credentials to sign requests with. Uses the default credential provider chain if not specified. + * The AWS credentials to sign requests with. + * Uses the default credential provider chain if not specified. */ credentials?: AwsCredentialIdentity | AwsCredentialIdentityProvider; @@ -22,7 +23,8 @@ export interface DsqlSignerConfig { hostname: string; /** - * The region the database is located in. Uses the region inferred from the runtime if omitted. + * The region the database is located in. + * Uses the region from the profile or inferred from the runtime if omitted. */ region?: string; @@ -35,6 +37,16 @@ export interface DsqlSignerConfig { * The amount of time in seconds the generated token is valid. */ expiresIn?: number; + + /** + * Optional. Can be provided to configure region from a profile + * if operating in an environment with a file system having + * an AWS configuration file. + * + * The credentials will also resolve based on this profile, if using + * a credentials provider that includes the AWS configuration file. + */ + profile?: string; } /** diff --git a/packages/middleware-signing/src/awsAuthConfiguration.ts b/packages/middleware-signing/src/awsAuthConfiguration.ts index 539f317441ee..010d55a5c1c4 100644 --- a/packages/middleware-signing/src/awsAuthConfiguration.ts +++ b/packages/middleware-signing/src/awsAuthConfiguration.ts @@ -318,6 +318,7 @@ const createConfigBoundCredentialProvider = (input: { credentials?: AwsCredentialIdentity | AwsCredentialIdentityProvider | RuntimeConfigAwsCredentialIdentityProvider; credentialDefaultProvider: PreviouslyResolved["credentialDefaultProvider"]; region: PreviouslyResolved["region"]; + profile?: string; }): AwsCredentialIdentityProvider => { const normalizedCredentialsProvider = input.credentials ? normalizeCredentialProvider(input.credentials) @@ -330,6 +331,7 @@ const createConfigBoundCredentialProvider = (input: { (normalizedCredentialsProvider as RuntimeConfigAwsCredentialIdentityProvider)({ callerClientConfig: { region: normalizeProvider(input.region), + profile: input.profile, }, }); return normalizedCreds; diff --git a/packages/rds-signer/src/Signer.ts b/packages/rds-signer/src/Signer.ts index 406443550aa0..c0f2178263f0 100644 --- a/packages/rds-signer/src/Signer.ts +++ b/packages/rds-signer/src/Signer.ts @@ -13,7 +13,8 @@ import { getRuntimeConfig as __getRuntimeConfig } from "./runtimeConfig"; export interface SignerConfig { /** - * The AWS credentials to sign requests with. Uses the default credential provider chain if not specified. + * The AWS credentials to sign requests with. + * Uses the default credential provider chain if not specified. */ credentials?: AwsCredentialIdentity | AwsCredentialIdentityProvider; /** @@ -25,7 +26,9 @@ export interface SignerConfig { */ port: number; /** - * The region the database is located in. Uses the region inferred from the runtime if omitted. + * The region the database is located in. + * Uses the region of the given profile or inferred from the runtime if + * both are omitted. */ region?: string; /** @@ -36,6 +39,15 @@ export interface SignerConfig { * The username to login as. */ username: string; + /** + * Optional. Can be provided to configure region from a profile + * if operating in an environment with a file system having + * an AWS configuration file. + * + * The credentials will also resolve based on this profile, if using + * a credentials provider that includes the AWS configuration file. + */ + profile?: string; } /** diff --git a/packages/rds-signer/src/runtimeConfig.ts b/packages/rds-signer/src/runtimeConfig.ts index f413d71bae1a..60afbb0ee68a 100644 --- a/packages/rds-signer/src/runtimeConfig.ts +++ b/packages/rds-signer/src/runtimeConfig.ts @@ -12,8 +12,17 @@ export const getRuntimeConfig = (config: SignerConfig) => { return { runtime: "node", sha256: config?.sha256 ?? Hash.bind(null, "sha256"), - credentials: config?.credentials ?? fromNodeProviderChain(), - region: config?.region ?? loadConfig(NODE_REGION_CONFIG_OPTIONS, NODE_REGION_CONFIG_FILE_OPTIONS), + credentials: + config?.credentials ?? + fromNodeProviderChain({ + profile: config.profile, + }), + region: + config?.region ?? + loadConfig(NODE_REGION_CONFIG_OPTIONS, { + ...NODE_REGION_CONFIG_FILE_OPTIONS, + profile: config.profile, + }), ...config, }; }; diff --git a/packages/token-providers/src/fromSso.ts b/packages/token-providers/src/fromSso.ts index 0266209a3b6c..06fde9511e6b 100644 --- a/packages/token-providers/src/fromSso.ts +++ b/packages/token-providers/src/fromSso.ts @@ -37,22 +37,20 @@ export interface FromSsoInit extends SourceProfileInit, CredentialProviderOption */ export const fromSso = (_init: FromSsoInit = {}): RuntimeConfigIdentityProvider => - async (awsIdentityProperties?: AwsIdentityProperties) => { + async ({ callerClientConfig } = {}) => { const init: FromSsoInit = { ..._init, - ...(awsIdentityProperties?.callerClientConfig?.region - ? { - parentClientConfig: { - region: awsIdentityProperties?.callerClientConfig?.region, - ..._init.parentClientConfig, - }, - } - : {}), + parentClientConfig: { + ...callerClientConfig, + ..._init.parentClientConfig, + }, }; init.logger?.debug("@aws-sdk/token-providers - fromSso"); const profiles = await parseKnownFiles(init); - const profileName = getProfileName(init); + const profileName = getProfileName({ + profile: init.profile ?? callerClientConfig?.profile, + }); const profile = profiles[profileName]; if (!profile) { diff --git a/packages/types/src/credentials.ts b/packages/types/src/credentials.ts index 33b02303ad8a..e7abfbf8c3e2 100644 --- a/packages/types/src/credentials.ts +++ b/packages/types/src/credentials.ts @@ -1,4 +1,4 @@ -import { Logger, RequestHandler } from "@smithy/types"; +import { Logger } from "@smithy/types"; import { AwsCredentialIdentity } from "./identity"; import { Provider } from "./util"; @@ -48,6 +48,7 @@ export type CredentialProviderOptions = { */ parentClientConfig?: { region?: string | Provider; + profile?: string; [key: string]: unknown; }; }; diff --git a/packages/types/src/identity/AwsCredentialIdentity.ts b/packages/types/src/identity/AwsCredentialIdentity.ts index ad1091af88ac..903050883f91 100644 --- a/packages/types/src/identity/AwsCredentialIdentity.ts +++ b/packages/types/src/identity/AwsCredentialIdentity.ts @@ -10,6 +10,7 @@ export { AwsCredentialIdentity, AwsCredentialIdentityProvider, IdentityProvider export interface AwsIdentityProperties { callerClientConfig?: { region(): Promise; + profile?: string; }; }