Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieve bucket's objects without knowing bucket's region with AWS S3 REST API

I'm trying to retrieve a bucket's objects with AWS S3 REST API (I'm not using the SDK) but unfortunately I'm facing the following problem : I don't know its region when I do the call to the API.

Here's what I do :

  • I build a request to "https:// [bucketname] .s3.amazonaws.com/"
  • I sign the request using a default region set to "us-west-1" (using the AWS4 signature process)
  • But imagine the bucket I'm trying to GET is set to the region "us-west-2", AWS is throwing me an error

Therefore here's my question:

Is there any way to get a list of the objects of a bucket without knowing its region ? Or is there any simple way to get the region of a bucket ?

INFO : I've read there are two style to call a bucket, "path-style" and "virtual-hosted-style", but whenever I send the request to "https://s3.amazonaws.com/ [bucketname]" instead it gives me a redirectpermanent error...

like image 511
Asticode Avatar asked Nov 23 '14 17:11

Asticode


1 Answers

AWS V4 authentication requires that you know the bucket's region so that you can correctly sign the request. Otherwise:

HTTP/1.1 400 Bad Request

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>AuthorizationHeaderMalformed</Code>
  <Message>The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'us-west-2'</Message>
  <Region>us-west-2</Region>
  <RequestId>xxxx</RequestId>
  <HostId>xxxx</HostId>
</Error>

V2 signatures were not region-specific, so there was previously a simple way you could learn the bucket's region using a V2 request:

http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketGETlocation.html

However, there apprears to be a catch-22 with V4, since you have to know the bucket's region before you can make the call to discover the bucket's region.

The first solution, then, is to capture the <Region> returned in the error response and use that region for signing future requests for the bucket. Obviously, you'd want to cache this information, since not doing so would lower performance and increase costs.

Alternately, there is a way to ask the US-Standard region (us-east-1) about the location of any bucket, in any region, using this URL format only:

https://s3.amazonaws.com/bucket-name?location

Sign this request with the us-east-1 region and you will get a response, wherever the bucket happens to be. Note that if the bucket is in us-east-1 (US-Standard) the LocationConstraint is returned empty.

<?xml version="1.0" encoding="UTF-8"?>
<LocationConstraint xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  us-west-2
</LocationConstraint>

You cannot use this URL construct for actually listing bucket objects in other regions, since https://s3.amazonaws.com/ always routes your request to US-Standard (us-east-1) but you can use it to discover the region of any bucket, since US-Standard has that information available.


Update/Additonal

At some point, S3 appears to have added a new response header, x-amx-bucket-region: which appears to be an undocumented addition to the REST API, and appears to be added to many S3 error responses, particularly 403 errors.

This seems like a useful mechanism for self-correction if you receive an error response.

Also, the information above about interrogating the US-Standard region about the location of any bucket anywhere is still accurate, and the same request should work if sent to any regional S3 REST endpoint, not just US-Standard, since all regions are aware of the location of all other buckets: e.g. https://s3-us-west-2.amazonaws.com/bucket-name?location would ask US-West-2 (Oregon), which also has the same information available, for any bucket globally. It might be desirable in some cases to interrogate your nearest region.

like image 158
Michael - sqlbot Avatar answered Oct 01 '22 18:10

Michael - sqlbot