All Products
Search
Document Center

Alibaba Cloud Service Mesh:Implement CORS in ASM

Last Updated:Mar 10, 2026

When a frontend application sends requests to a backend service on a different origin (domain, protocol, or port), the browser blocks the response unless the server explicitly allows cross-origin access. Cross-origin resource sharing (CORS) is the standard mechanism that lets servers declare which origins can access their resources.

In Service Mesh (ASM), you configure CORS by adding a corsPolicy field to a VirtualService. The ASM sidecar proxy handles CORS headers automatically -- your backend application code does not need to manage CORS itself.

How CORS works

A browser applies CORS rules whenever a script makes a request to an origin different from the page's own origin. The flow depends on whether the request is classified as simple or preflight.

Simple requests go directly to the server with an Origin header. The server responds with Access-Control-Allow-Origin and Access-Control-Allow-Methods headers to indicate whether access is permitted:

# Successful cross-origin request
GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://app.example.com

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com

# Denied cross-origin request (browser blocks the response)
GET /api/data HTTP/1.1
Host: api.example.com
Origin: https://app.example.com

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://other.example.com

A request qualifies as simple when it meets all three conditions:

  • Uses GET, HEAD, or POST

  • Sets Content-Type to text/plain, application/x-www-form-urlencoded, or multipart/form-data

  • Uses only CORS-safelisted headers: Accept, Accept-Language, Content-Language, and Content-Type (restricted to the values above)

Preflight requests apply to everything else. The browser first sends an OPTIONS request to check whether the actual request is allowed:

# Preflight request
OPTIONS /api/data HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header

# Preflight response (allowed)
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: GET, PUT, POST
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 86400

If the preflight response permits the request, the browser sends the actual request. Otherwise, the browser blocks it.

Configure a CORS policy in a VirtualService

Add a corsPolicy block under the http route in your VirtualService. The sidecar proxy reads this configuration and adds the appropriate Access-Control-* response headers automatically.

Click to view a sample VirtualService

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: ratings-route
spec:
  hosts:
  - ratings.prod.svc.cluster.local
  http:
  - route:
    - destination:
        host: ratings.prod.svc.cluster.local
        subset: v1
    corsPolicy:
      allowOrigins:
      - exact: https://example.com
      - regex: *     # Regular expressions are supported to specify the addresses of the origins.
      allowMethods:
      - POST
      - GET
      allowCredentials: false
      allowHeaders:
      - X-Foo-Bar
      maxAge: "24h"

corsPolicy parameter reference

ParameterTypeMaps to HTTP headerDescription
allowOriginsStringMatch[]Access-Control-Allow-OriginOrigins allowed to access the service. Supports exact, prefix, and regex match types. Set to wildcard (*) to allow all origins for requests without credentials.
allowMethodsstring[]Access-Control-Allow-MethodsHTTP methods allowed for cross-origin requests.
allowHeadersstring[]Access-Control-Allow-HeadersHTTP headers that can be used in cross-origin requests.
exposeHeadersstring[]Access-Control-Expose-HeadersResponse headers that browsers are allowed to access.
maxAgeDurationAccess-Control-Max-AgeHow long browsers can cache the preflight response.
allowCredentialsboolAccess-Control-Allow-CredentialsWhether cross-origin requests can include credentials (cookies, HTTP authentication).

Tutorial: Enable CORS for a cross-origin demo

This walkthrough deploys a frontend and backend application on separate ingress gateways, demonstrates the CORS error, then resolves it by adding a corsPolicy to the backend's VirtualService.

Before you begin

Step 1: Deploy the applications

Deploy the backend (details service)

  1. Connect to the cluster with kubectl. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.

  2. Save the following YAML as details.yaml:

    details.yaml

       apiVersion: v1
       kind: Service
       metadata:
         name: details
         labels:
           app: details
           service: details
       spec:
         ports:
         - port: 9080
           name: http
         selector:
           app: details
       ---
       apiVersion: v1
       kind: ServiceAccount
       metadata:
         name: bookinfo-details
         labels:
           account: details
       ---
       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: details-v1
         labels:
           app: details
           version: v1
       spec:
         replicas: 1
         selector:
           matchLabels:
             app: details
             version: v1
         template:
           metadata:
             labels:
               app: details
               version: v1
           spec:
             serviceAccountName: bookinfo-details
             containers:
             - name: details
               image: docker.io/istio/examples-bookinfo-details-v1:1.16.4
               imagePullPolicy: IfNotPresent
               ports:
               - containerPort: 9080
               securityContext:
                 runAsUser: 1000
  3. Deploy the details application in the default namespace:

       kubectl apply -f details.yaml -n default

Deploy the frontend (istio-cors-demo)

  1. Save the following YAML as istio-cors-demo.yaml:

    istio-cors-demo.yaml

       apiVersion: v1
       kind: ServiceAccount
       metadata:
         name: istio-cors-demo
       ---
       apiVersion: v1
       kind: Service
       metadata:
         name: istio-cors-demo
         labels:
           app: istio-cors-demo
           service: istio-cors-demo
       spec:
         ports:
           - name: http
             port: 8000
             targetPort: 80
         selector:
           app: istio-cors-demo
       ---
       apiVersion: apps/v1
       kind: Deployment
       metadata:
         name: istio-cors-demo
       spec:
         replicas: 1
         selector:
           matchLabels:
             app: istio-cors-demo
             version: v1
         template:
           metadata:
             labels:
               app: istio-cors-demo
               version: v1
           spec:
             serviceAccountName: istio-cors-demo
             containers:
               - image: registry.cn-hangzhou.aliyuncs.com/build-test/istio-cors-demo:v1.0-g8e215f6-aliyun
                 imagePullPolicy: IfNotPresent
                 name: istio-cors-demo
                 ports:
                   - containerPort: 80
  2. Deploy the istio-cors-demo application in the foo namespace:

       kubectl apply -f istio-cors-demo.yaml -n foo

Step 2: Create two ingress gateways

Create two separate ingress gateways so the frontend and backend are exposed on different IP addresses, simulating a cross-origin scenario.

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose ASM Gateways > Ingress Gateway.

  3. On the Ingress Gateway page, click Create.

  4. On the Create page, set Name to ingressgateway. Select a cluster from the Cluster drop-down list. Select Internet Access for CLB Instance Type. Select a Classic Load Balancer (CLB) instance type below Create a CLB Instance. Keep the default values for other parameters and click Create.

  5. Repeat steps 3 and 4 to create a second ingress gateway named ingressgateway2.

Step 3: Set up routing rules

Route traffic to the backend

  1. Create an Istio gateway to associate the details service with ingressgateway.

    1. In the left-side navigation pane of the ASM instance, choose ASM Gateways > Gateway.

    2. On the Gateway page, click Create from YAML.

    3. Select default from the Namespace drop-down list, paste the following YAML, and click Create:

      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: bookinfo-gateway
        namespace: default
      spec:
        selector:
          istio: ingressgateway
        servers:
          - hosts:
              - '*'
            port:
              name: http
              number: 80
              protocol: HTTP
  2. Create a VirtualService to route /details requests to the details service.

    1. In the left-side navigation pane, choose Traffic Management Center > VirtualService. Click Create from YAML.

    2. Select default from the Namespace drop-down list, paste the following YAML, and click Create:

      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: bookinfo
        namespace: default
      spec:
        gateways:
          - bookinfo-gateway
        hosts:
          - '*'
        http:
          - match:
              - uri:
                  prefix: /details
            route:
              - destination:
                  host: details
                  port:
                    number: 9080
  3. Verify the backend is accessible.

    1. Get the IP address of ingressgateway. For more information, see Create an ingress gateway.

    2. Open http://<ingressgateway-ip>/details/2 in a browser. A JSON response from the details service confirms the backend is working. Backend response from the details service

Route traffic to the frontend

  1. Create an Istio gateway to associate the istio-cors-demo application with ingressgateway2.

    1. In the left-side navigation pane, choose ASM Gateways > Gateway. Click Create from YAML.

    2. Select foo from the Namespace drop-down list, paste the following YAML, and click Create:

      apiVersion: networking.istio.io/v1beta1
      kind: Gateway
      metadata:
        name: istio-cors-demo-gateway
        namespace: foo
      spec:
        selector:
          istio: ingressgateway2
        servers:
          - hosts:
              - '*'
            port:
              name: http
              number: 80
              protocol: HTTP
  2. Create a VirtualService for the frontend.

    1. In the left-side navigation pane, choose Traffic Management Center > VirtualService. Click Create from YAML.

    2. Select foo from the Namespace drop-down list, paste the following YAML, and click Create:

      apiVersion: networking.istio.io/v1beta1
      kind: VirtualService
      metadata:
        name: istio-cors-demo
        namespace: foo
      spec:
        gateways:
          - istio-cors-demo-gateway
        hosts:
          - '*'
        http:
          - route:
              - destination:
                  host: istio-cors-demo
                  port:
                    number: 8000

Confirm the cross-origin error

  1. Get the IP address of ingressgateway2. For more information, see Create an ingress gateway.

  2. Open http://<ingressgateway2-ip> in Google Chrome.

  3. In the URL field on the page, enter http://<ingressgateway-ip>/details/2 and click Send.

    Frontend URL field and Send button

  4. Open Chrome DevTools (press F12 or click the Settings icon > More tools > Developer tools). The console shows a CORS error because the backend does not include an Access-Control-Allow-Origin header for the frontend's origin.

    CORS error in Chrome DevTools

Step 4: Add a CORS policy to the backend VirtualService

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. Click the name of the ASM instance. In the left-side navigation pane, choose Traffic Management Center > VirtualService.

  3. Find the bookinfo VirtualService and click YAML in the Actions column.

  4. In the Edit dialog box, add the following corsPolicy block to the http field, then click OK: Replace the following placeholder with the actual value:

    PlaceholderDescriptionExample
    <ingressgateway2-ip>IP address of the ingressgateway2 gateway47.95.XX.XX
       corsPolicy:
         allowCredentials: false
         allowMethods:
           - POST
           - GET
         allowOrigins:
           - prefix: 'http://<ingressgateway2-ip>'
         maxAge: 24h

    CORS policy added to the VirtualService YAML

Step 5: Verify that CORS works

  1. Open http://<ingressgateway2-ip> in Google Chrome.

  2. In the URL field, enter http://<ingressgateway-ip>/details/2 and click Send.

  3. The page displays the JSON response from the details service, confirming that the cross-origin request succeeded.

    Successful cross-origin response