-
Notifications
You must be signed in to change notification settings - Fork 586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Assuming role configured in AWS profile does not work outside of aws partition (China, US Gov Cloud, etc.) #6711
Comments
When I modify the code to the following it is working My confusion is that even if I specify the region in the .config and credentials files it doesn't seem to take effect whether fromIni can read . /aws/config? [root@ip-172-31-22-83 nodejs]# cat a.js
const { fromIni } = require("@aws-sdk/credential-providers");
const { STSClient, GetCallerIdentityCommand } = require("@aws-sdk/client-sts");
async function getRoleIdentity() {
const credentials = fromIni({
profile: "tes_assume",
clientConfig: { region: "cn-north-1" }
});
console.log(`credentials:`, credentials);
const stsClient = new STSClient({
endpoint: "https://sts.cn-north-1.amazonaws.com.cn",
credentials,
region: "cn-north-1",
});
try {
// 调用 GetCallerIdentity API
const command = new GetCallerIdentityCommand({});
const response = await stsClient.send(command);
console.log("Current Role Identity:");
console.log(`response:`, response);
console.log(`Account: ${response.Account}`);
console.log(`UserId: ${response.UserId}`);
console.log(`ARN: ${response.Arn}`);
} catch (error) {
console.error("Error fetching identity:", error);
}
}
getRoleIdentity(); |
I can't reproduce this issue In config -
In credentials
Code I have import { STSClient, GetCallerIdentityCommand } from "@aws-sdk/client-sts";
import { fromIni } from "@aws-sdk/credential-providers";
async function getRoleIdentity() {
const credentials = fromIni({
profile: "test",
// clientConfig: { region: "us-east-1" },
});
console.log("credentials: ", credentials);
const stsClient = new STSClient({
credentials,
region: "us-east-1",
});
try {
const command = new GetCallerIdentityCommand({});
const response = await stsClient.send(command);
console.log("Current Role Identity:");
console.log(`Account: ${response.Account}`);
console.log(`UserId: ${response.UserId}`);
console.log(`ARN: ${response.Arn}`);
} catch (error) {
console.error("Error fetching identity:", error);
}
}
getRoleIdentity(); I can get the result without specifying the region. I will talk about it with the team |
Hey @csy97 ,
Please let me know if you have any other questions. Thanks |
Hi @zshzbh, We do have additional questions. The It doesn't seem correct for SDKv3 to ignore the |
I did some research using mitmproxy to see what the different clients do, comparing the AWS CLI, SDKv2 and SDKv3. TL;DR: The CLI and SDKv2 behave the same, SDKv3 behaves differently. ConfigThe behavior depends a lot on the configuration setup. I used the following config:
ResultsThe AWS CLI (v1 and v2)For better or worse, the AWS CLI defines the Gold Standard of how these files are supposed to behave.
Result, 2 calls, both to
Conclusion: the AWS CLI v2 uses the region of the target profile to determine in what region to perform the I also tested AWS CLIv1 (including The SDKv2I used the following program to test the behavior of the previous iteration of the SDK: process.env.AWS_SDK_LOAD_CONFIG = '1';
import { STS } from 'aws-sdk';
import { SharedIniFileCredentials } from 'aws-sdk';
import { ProxyAgent } from 'proxy-agent';
import * as AWS from 'aws-sdk';
async function main() {
AWS.config.update({
httpOptions: { agent: new ProxyAgent() }
});
// Load credentials from INI file
const credentials = new SharedIniFileCredentials({ profile: 'Assumable' });
// Configure STS client with proxy and credentials
const sts = new STS({
credentials: credentials,
});
const identity = await sts.getCallerIdentity().promise();
console.log('Caller Identity:', identity);
}
main().catch(e => {
console.error(e);
process.exitCode = 1;
}); Command line:
Result, 2 calls, one
Conclusion: the SDK v2 uses the region of the target profile to determine in what region to perform the If I pass the profile with
SDK v3Using the following program: import { STS } from '@aws-sdk/client-sts';
import { ProxyAgent } from 'proxy-agent';
import { fromNodeProviderChain } from '@aws-sdk/credential-providers';
import { NodeHttpHandler } from '@smithy/node-http-handler';
async function main() {
// Configure proxy for STS client
const clientConfig = {
requestHandler: new NodeHttpHandler({
httpsAgent: new ProxyAgent()
})
};
const stsClient = new STS({
credentials: fromNodeProviderChain({ profile: 'Assumable', clientConfig }),
...clientConfig,
});
const identity = await stsClient.getCallerIdentity();
console.log('Caller Identity:', identity);
}
main().catch(e => {
console.error(e);
process.exitCode = 1;
}); Command line:
Results
Conclusion: I guess again I can't fault the SDK for performing the With
At least the target region is correct, but the AssumeRole region is still wrong! ConclusionDisregarding the target region of the
One of these is not like the others... 😬 |
For shits and giggles, I decided to give myself an aneurism and tried to pass in different sources of region information that conflict with the profile setting, using command-line flags and environment variables, to see what would happen:
The CLIs will always let environment variables and command line switches override both regions. The CLIv1 ignores SDKv2 ignores SDKv3 ignores |
Hey @rix0rrr, Thanks for the test! The CLI is a special case as it supports command line options. The command line options in the CLI are roughly equivalent to specifying the region in a service client instantiation, so the region specified in CLI always takes precedence. As for JS SDK V3 defaults to As for JS SDK V2, as it's maintenance mode, we only fix critical bugs and security issues. Thanks! |
The current search order for inner STS assume role region is:
For all SDKs, the general configuration precedence is the same: CODE, ENV, FILE, in that order. // no credentials provider is set, the default credentials provider
// will prioritize the parent client region
new Client({ region: 'us-west-2' });
// STS AssumeRole is called with us-west-2 (priority=2). The UX problem here is that when you define a custom credentials provider, import { fromIni } from "@aws-sdk/credential-providers";
const provider = fromIni({ ... }); even though this is an SDK credential provider, it is a standalone function. As such, it is considered a CODE level configuration, so the region should be set on it like so: fromIni({ profile: "abc", clientConfig: { region: "..." } }); If you were to instead set All that said, the behavior clearly defies the expectations of the caller, so we need to think about what can be safely changed. Initially, I would consider the following change:
|
We need to configure things like a proxy agent, do we have to configure in code. Yet I still want the region from the profile if that what is being asked for by the user |
Providing a copy of an internal doc here for informational purposes. AWS SDK JSv3 - credential provider inner client region resolution behaviorIn the AWS SDK for JavaScript v3, a “credential provider” is any function having the signature () => Promise<AwsCredentialIdentity>; where the identity is a data object containing at least an AWS access key id and secret access key pair. Below is how credential providers offered by the SDK are combined with clients by user code. import {
fromIni, fromCognitoIdentity, fromWebToken, fromSSO,
fromNodeProviderChain, fromEnv
// etc.
} from "@aws-sdk/credential-providers";
import { S3 } from "@aws-sdk/client-s3";
const s3 = new S3({
region: "ap-northeast-1",
credentials: fromIni() // if this resolves to STS, what region is used?
}); One immediate pitfall for users is that, because these credential providers are standalone functions and can be used to fetch credentials without the context of any particular SDK client such as S3 shown above, and because some credentials are fetched with “inner” clients such as STS, SSO, SSO-OIDC, and CognitoIdentity, it is incredibly non-obvious that the user must supply the desired region to both the outer S3 client and the inner credentials client. // A devx pitfall:
// matching inner/outer region declarations have been required since 2020 GA
// if using an credential provider client like STS.
new S3({
region: "ap-northeast-1",
credentials: fromIni({ clientConfig: { region: "ap-northeast-1" }})
}); A partial solutionIn #5758, from Feb 2024, v3.511.0, the JS team modified the default behavior so that in the absence of a user-specified credentials provider, the default provider would use the client’s region. // v3.511.0
new S3({
region: "ap-northeast-1"
});
// if STS resolves the credentials, it will prefer the client's
// region of ap-northeast-1 unless overridden. However, for cases where a provider is specified, this fallback does not happen. // provider initialized with no idea what client it is associated with.
const provider = fromIni();
// provider uses us-east-1 instead of the client's region. 😫
new S3({
region: "ap-northeast-1",
credentials: provider
}); A better solution (proposal)PR: #6726 I propose that we enable all inner-client credential providers, whether implicitly used by the default credential chain of a client, or passed to a client as code credentials, to have the ability to know the client’s region if called in the context of a client. The result for the customer will be that credential provider regions match simply and intuitively with the client they are being used with. new S3({
region: "ap-northeast-1",
credentials: fromIni() // uses client's region 👍
}); const provider = fromIni();
new S3({
region: "ap-northeast-1",
credentials: provider // uses client's region 👍
}); import {
fromIni, fromCognitoIdentity, createCredentialChain
} from "@aws-sdk/credential-providers";
new S3({
region: "ap-northeast-1",
credentials: createCredentialChain(fromCognitoIdentity, fromIni)
// all provider steps in the chain use client region 👍
}); Code MechanismAs of SRA Identity & Auth, the signature of AwsCredentialIdentityProvider has changed, from // pre-SRA
() => Promise<AwsCredentialIdentity>;
// post-SRA
(identityProperties?: Record<string, any>) => Promise<AwsCredentialIdentity>;
// identityProperties is not currently used to convey anything. The SRA anticipated that additional properties might be needed at the invocation of the provider, and not merely in its factory function as before. In the proposed PR, this has been turned into an AWS-specific type that is used in our credential providers. type RegionalAwsCredentialIdentityProvider =
({ contextClientConfig: { region(): Promise<string> }})
=> Promise<AwsCredentialIdentity>; This allows the SDK’s config resolver, which builds the normalized credential provider function, to bind the config region during normalization. // simplified for illustration: code in config resolver.
const resolveConfig(config) => {
// 1. normalize the provider or use the default chain.
const credentialsProvider = normalizeProvider(config.credentials);
// 2. (new) additionally bind the config's region.
const regionBoundCredentialsProvider = () => {
return credentialsProvider({ contextClientConfig: config });
}
// 3. set the normalized and bound provider back to the config.
config.credentials = regionBoundCredentialsProvider;
} ConsiderationsIs this a breaking change?
But users consider behavior changes to be breaking changes...
new S3({
region: "ap-northeast-1",
credentials: fromIni({ clientConfig: { region: "eu-west-1" }})
// questionable, but still allowed.
}); Open Question: what about the profile region?Consider the following scenario, assuming no environment variables are set.
Since you cannot code-configure a profile at the client level, S3 in this example initializes with the default profile and its region of us-west-2. However, credentials are sourced from configuration file with profile “a”. This profile has a region of ap-northeast-1, however the parent or context client has a region of us-west-2. Should the profile region take priority or should the context/parent/outer client region take priority? new S3({
// S3 client region is us-west-2 from default profile.
credentials: fromIni({ profile: "a" })
// role_arn etc. are used, but the profile's region is ignored currently,
// so us-west-2 from the client will be used in the proposed change.
}); Reasons to prioritize client region over profile region:
Reasons to prioritize profile region over client region:
Alternate Example 1: using credential provider outside of a client. // invoked outside of client, will use profile region,
// or fallback to global (us-east-1).
const credentials = await fromIni({ profile: "a" })(); Alternate Example 2: using environment variable to select the profile. // profile selected globally via ENV.
process.env.AWS_PROFILE="a";
// client region will be sourced from profile "a".
new S3({
// assume role region will also use the profile's.
credentials: fromIni()
}); |
Well howdy-doody doesn't that all sound awfully familiar 😅 |
Checkboxes for prior research
Describe the bug
When I call GetCallerIdentityCommand at cn-north-1 the request will be sent to the STS service at us-east-1. China's resources are isolated from global, so obviously this won't work in China.
Regression Issue
SDK version number
@aws-sdk/package-name@version, ...
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v18.20.5
Reproduction Steps
credentials file like this
config file like this
The js code is very simple.When I try to execute GetCallerIdentityCommand using profile test_assume I get the error “Error fetching identity: InvalidClientTokenId: The security token included in the request is invalid”
package.json
I capture tcpdump request during cdk bootstrap command. The output is
I capture tcpdump request during cdk bootstrap command. The output is
As you can see, the ip address of STS service requested is in us-east-1 region.
Apparently, it could not work in the China region. Please fix this issue, Thanks!
Observed Behavior
Expected Behavior
SDK V3 Using source_profile works fine.
Possible Solution
No response
Additional Information/Context
No response
The text was updated successfully, but these errors were encountered: