aws-sdk-js-v3 icon indicating copy to clipboard operation
aws-sdk-js-v3 copied to clipboard

S3Client doesn't honor useGlobalEndpoint setting

Open papsicle opened this issue 2 years ago • 3 comments

Describe the bug

Trying to do an S3Copy using the JS sdk over different regions and without knowing the target region doesn't work.

There's a setting called useGlobalEndpoint which seems to allow using the global endpoint to let S3 resolve the region on its own, but that's not working when turned "on".

Expected Behavior

The sdk copies from my source bucket to my destination bucket, whatever regions they are in.

Current Behavior

We get either of 2 issues:

  1. When the AWS_REGION env variable is set, this error is returned
causeOfFailure={name=AuthorizationHeaderMalformed, $fault=client, $metadata={httpStatusCode=400, requestId=0273JQS0CCE292Q5, extendedRequestId=1d7Sh5Mr5hriesnI46CCtEdNGVly3D10CoIn6SEDRzZE+rVG1Eup+rLEjXw13AOuzlVQe/+aFV4=, attempts=1, totalRetryDelay=0}, Code=AuthorizationHeaderMalformed, Region=eu-west-2, RequestId=0273JQS0CCE292Q5, HostId=1d7Sh5Mr5hriesnI46CCtEdNGVly3D10CoIn6SEDRzZE+rVG1Eup+rLEjXw13AOuzlVQe/+aFV4=, message=The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'eu-west-2', stack=AuthorizationHeaderMalformed: The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'eu-west-2'
    at throwDefaultError (/var/task/node_modules/@aws-sdk/smithy-client/dist-cjs/default-error-handler.js:8:22)
    at deserializeAws_restXmlGetBucketLocationCommandError (/var/task/node_modules/@aws-sdk/client-s3/dist-cjs/protocols/Aws_restXml.js:3917:43)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async /var/task/node_modules/@aws-sdk/middleware-serde/dist-cjs/deserializerMiddleware.js:7:24
    at async /var/task/node_modules/@aws-sdk/middleware-signing/dist-cjs/middleware.js:14:20
    at async /var/task/node_modules/@aws-sdk/middleware-retry/dist-cjs/retryMiddleware.js:27:46
    at async /var/task/node_modules/@aws-sdk/middleware-logger/dist-cjs/loggerMiddleware.js:7:26
    at async Runtime.lambda [as handler] (/var/task/app.js:24:26)}

This confirms that the sdk is "smart enough" to find the correct target region, but not to use it. 2. When the AWS_REGION env variable is not set, this error is returned

causeOfFailure={name=Error, message=Region is missing, stack=Error: Region is missing
    at default (/var/task/node_modules/@aws-sdk/config-resolver/dist-cjs/regionConfig/config.js:10:15)
    at /var/task/node_modules/@aws-sdk/node-config-provider/dist-cjs/fromStatic.js:6:83
    at /var/task/node_modules/@aws-sdk/property-provider/dist-cjs/chain.js:11:28
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async coalesceProvider (/var/task/node_modules/@aws-sdk/property-provider/dist-cjs/memoize.js:14:24)
    at async /var/task/node_modules/@aws-sdk/property-provider/dist-cjs/memoize.js:26:28
    at async useFipsEndpoint (/var/task/node_modules/@aws-sdk/config-resolver/dist-cjs/regionConfig/resolveRegionConfig.js:21:74)
    at async resolveParams (/var/task/node_modules/@aws-sdk/middleware-endpoint/dist-cjs/adaptors/getEndpointFromInstructions.js:29:40)
    at async getEndpointFromInstructions (/var/task/node_modules/@aws-sdk/middleware-endpoint/dist-cjs/adaptors/getEndpointFromInstructions.js:7:28)
    at async /var/task/node_modules/@aws-sdk/middleware-endpoint/dist-cjs/endpointMiddleware.js:8:26}

Reproduction Steps

stsClient = new STSClient({region: REGION})
const command = new AssumeRoleCommand({
        RoleSessionName: "cloud-transfer-lambda",
        RoleArn: process.env[BUCKET_DELIVERY_ROLE]
    })
const credentials = stsClient.send(command)
    .then((assumeRoleResult) => {
        const credentials = assumeRoleResult.Credentials;
        if (!credentials || !credentials.AccessKeyId || !credentials.SecretAccessKey) {
            throw new Error(`Could not assume role ${process.env[BUCKET_DELIVERY_ROLE]}`);
        }
        return new Credentials(credentials.AccessKeyId, credentials.SecretAccessKey, credentials.SessionToken);
    })
const s3Client = new S3Client({credentials, useGlobalEndpoint: true, maxAttempts: 2});

const copyCommandInput: CopyObjectCommandInput = {
        ACL: ObjectCannedACL.bucket_owner_full_control,
        CopySource: "bucket-in-region-A/somepath/file.txt",
        Bucket: "bucket-in-region-B",
        Key: "prefix/somepath/file.txt",
    }

// Scenario B
// delete process.env["AWS_REGION"];
const result: CopyObjectCommandOutput = await s3Client.send(buildTransferCommand(cloudTransfer));

Possible Solution

No response

Additional Information/Context

No response

SDK version used

3.267.0

Environment details (OS name and version, etc.)

Node 18.14.0 in an AWS Lambda

papsicle avatar Mar 21 '23 15:03 papsicle

I will transfer this issue to the right repo, which is this one.

Thanks!

yenfryherrerafeliz avatar Mar 22 '23 22:03 yenfryherrerafeliz

Hi @papsicle, thanks for opening this issue. I can confirm that this is a bug. I have confirmed with the team that even though the parameter is exposed, the logic for handling this option it is not implemented yet. The reason for this is that must of our code is auto generated from a service model, which in this case introduced this new option. I do not have a timeline for when our team will work on getting this fixed, but I will add a needs-review label so it gets into our bag log as a bug to fix.

Thanks!

yenfryherrerafeliz avatar Mar 23 '23 19:03 yenfryherrerafeliz

This is likely impacting all clients, not just S3Client. STSClient doesn't seem to be respecting the useGlobalEndpoints prop for my case

peterwoodworth avatar Jun 21 '23 23:06 peterwoodworth

useGlobalEndpoint does not mean the SDK will make cross region requests. An instance of an SDK Client is tied to one region unless the service itself is regionless.

useGlobalEndpoint=true simply means that for endpoint routing in us-east-1, the legacy "global" endpoint for a service will be used instead of the us-east-1 regional endpoint.

Example:

const config = {
  region: "us-east-1",
  useGlobalEndpoint: false,
};
// https://mybucket.s3.us-east-1.amazonaws.com/
// uses regional us-east-1 endpoint

const config = {
  region: "us-east-1",
  useGlobalEndpoint: true,
};
// https://mybucket.s3.amazonaws.com/
// uses legacy global endpoint (us-east-1)

const config = {
  region: "us-west-2",
  useGlobalEndpoint: false,
};
// https://mybucket.s3.us-west-2.amazonaws.com/
// has no effect on regions that are not us-east-1

To copy an object between regions


const destinationRegion = "us-west-2";

// create the SDK client for the destination region.
const s3 = new S3({ region: destinationRegion });

await s3.copyObject({
  Bucket: "bucket in destination region",
  Key: "key in destination region",
  CopySource: "bucket in source region/key in source region",
});

kuhe avatar Oct 09 '25 15:10 kuhe

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread.

github-actions[bot] avatar Oct 28 '25 00:10 github-actions[bot]