We’ve worked with many customers to help migrate their on-premises applications to Oracle Cloud Infrastructure (OCI). These applications often consist of third-party, custom, or internet service provider (ISV) solutions. Sometimes, we’re faced with migrating web applications and web servers to OCI. In almost all these cases, we need to deal with cross-origin resource sharing (CORS).
CORS is a way for web servers to serve resources from a different source in a controlled manner. You can implement it using various solutions, which we cover. This post talks about implementing CORS on OCI load balancers because most of our customers choose this kind of implementation.
To prevent a web page code from making requests to a different origin than the one it was served from, web browsers typically enforce a same-origin policy. The policy protects against malicious websites, but it can also prevent legitimate interactions between a server and clients of a known and trusted origin.
The CORS standard was introduced to address those issues: CORS allows web pages to consume REST APIs served from a different origin by using other HTTP request and response headers to specify which origins can access the resources.
When a web browser makes a request to a server hosting a cross-origin resource, it first sends a “preflight” request to determine if the requested methods are supported. If the server allows the methods, the browser proceeds with the actual request. The CORS standard also enables servers to indicate whether requests can include credentials, such as cookies, authorization headers, or TLS client certificates.
A CORS simple request is an HTTP request that includes an origin header, which identifies the origin server name. A CORS preflight request checks to see if the CORS protocol is understood. It uses “options” as the method and includes the following headers:
Access-Control-Request-Method: Indicates which method a future CORS request to the same resource might use
Access-Control-Request-Headers: Indicates which headers a future CORS request to the same resource might use
An HTTP response to a CORS request can include the following headers:
Access-Control-Allow-Origin: Indicates whether the response can be shared by returning the literal value of the origin request header
Access-Control-Allow-Credential: Indicates whether the response can be shared when request’s credentials mode is “include”
Origin
request header.You have an application server, s1.domain-a.com, serving the web page, http://s1.domain-a.com/. The first request defines the origin server as s1.domain-a.com. The browser runs a JavaScript, relying on “XMLHttpRequest,” which loads http://s1.domain-a.com/image1.gif. This process is a same origin request and doesn’t require any CORS header.
The JavaScript loads http://s2.domain-b.com/image2.gif, which is a cross-origin request. The browser doesn’t allow this request because of the same-origin policy.
The s2.domain-b.com sends CORS headers in the response, such as “Access-Control-Allow-Origin: s1.domain-a.com”. The browser permits the request, and the image is shown in the page.
The following diagram depicts the different requests:
If you want to migrate your API server to OCI, you need to configure CORS headers to allow Cross-Origin requests.
You can add CORS headers in the following ways:
In your application server code
Configure an Apache server in front of your application server by “Header set Access-Control-Allow-Origin” tags
Configure an OCI API Gateway
Configuring headers in OCI Load Balancing
The document demonstrates how to implement the fourth solution by creating an OCI Compute instance with an Apache server as the origin, followed by setting up a load balancer to frontend the Apache service. Both the Compute instance and the load balancer are publicly accessible for testing the response with and without the extra headers.
The origin server has been prepared in OCI as a simple Apache server. You can find a sample configuration in Create a web server on a Compute instance.
Our example uses the following conditions:
We have a httpd server listening on port 80.
The Linux firewall doesn’t block the requests against port 80.
You have configured the proper security lists and routing tables to allow your client to access the Apache server on port 80.
Create a sample html page in /var/www/html/index.html, such as the following example:
You can configure a public load balancer by following this tutorial.
When you reach the Add Backends (Servers) to Your Backend Set step, be sure to select the Compute Instance you just created as the origin server and confirm port 80. When creating the Listener for your load balancer, choose port 80 there as well.
After the load balancer has been created, add a new rule set called “CORS,” as described in the documentation. Check the box “Specify Response Header Rules” and add the following header and values:
Access-Control-Allow-Origin:
s1.domain-a.comAccess-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT
Access-Control-Allow-Credentials: true
Create the rule set, edit the listener, and add the rule set to it:
Resolving on your client hosts file the OCI Compute public IP with Apache as myoriginserver and the load balancer listener public IP as mylbservice, we can verify headers with the curl command. For more details on hosts file editing, see How to edit the hosts file on Windows, Mac, or Linux.
Make a CORS request to the Apache server using the Origin header:
$ curl -k --head -H "Origin: http://s1.domain-a.com" http://myoriginserver/index.html
HTTP/1.1 200 OK
Date: Tue, 21 Feb 2023 16:43:07 GMT
Server: Apache/2.4.37 (Oracle Linux) OpenSSL/1.1.1k
Last-Modified: Tue, 21 Feb 2023 15:08:59 GMT
ETag: "2a-5f53728c545fa"
Accept-Ranges: bytes
Content-Length: 42
Content-Type: text/html; charset=UTF-8
No headers are present in the response. Run the same request against the load balancer:
$ curl -k --head -H "Origin: http://s1.domain-a.com" http://mylbservice/index.html
HTTP/1.1 200 OK
Date: Tue, 21 Feb 2023 16:43:41 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 42
Connection: keep-alive
Last-Modified: Tue, 21 Feb 2023 15:08:59 GMT
ETag: "2a-5f53728c545fa"
Accept-Ranges: bytes
Access-Control-Allow-Origin:
s1.domain-a.comAccess-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization
Access-Control-Allow-Methods: GET, OPTIONS, PUT
Access-Control-Allow-Credentials: true
The load balancer has added the headers. The following code block shows a sample preflight request with the options method:
$ curl --HEAD -X OPTIONS -H "Access-Control-Request-Method: POST" -H "Access-Control-Request-Headers: content-type" http://mylbservice/index.html
HTTP/1.1 200 OK
Date: Tue, 21 Feb 2023 16:45:29 GMT
Content-Type: text/html; charset=UTF-8
Content-Length: 0
Connection: keep-alive
Allow: OPTIONS,HEAD,GET,POST,TRACE
Access-Control-Allow-Origin:
s1.domain-a.comAccess-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization
Access-Control-Allow-Methods: GET, OPTIONS, PUT
Access-Control-Allow-Credentials: true
The presented solution can be useful when exposing your API or web services to different sources using the OCI public or private Load Balancer. CORS is supported on most modern browsers so managing CORS headers is required when web application code needs to access a service in a different domain.
More scenarios are possible, so if you have questions, you can reach out to the authors, Cristiano or Arno. If you want to go hands-on and replay the above scenario yourself, you can get a free trial of Oracle Cloud Infrastructure.
Cristiano is a Cloud Solutions Architect based in Milan (Italy) helping Oracle customers migrating their workloads from on-premise to Cloud. He joined Oracle in 1998 and worked in Oracle Support and Oracle Consulting before the current position in the 3rd Party Apps Specialists Team.
Arno Schots is a hands-on technology enthusiast. In his role as Cloud Director EMEA at Oracle he is leading a team of world-class architects, who are creating the best possible cloud architectures for Oracle's customers, to help them migrate to OCI and be suscesful as a company.
Customer succes is what drives & motivates Arno, hence he is involved in many projects on a weekly basis. Arno beliefs architects should be hands-on and sharing their knowlegde via blog posts with wider audiences.
In his spare time he likes to play flamenco and rock guitar and various kinds of outdoor sports like windsurfing, cyclimng and running in the mountains. He is a happy father of one son.
Next Post