Conversation
There was a problem hiding this comment.
Cool! Nice approach that can further streamline the CORS UX. 🎉
Was able to replicate with the following steps:
- create a CloudFront distribution, as per our docs:
$ awslocal s3 mb s3://test
$ echo 'Hello World' > /tmp/hello.txt
$ awslocal s3 cp /tmp/hello.txt s3://test/hello.txt --acl public-read
$ domain=$(awslocal cloudfront create-distribution --origin-domain-name test.s3.amazonaws.com | jq -r '.Distribution.DomainName')
$ echo $domain
ce6554a5.cloudfront.localhost.localstack.cloud
- create a simple
index.htmlfile that connects to the enpoint:
<html>
<script>
fetch('http://ce6554a5.cloudfront.localhost.localstack.cloud:4566/hello.txt');
</script>
</html>
- upload the file to a bucket and expose it as an S3 website:
awslocal s3 cp /tmp/index.html s3://test/index.html --content-type text/html
awslocal s3api put-bucket-website --bucket test --website-configuration 'ErrorDocument={Key=index.html},IndexDocument={Suffix=index.html}'
- open http://test.s3-website.localhost.localstack.cloud:4566/index.html in the browser, observe the Network console (request to
http://ce6554a5.cloudfront.localhost.localstack.cloud:4566/hello.txt)
Result:
- returns a
403error on current master 🟥 - returns
200and expected file content with the changes in this PR ✅
To me, this achieves a decent balance between improving convenience (works out of the box without extra configs), while not sacrificing security (requests still only allowed from *.localhost.localstack.cloud pages in the browser). 👍 As usual with CORS or security-critical configurations, would be good to get a second pair of eyes on it, though.. 👀 /cc @dfangl @alexrashed @thrau
| _ports = set([config.EDGE_PORT] + ([config.EDGE_PORT_HTTP] if config.EDGE_PORT_HTTP else [])) | ||
| for protocol in {"http", "https"}: | ||
| for port in _ports: | ||
| for port in _get_allowed_cors_ports(): |
There was a problem hiding this comment.
nit: we could also use _ALLOWED_INTERNAL_PORTS here, for consistency. (although the performance impact is probably negligible).
There was a problem hiding this comment.
That's what I thought and did at first, but then it would be generated only once, and in your other tests where you monkey patch ALLOWED_CORS_ORIGINS, you'd have to monkey patch _ALLOWED_INTERNAL_PORTS before. I thought it'd make your tests a bit more complicated.
localstack/tests/unit/test_cors.py
Lines 18 to 21 in be7178d
|
Thanks @whummer for creating a reproducible sample! Just a note:
The requests are only allowed from |
a693385 to
c87decd
Compare
c87decd to
f61cd88
Compare
thrau
left a comment
There was a problem hiding this comment.
I think this is fantastic 🎉 I don't see a big issue right now 👍
localstack/aws/handlers/cors.py
Outdated
| return True | ||
|
|
||
| @staticmethod | ||
| @log_duration(min_ms=0) |
localstack/aws/handlers/cors.py
Outdated
| from ...constants import LOCALHOST, LOCALHOST_HOSTNAME, PATH_USER_REQUEST | ||
| from ...utils.bootstrap import log_duration |
There was a problem hiding this comment.
nit: ideally we don't use relative imports of modules that are outside the scope of the component we are building. basically: relative imports are used when things belong together in a component, absolute imports are used when importing code that represents a dependency to another component
There was a problem hiding this comment.
Right, I'm not sure why there are dynamic imports here, I can change them 👍
This is a follow up from #7554, from an idea proposed by @whummer (in this comment) , with dynamic handling of CORS origin for web resource served by LocalStack.
This is not mergeable as is, as it still has some logging regarding performance, but I'd like to have some comments / opinions.
Scenario:
LocalStack is serving a resource meant to be accessed from the browser (CloudFront or S3 website).
But this resource needs to access LocalStack resources as well. Right now, the only way is to set the environment variables of LocalStack to allow the Origin (let’s say,
http://<bucket>.s3-website.localhost.localstack.cloud:4566).Fix
This PR adds a dynamic check of the origin, to validate if it follows some regex matching 2 service domains known for serving content accessible from a user browser (thus enforcing CORS). We can then add a regex for every resource subdomain in that situation.
The performance right now is around 4µs on my local machine when a request would be either rejected or matching
s3-websiteorcloudfront. The performance would not be affected for most requests, as we either don't match CORS because of noOriginheader, or the request is normally allowed.\cc @whummer @dfangl @alexrashed