I am configuring a bucket on a customer's ECS appliance and having an issue with CORS. I have uploaded the configuration via boto and confirmed it was set using the below anonymized code:
This is the same CORS configuration used on AWS without issue. Below is the output from the script confirming it has been set:
$ python script.py
Current CORS:
http://s3.amazonaws.com/doc/2006-03-01/
">
GET
PUT
POST
HEAD
https://[our_domain]
*
Accept-Ranges
Content-Range
Content-Encoding
Content-Length
The "Origin" is being properly set in the request and matches the CORS config. I am using the AWS SDK for Javascript aws-sdk-js/2.2.30. Below are the console errors in the browser:
[Error] Failed to load resource: the server responded with a status of 400 (Bad Request) ([s3_bucket], line 0)
[Error] Failed to load resource: Origin https://[our_domain] is not allowed by Access-Control-Allow-Origin. ([s3_bucket], line 0)
Unfortunately, issuing the OPTIONS request yourself is not an option; the JavaScript runtime always generates its own OPTIONS request for security reasons and you have no control over that. It appears the only solution here is to use namespace BaseURLs.
Note that for testing purposes, you can do all this through your /etc/hosts file, simply add:
namespace.ecs.yourdomain.com xxx.xxx.xxx.xxx
And configure the BaseURL ecs.yourdomain.com inside ECS. ECS does not need to verify this hostname with DNS; it simply uses it to parse hosts to differentiate between path-style requests and virtually-hosted requests (i.e. namespace.ecs.yourdomain.com/bucket vs. bucket.namespace.ecs.yourdomain.com).
Thanks for the quick response! I have not configured the BaseURL on the ECS appliance and instead I am addressing it using an IP address. I thought it might have something to do with the namespace and so I specifically designated the namespace in a request header as seen below:
Have you configured ECS to use a "with namespace" BaseURL? Since the OPTIONS preflight for CORS is an anonymous request, we must know the bucket name and the namespace to properly locate the bucket and parse its CORS config.
For example, you'll need to be making requests to:
And ECS will need to have an Object Base URL defined for ecs.company.com with the option "Use base URL with Namespace e.g. bucket.namespace.baseurl" selected.
Can you see if the runtime is generating an OPTIONS request before your GET? If it is, that request won't have any custom headers and thus, no namespace.
Firefox showed the OPTIONS request happening after the GET but being aborted (which is probably just a quirk of Firefox as the OPTIONS request would logically be occurring first). I switched to Chrome and see in the console that it is an OPTIONS request that is failing:
However, the error itself seems to do with the SSL cert? I will look into ignoring self-signed certs with the aws sdk as the customer hasn't replaced the default certs.
Chrome reports the following request headers on the OPTIONS request:
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36
I am not sure why it says "Provisional headers are shown". Perhaps these are the headers that would be sent dependent on the response from the OPTIONS request. I haven't been able to intercept the OPTIONS request itself with something like wireshark as traffic is encrypted. However it seems to line up with what you have said. As the OPTIONS request is generated by the client browser I guess I am unable to set a custom header. Maybe if I can manually issue an OPTIONS request with the custom header from within my code will this prevent the issue?? Otherwise it seems I will need to configure DNS and a BaseURL on the customer's ECS appliance which I was trying to avoid.
No, cyberduck and python work because they don't require CORS and always use authenticated requests. For authenticated requests, we take your username and look up the namespace that user is assigned to. The issue is that the OPTIONS request issued by JavaScript is anonymous and thus, we don't have your username to look up the namespace. At that point, the only way to get the namespace information is to grab it from the hostname on the URL.
JasonCwik
281 Posts
4857
0
Posted April 27th, 2016 11:00
Unfortunately, issuing the OPTIONS request yourself is not an option; the JavaScript runtime always generates its own OPTIONS request for security reasons and you have no control over that. It appears the only solution here is to use namespace BaseURLs.
Note that for testing purposes, you can do all this through your /etc/hosts file, simply add:
namespace.ecs.yourdomain.com xxx.xxx.xxx.xxx
And configure the BaseURL ecs.yourdomain.com inside ECS. ECS does not need to verify this hostname with DNS; it simply uses it to parse hosts to differentiate between path-style requests and virtually-hosted requests (i.e. namespace.ecs.yourdomain.com/bucket vs. bucket.namespace.ecs.yourdomain.com).