Skip to content
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

Implement bucket-level CORS configuration settings with S3 APIs PutBucketCors, etc #20150

Closed
wants to merge 1 commit into from

Conversation

marktheunissen
Copy link
Contributor

@marktheunissen marktheunissen commented Jul 25, 2024

Description

This PR adds support for the S3 APIs PutBucketCors, DeleteBucketCors, GetBucketCors and allows the API to use these bucket-specific CORS configurations while falling back to global config where no bucket-specific configuration is given.

Motivation and Context

MinIO has always supported "Global CORS" settings, but has not supported the S3 Bucket Cors APIS:

The global configuration is done with cors_allow_origin or env var MINIO_API_CORS_ALLOW_ORIGIN, and defaults to origins=*. This is the only CORS configuration that is currently supported.

S3's API, however, allows a user to put a CORS configuration for a given bucket with a rich configuration language, up to 100 rules may be applied. Docs:

For example:

<CORSConfiguration>
 <CORSRule>
   <AllowedOrigin>http://www.example1.com</AllowedOrigin>

   <AllowedMethod>PUT</AllowedMethod>
   <AllowedMethod>POST</AllowedMethod>
   <AllowedMethod>DELETE</AllowedMethod>

   <AllowedHeader>*</AllowedHeader>
 </CORSRule>
</CORSConfiguration>

The goal of this PR is to match the S3 rules engine as closely as possible, with a few small exceptions where S3 does not follow the fetch() spec. CORS is made for browsers and thus it's the fetch() spec that defines how it should behave. These exceptions are documented in the functional tests in minio-go. Fetch spec is here:

Another objective is to allow the global CORS settings to continue functioning, without any action required from users who do not apply bucket CORS.

Implementation

MinIO currently uses https://github.com/rs/cors to handle Global CORS.

The intention in this PR is to provide an adapter which can transform a matched S3 Bucket CORS rule, to an rs/cors configuration. This is slightly less efficient than implementing a seperate CORS engine just for the bucket configurations, however, it simplifies things, as there is only one actual cors engine, rs/cors, not two.

The old implementation applies CORS through a handler wrapper, rather than a mux.Middleware. This PR needs to change that, as we now need the bucket name in the CORS handling logic, and the mux router does not provide the bucket var name, unless a route matches.

This PR introduces corsHandler as a real Middleware (added to globalMiddlewares). corsHandler is able to check if a CORS config is applied to a bucket, and if it is, use it instead of the global config.

The disadvantage of using mux.Middleware, is that it's slightly less efficient, as mux sets up the Middleware chain every time there is a route match. This is in contrast to the current global CORS handler wrapper, which is only called once when the router is initialized.

One unavoidable change is that currently preflight is evaluated before any auth, so for example, doing curl -v -XOPTIONS https://play.min.io/minio/kms/v1/status -H "Origin: http://foobar.com/" gives you 200 OK. After this PR, auth will be evaluated first, so it will be access denied. I believe the new code in this PR is a more correct implementation.

How to test this PR?

  • Automated tests are provided
  • The functional tests in the minio-go repo contain 30 request/response tests that verify CORS correctness.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Optimization (provides speedup with no functional changes)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • Fixes a regression (If yes, please add commit-id or PR # here)
  • Unit tests added/updated
  • Internal documentation updated
  • Create a documentation update request here

All related PRs:

go.mod Outdated Show resolved Hide resolved
@marktheunissen marktheunissen force-pushed the bucketcors branch 4 times, most recently from 6054f47 to 8f1cbd6 Compare July 26, 2024 03:40
Copy link
Contributor

@klauspost klauspost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just some minor stuff.

cmd/admin-bucket-handlers.go Outdated Show resolved Hide resolved
cmd/api-errors.go Show resolved Hide resolved
cmd/api-errors.go Show resolved Hide resolved
cmd/api-errors.go Show resolved Hide resolved
cmd/api-errors.go Show resolved Hide resolved
.typos.toml Outdated Show resolved Hide resolved
cmd/routers.go Show resolved Hide resolved
cmd/site-replication.go Outdated Show resolved Hide resolved
@marktheunissen marktheunissen force-pushed the bucketcors branch 4 times, most recently from 1086feb to f49a8e5 Compare July 31, 2024 06:06
go.mod Outdated Show resolved Hide resolved
cmd/api-errors.go Show resolved Hide resolved
cmd/api-router-cors.go Show resolved Hide resolved
cmd/api-router-cors.go Show resolved Hide resolved
cmd/routers.go Show resolved Hide resolved
docs/cors/README.md Outdated Show resolved Hide resolved
@harshavardhana
Copy link
Member

One unavoidable change is that currently preflight is evaluated before any auth, so for example, doing curl -v -XOPTIONS https://play.min.io/minio/kms/v1/status -H "Origin: http://foobar.com/" gives you 200 OK. After this PR, auth will be evaluated first, so it will be access denied. I believe the new code in this PR is a more correct implementation.

This is correct implementation.

@marktheunissen
Copy link
Contributor Author

@harshavardhana I've pushed some commits for review

Copy link
Member

@harshavardhana harshavardhana left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM please update the dependency.

cmd/api-router-cors.go Show resolved Hide resolved
@harshavardhana
Copy link
Member

Lets move this PR to mineos only @marktheunissen https://github.com/miniohq/mineos we are not making this change for public consumption.

@marktheunissen
Copy link
Contributor Author

@harshavardhana How will we handle the divergence in repos like pkg and minio-go? For example, there are now CORS tests in minio-go that require this PR: https://github.com/minio/minio-go/blob/master/functional_tests.go#L13560

@harshavardhana
Copy link
Member

@harshavardhana How will we handle the divergence in repos like pkg and minio-go? For example, there are now CORS tests in minio-go that require this PR: https://github.com/minio/minio-go/blob/master/functional_tests.go#L13560

They are clients @marktheunissen and libraries the main functionality stays in EOS.

@harshavardhana
Copy link
Member

@harshavardhana How will we handle the divergence in repos like pkg and minio-go? For example, there are now CORS tests in minio-go that require this PR: https://github.com/minio/minio-go/blob/master/functional_tests.go#L13560

They must be run against EOS only.

cmd/api-errors.go Outdated Show resolved Hide resolved
cmd/api-errors.go Show resolved Hide resolved
@marktheunissen marktheunissen force-pushed the bucketcors branch 2 times, most recently from bdc3ebf to 12365ec Compare August 6, 2024 03:30
…cketCors, GetBucketCors, etc

Singleflight on getconfig. FIXMEs for spelling. Fewer allocations for middleware

Move docs, fix typos complaining

deps fix
@marktheunissen
Copy link
Contributor Author

Moving to MinEOS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants