About CORS

Cross-Origin Resource Sharing (CORS) is a security feature that is implemented by web browsers and that controls how web pages in one domain can request and interact with resources that are hosted on a different domain. By default, web browsers only allow requests to resources that are hosted on the same domain as the web page that served the original request. Access to web pages or resources that are hosted on a different domain is restricted to prevent potential security vulnerabilities, such as cross-site request forgery (CRSF).

When CORS is enabled in a web browser and a request for a different domain comes in, the web browser checks whether this request is allowed or not. To do that, it typically sends a preflight request (HTTP OPTIONS method) to the server or service that serves the requested resource. The service returns the methods that are permitted to send the actual cross-origin request, such as GET, POST, etc. If the request to the different domain is allowed, the response includes CORS-specific headers that instruct the web browser how to make the cross-origin request. For example, the CORS headers typically include the origin that is allowed to access the resource, and the credentials or headers that must be included in the cross-origin request.

Note that the preflight request is optional. Web browsers can also be configured to send the cross-origin directly. However, access to the request resource is granted only if CORS headers were returned in the response. If no headers are returned during the preflight request, the web browser denies access to the resource in the other domain.

CORS policies are typically implemented to limit access to server resources for JavaScripts that are embedded in a web page, such as:

  • A JavaScript on a web page at example.com tries to access a different domain, such as api.com.
  • A JavaScript on a web page at example.com tries to access a different subdomain, such as api.example.com.
  • A JavaScript on a web page at example.com tries to access a different port, such as example.com:3001.
  • A JavaScript on a web page at https://example.com tries to access the resources by using a different protocol, such as http://example.com.

For more information, see the CORS API.

Before you begin

  1. Follow the Get started guide to install Gloo Gateway, set up a gateway resource, and deploy the httpbin sample app.

  2. Get the external address of the gateway and save it in an environment variable.

Set up CORS policies

  1. Deploy the Petstore app.

      kubectl apply -f https://raw.githubusercontent.com/solo-io/gloo/v1.16.x/example/petstore/petstore.yaml
      

    Example output:

      deployment.apps/petstore created
    service/petstore created
      
  2. Verify that the Petstore app is up and running.

      kubectl get pods   
      

    Example output:

      NAME                        READY   STATUS    RESTARTS   AGE
    petstore-66cddd5bb4-x7vdd   1/1     Running   0          26s
      
  3. Create a RouteOption resource to define your CORS rules. The following example allows requests from the example.com/ and *.example.com origins.

      kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: RouteOption
    metadata:
      name: cors
      namespace: default
    spec:
      options:
        cors:
          allowCredentials: true
          allowHeaders:
          - origin
          allowMethods:
          - GET
          - POST
          - OPTIONS
          allowOrigin:
          - https://example.com/
          allowOriginRegex:
          - https://\[a-zA-Z0-9\]\*.example
          exposeHeaders:
          - origin
          maxAge: 1d
    EOF
      
  4. Create an HTTPRoute resource for the Petstore app that applies the RouteOption resources that you created.

      kubectl apply -f- <<EOF
    apiVersion: gateway.networking.k8s.io/v1beta1
    kind: HTTPRoute
    metadata:
      name: petstore-cors
      namespace: default
    spec:
      parentRefs:
      - name: http
        namespace: gloo-system
      hostnames:
        - cors.example
      rules:
        - filters:
            - type: ExtensionRef
              extensionRef:
                group: gateway.solo.io
                kind: RouteOption
                name: cors
          backendRefs:
            - name: petstore
              port: 8080
    EOF
      
  5. Send a request to the Petstore app on the cors.example domain and use https://example.com/ as the origin. Verify that your request succeeds and that you get back CORS headers, such as access-control-allow-origin, access-control-allow-credentials, and access-control-expose-headers.

    Example output:

       * Mark bundle as not supporting multiuse
       < HTTP/1.1 200 OK
       < content-type: text/xml
       < date: Mon, 03 Jun 2024 17:05:31 GMT
       < content-length: 86
       < x-envoy-upstream-service-time: 7
       < access-control-allow-origin: https://example.com/
       < access-control-allow-credentials: true
       < access-control-expose-headers: origin
       < server: envoy
       < 
       [{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
       

  6. Send another request to the Petstore app. This time, you use notallowed.com as your origin. Although the request succeeds, you do not get back any CORS headers, because notallowed.com is not configured as a supported origin.

    Example output:

      * Mark bundle as not supporting multiuse
    < HTTP/1.1 200 OK
    < content-type: text/xml
    < date: Mon, 03 Jun 2024 17:20:10 GMT
    < content-length: 86
    < x-envoy-upstream-service-time: 3
    < server: envoy
    < 
    [{"id":1,"name":"Dog","status":"available"},{"id":2,"name":"Cat","status":"pending"}]
      

Cleanup

Remove the resources that you created in this guide.

  kubectl delete -f https://raw.githubusercontent.com/solo-io/gloo/v1.16.x/example/petstore/petstore.yaml
kubectl delete routeoption cors -n default
kubectl delete httproute petstore-cors -n default