When a client from one domain accesses a service in a different domain or a service that resides in the same domain but uses a different port, the client initiates a cross-origin request. If the service does not allow cross-origin resource access, the client cannot access the service. In this case, you can implement cross-origin resource sharing (CORS) to allow web application servers to support cross-origin resource access. This topic describes how to configure a CORS policy in a virtual service of Service Mesh (ASM) to implement CORS.
CORS overview
For security reasons, browsers restrict cross-origin HTTP requests that are initiated from scripts. To meet your requirements for cross-origin resource access, ASM allows you to implement CORS. CORS is a mechanism based on HTTP headers and allows a server to identify domains, schemes, or ports other than its own from which a browser permits loading resources.
The CORS mechanism supports two types of requests: simple requests and preflight requests.
Simple requests:
A browser sends a cross-origin request. The Origin header is specified in the request. This indicates that the request is a cross-origin request. After the server receives the cross-origin request, the server determines whether to allow the request based on configured CORS rules. In response, the server returns the Access-Control-Allow-Origin and Access-Control-Allow-Methods headers to indicate whether the request is allowed.
Preflight requests:
A browser first sends a preflight request by using the OPTIONS method. The request is used to check whether the server allows cross-origin requests from the current domain. If the server allows cross-origin requests from the current domain, the browser sends an actual cross-origin request.
The OPTIONS request contains the following headers: Origin, Access-Control-Request-Method, and Access-Control-Request-Headers. After the server receives the OPTIONS request, the server specifies the Access-Control-Allow-Origin, Access-Control-Allow-Method, Access-Control-Allow-Headers, and Access-Control-Max-Age headers in the response to indicate whether the request is allowed. If the preflight request is allowed, the browser sends the actual cross-origin request.
If a request meets the following three requirements, the CORS mechanism processes the request as a simple request. Otherwise, the CORS mechanism processes the request as a preflight request.
The request uses one of the following methods:
GET, HEAD, and POST
The Content-Type header in the request is set to one of the following values:
text/plain, application/x-www-form-urlencoded, and multipart/form-data
The request uses one of the following CORS-safelisted headers that are defined by the Fetch standard:
Accept, Accept-Language, Content-Language, and Content-Type. Note that the value of the Content-Type header must be set to one of the values that are listed in the second requirement.
Configure a CORS policy in a virtual service
Browsers automatically implement CORS communication. To allow cross-origin requests that are initiated to a service and implement CORS communication, you must set the corsPolicy
field in the virtual service that is defined for the service.
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"
Parameter | Description |
allowOrigins | The addresses of the origins that are allowed to access the service. Regular expressions are supported. For requests without credentials, the server can set this parameter to a wildcard (*) so that all origins are allowed to access the service. |
allowMethods | The HTTP methods that can be used to initiate cross-origin requests. |
allowHeaders | The headers that can be used during actual cross-origin requests. The specified headers are serialized to the Access-Control-Allow-Headers header used in the response to a preflight request. |
exposeHeaders | The headers that the server allows browsers to access. |
maxAge | The maximum amount of time that browsers can cache the response to a preflight request. |
allowCredentials | Specifies whether cross-origin requests can be made with credentials. Only valid credentials can be used to send cross-origin requests. |
Best practices for CORS
Prerequisites
The cluster is added to the ASM instance. For more information, see Add a cluster to an ASM instance.
The default and foo namespaces are created, and automatic sidecar injection is enabled for the namespaces. For more information, see Enable automatic sidecar proxy injection.
Step 1: Deploy applications
Deploy a backend application.
Use kubectl to connect to the ACK cluster. For more information, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
Create a file named details.yaml and add the following content to the file:
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
Run the following command to deploy the details application in the default namespace:
kubectl apply -f details.yaml -n default
Deploy a frontend application.
Create a file named istio-cors-demo.yaml and add the following content to the file:
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
Run the following command to deploy the istio-cors-demo application in the foo namespace:
kubectl apply -f istio-cors-demo.yaml -n foo
Step 2: Deploy ingress gateway services
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose .
On the Ingress Gateway page, click Create.
On the Create page, set the Name parameter to ingressgateway, select a cluster in which you want to deploy the ingress gateway from the Cluster drop-down list, select Internet Access for SLB Instance Type, select Create SLB Instance, and then select the Server Load Balancer (SLB) instance specifications from the drop-down list. Use the default values for other parameters and click Create.
Repeat Step 3 and Step 4 to create an ingress gateway service named ingressgateway2.
Step 3: Create routing rules
Create a routing rule for the backend application to expose the application by using the ingressgateway gateway.
Create an Istio gateway.
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose
.On the Gateway page, click Create from YAML.
On the Create page, select default from the Namespace drop-down list, select a template from the Template drop-down list, replace the content in the YAML code editor with the following content, and then 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
Create a virtual service.
On the details page of the ASM instance, choose
in the left-side navigation pane. On the VirtualService page, click Create from YAML.On the Create page, select default from the Namespace drop-down list, select a template from the Template drop-down list, replace the content in the YAML code editor with the following content, and then 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
Access the backend application.
Obtain the IP address of the ingressgateway gateway service. For more information, see Create an ingress gateway service.
In the browser address bar, enter http://<IP address of the ingressgateway gateway service>/details/2.
If the message in the preceding figure is returned, it indicates that the request to the details backend application is successful.
Create a routing rule for the frontend application to expose the application by using the ingressgateway2 gateway.
Create an Istio gateway.
On the details page of the ASM instance, choose
in the left-side navigation pane. On the Gateway page, click Create from YAML.On the Create page, select foo from the Namespace drop-down list, select a template from the Template drop-down list, replace the content in the YAML code editor with the following content, and then 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
Create a virtual service.
On the details page of the ASM instance, choose
in the left-side navigation pane. On the VirtualService page, click Create from YAML.On the Create page, select foo from the Namespace drop-down list, select a template from the Template drop-down list, replace the content in the YAML code editor with the following content, and then 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
Access the backend application by using the frontend application.
Obtain the IP address of the ingressgateway2 gateway service. For more information, see Create an ingress gateway service.
In the address bar of Google Chrome, enter http://<IP address of the ingressgateway2 gateway service>.
In the URL field, enter http://<IP address of the ingressgateway gateway>/details/2 and click Send.
In the upper-right corner of Google Chrome, click the
icon and choose .
The preceding error messages indicate that the request fails. This is because the istio-cors-demo frontend application sends a cross-origin request to access the details backend application.
Step 4: Configure a CORS policy
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose .
On the VirtualService page, find the bookinfo virtual service and click YAML in the Actions column.
In the Edit dialog box, add the following content to the http field and click OK.
- corsPolicy: allowCredentials: false allowMethods: - POST - GET allowOrigins: - prefix: 'http://<IP address of the ingressgateway2 gateway service>' maxAge: 24h
Step 5: Verify that the CORS policy takes effect
In the address bar of Google Chrome, enter http://<IP address of the ingressgateway2 gateway service>.
In the URL field, enter http://<IP address of the ingressgateway gateway>/details/2 and click Send.
If the message in the preceding figure is returned, the istio-cors-demo frontend application successfully accessed the details backend application. This indicates that the CORS policy takes effect.