CORS

Enforce client-site access controls with cross-origin resource sharing (CORS).

For example, you can configure requests that are made on your behalf. At the same time, you can block requests that are made by attacks, such as Javascript code or malware. Consider the following request scenarios that you can configure with CORS.

For more information, see the following resources.

If you import or export resources across workspaces, your policies might not apply. For more information, see Import and export policies.

Before you begin

This guide assumes that you use the same names for components like clusters, workspaces, and namespaces as in the getting started, and that your Kubernetes context is set to the cluster you store your Gloo config in (typically the management cluster). If you have different names, make sure to update the sample configuration files in this guide.

Follow the getting started instructions to:

  1. Set up Gloo Gateway in a single cluster.
  2. Deploy sample apps.
  3. Configure an HTTP listener on your gateway and set up basic routing for the sample apps.

Configure CORS policies

You can apply a CORS policy at the route level. For more information, see Applying policies.

Review the following sample configuration files.

apiVersion: security.policy.gloo.solo.io/v2
kind: CORSPolicy
metadata:
  name: simple-cors
  namespace: bookinfo
spec:
  applyToRoutes:
  - route:
      labels:
        route: ratings
  config:
    maxAge: 1m
    allowCredentials: true
    allowHeaders:
    - foo
    - bar
    allowMethods:
    - GET
    allowOrigins:
    - exact: http://istio.io  

Review the following table to understand this configuration. For more information, see the API docs.

Setting Description
spec.applyToRoutes Use labels to configure which routes to apply the policy to. This example label matches the app and route from the example route table that you apply separately. If omitted and you do not have another selector such as applyToDestinations, the policy applies to all routes in the workspace.
maxAge Optionally specify how long the results of a preflight request are cached. This value translates to the Access-Control-Max-Age header. In this example, the value is 1m.
allowCredential Optionally let the caller send the actual request with credentials, not just the preflight request. This value translates to the Access-Control-Allow-Credentials header. In this example, the value is true.
allowHeaders Specify a list of HTTP headers that can be used in requests. This value is serialized to the Access-Control-Allow-Headers header. In this example, the foo and bar headers can be used in the request.
allowMethods Specify a list of HTTP methods that can be used in requests. This value is serialized to the Access-Control-Allow-Methods header. In this example, only the GET method can be used to access the resource.
allowOrigins Enter a string pattern to use to decide if an origin is allowed. An origin is allowed if any of the string patterns match the origin in the header. You can set up exact, prefix, suffix, or regex matches. By default, matching is case-sensitive for exact, prefix, and suffix matching, unless you include ignoreCase: true. This value is serialized to the Access-Control-Allow-Origin header. In this example, the origin header must match exactly http://istio.io.

Verify CORS policies

  1. Apply the example CORS policy in the cluster with the Bookinfo workspace in your example setup.

    kubectl apply -f - << EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: CORSPolicy
    metadata:
      name: simple-cors
      namespace: bookinfo
    spec:
      applyToRoutes:
      - route:
          labels:
            route: ratings
      config:
        maxAge: 1m
        allowCredentials: true
        allowHeaders:
        - foo
        - bar
        allowMethods:
        - GET
        allowOrigins:
        - exact: http://istio.io
    EOF
    
  2. Send a request to the ratings app through the ingress gateway that the route table is attached to.

    curl -vik -H "Origin: http://istio.io" -H "Access-Control-Request-Method: GET" -X OPTIONS --resolve www.example.com:80:${INGRESS_GW_IP} https://www.example.com:80/ratings/1 
    
    curl -vik -H "Origin: http://istio.io" -H "Access-Control-Request-Method: GET" -X OPTIONS --resolve www.example.com:443:${INGRESS_GW_IP} https://www.example.com:443/ratings/1 
    

  3. Review the responses to verify your CORS policy. Depending on how you set up the policy, you might still expect to get a 200 response, but certain access control headers are missing, which let you know that the CORS is rejected.

    • If CORS is enabled, you see an Access-Control-Allow-Origin header in the response.
    • If CORS is disabled, you do not see any Access-Control-* headers in the response.
    • If the preflight request is successful, the response includes the Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers. If the request was not successful, these headers are missing.

    Example response:

    HTTP/1.1 200 OK 
    access-control-allow-origin: http://istio.io 
    access-control-allow-credentials: true 
    access-control-allow-methods: GET 
    access-control-allow-headers: foo,bar 
    access-control-max-age: 60 
    date: Tue, 02 Feb 2022 22:29:04 GMT 
    server: istio-envoy 
    content-length: 0
    
  4. Optional: Clean up the resources that you created.

    kubectl -n bookinfo delete corspolicy simple-cors