Code Monkey home page Code Monkey logo

azure-staticwebsite-behind-cloudflare's Introduction

Using Azure Static Websites Behind Cloudflare

December 21st, 2021

Table of Contents

  1. Overview
  2. Azure Static Website Setup
  3. Domain Registration & Custom Domains with Azure Static Websites
  4. Configuring Cloudflare in Front
  5. Summary

As part of Azure blob storage exists the capability to host static websites. In combination with features from Cloudflare, there exists a maintainable, performant, secure, and low cost option for serving static content as this document is meant to prove. Below are some typical requirements for a company website that consists of only static assets.

  • No public access via API or directory browsing to website assets
  • Assets must be served over HTTPS
  • A custom domain is the only way to reach the site
  • The proper security headers will be put in place and tested to meet standards.
  • Assets can be cached and minified without the need for a complex build process.

The steps in this page detail that which was performed to set everything up ranging from the purchase of a domain through GoDaddy to configuration of both Azure static websites and Cloudflare to determine if the specified requirements could be satisfied. Note that the screenshots used in the hyperlinks in this page where created on December 21st, 2021 and will deviate from the actual service provider screens over time.

With an Azure subscription in place, a storage account was created Azure portal which is an obvious required step for using Azure static websites. Though there are many ways to create a storage account, the steps below using the portal were what was used.

  1. In the Azure portal, clicked + Create a resource in the upper left-hand corner.
  2. Entered storage account in the search box and clicked Create on the following page.
  3. On the Basics blade entered information like a resource group put this resource in and a unique storage account name. Other options like redundancy could be changed later so no other configuration was necessary here.

Once the storage account was created, the ability to enable static websites was available from the Static website blade. (NOTE: A not authorized message on this Static website blade was be observed requiring some blob access modifications in accordance with this graphic). Static websites were enabled by simply by toggling it on, entering the name of index document (e.g. index.html), and choosing Save. The URL of static website was displayed (i.e. https://staticwebsitecloudflare.z13.web.core.windows.net) as a result. This URL was the Azure public website address.

Aside from a new public URL, another side-effect of enabling static websites was the creation of a special folder named $web. This is the target location for static website assets sourced from this repository's src folder. To upload files, the $web folder was chosen from the Storage browser blade. Everything on this screen was self-explanatory so the upload mechanics will not be discussed here in detail. Once all the assets were uploaded, their delivery to a browser were tested successfully by navigating to the URL (https://staticwebsitecloudflare.z13.web.core.windows.net) specified on the Static website blade in the last section.

Although a big success to have a static website up in less than 5 minutes, there was more work to do to satisfy all the requirements listed in the Overview.

The next goal was to register a custom domain and associate it with the Azure static website created in the last section. GoDaddy was used though any registrar would do. The domain registration process on GoDaddy was fairly straight-forward so it will not be covered in detail here. The domain chosen for this exercise was staticwebsitecloudflare.site and the cost was $1.17/year. Auto-renewal was cancelled since this domain is only going to be used for this exercise.

DNS settings could be managed in the GoDaddy portal. By default, the DNS settings included an A record with a special value of Parked. This was a friendly name to the GoDaddy placeholder page. One option that came to mind at this point was to change this A record value to the IP for our Azure static website so the DNS look-ups for staticwebsitecloudflare.site would resolve appropriately. Unfortunately this experiment did not work as that IP is pooled and Azure requires the FQDN in order to route traffic appropriately. There was also a CNAME record that effectively returned the address of the root domain represented as @. With these default DNS entries in place, the steps and approach chosen to associate our new domain with our Azure static website was as follows.

  1. In the GoDaddy DNS settings, changed the CNAME record value to the FQDN of the Azure website and set the Domain name field to the www subdomain address (i.e. www.staticwebsitecloudflare.site) on the Custom tab on the Networking blade in the Azure storage account. (NOTE: The first option in the Azure instructions eventually worked but it took a couple of tries. Its possible the CNAME record needed time to expire.). At this point, navigation to see our website to the www subdomain, www.staticwebsitecloudflare.site, worked in the browser. Unfortunately navigation to the root of the domain, staticwebsitecloudflare.site, still resolved to the GoDaddy placeholder site. To remedy this the following steps were performed.
  2. Removed the A record in preparation for the next step.
  3. Used GoDaddy's domain forwarding to forward traffic from staticwebsitecloudflare.site to www.staticwebsitecloudflare.site. Because of the configuration in Step 1, the assets from the Azure static website were returned in the browser.

In the end our GoDaddy configuration looked as follows in this graphic. GoDaddy added to A records for its forwarding service domain forwarding was set up.

At this point, browser navigation to the root domain of staticwebsitecloudflare.site and the subdomain of www.staticwebsitecloudflare.site to see the Azure static website both worked. This was good progress but there were still issues.

  1. The site scored an F on securityheaders.io.
  2. The content was not being distributed over HTTPS.
  3. Browser navigation using the Azure static website address (i.e. https://staticwebsitecloudflare.z13.web.core.windows.net/) to see content still worked.
  4. Website files were not being compressed or cached.

The next section introduces Cloudflare to fix these issues.

Its advantageous to have all the traffic to pass through a "value layer" that provides security, caching, and other features. Although many cloud providers offer the same features, Cloudflare was easy set up and is best in class. At the time of this writing, their servers handle 10 trillion requests every month.

At a high level, in order for traffic to be forced through Cloudflare two things needed to be done.

  1. DNS management for the domain must be transferred from GoDaddy to Cloudflare.
  2. In Azure, set the blob service created earlier to accept traffic only from Cloudflare servers.

With a free account on Cloudflare in place, the following steps were followed to set up Cloudflare as a proxy.

  1. The first step was to add the site. It was at this point, the URL for the custom domain set up in the last section, was specified and the free plan as chosen. From there, Cloudflare read the GoDaddy DNS records for purposes of import. During the review only the CNAME record pointing to our Azure static website domain was kept. Recall records like the first two A records were for the GoDaddy forwarding service and that was no longer being used.
  2. The next step was to switch to using Cloudflare's nameservers. This involved logging back into the GoDaddy portal and changing the nameservers in the DNS settings to those provided by Cloudflare. Note that GoDaddy issued a warning for this change. After making this change only Cloudflare's nameservers could be seen. All DNS records were cleared as DSN now being managed by Cloudflare. Also once complete Cloudflare checked that the nameservers have been changed successfully.
  3. At this point Cloudflare presented some configuration recommendations such as enabling HTTPS and minification of static website assets. Both options were enabled. It should not go unnoticed as these are two significant features being given for free. Cloudflare is going to manage a valid TLS certificate and minify files thereby reducing effort and cost.

This was it for the initial setup. Shortly after setup (i.e. less than 60 seconds) an nslookup was run to see that Cloudflare's nameservers were being used.

> nslookup
...

> set type=NS
> www.staticwebsitecloudflare.site
...

staticwebsitecloudflare.site
        primary name server = cris.ns.cloudflare.com
        responsible mail addr = dns.cloudflare.com
        serial  = 2265582889
        refresh = 10000 (2 hours 46 mins 40 secs)
        retry   = 2400 (40 mins)
        expire  = 604800 (7 days)
        default TTL = 3600 (1 hour)

Browsing to the www subdomain of www.staticwebsitecloudflare.site also worked, was served over HTTPS with a valid certificate, and it was observed that files were being minified.

At this point, the outstanding issues were as follows.

  1. The root domain (staticwebsitecloudflare.site) did not work.
  2. Navigation to the Azure static website address to see the site still worked.
  3. The necessary security headers to score an acceptable rating on securityheaders.io were not set.

To fix the first issue list above, what Cloudflare calls Page Rules were used and what those are are best explained here. Two rules were put in place that allowed for the forwarding traffic, originally destined for the root domain, to go to the www subdomain. This was basically the same thing done in GoDaddy. In the end there were two redirect rules for HTTP and HTTPS. The root domain however still did not work and this is because there was no A record. In Cloudflare DNS settings it made sense to use the pooled IP address from Azure, which in this case was 104.21.3.7. This entry did not need to be proxied so the Proxy state was set to DNS only.

> nslookup
...

Non-authoritative answer:
Name:    staticwebsitecloudflare.site
Address:  104.21.3.7

Once the specified address was returned from an nslookup command, a couple of more steps were necessary and these were somewhat tricky.

  1. In the Cloudflare DNS settings, the Proxy status for the CNAME record was set from Proxied to DNS only. The was temporary and the reason was to re-verify the CNAME record from Azure like was done with GoDaddy. This would not work if the Proxy status toggle is set to Proxied.
  2. In Azure, the CNAME was re-verified using Custom tab of the Network blade in the storage account. The previous entry had to be first cleared, saved, and then reapplied.
  3. While in Azure, HTTP traffic was also allowed using the Configuration blade and disable Secure transfer required. The idea was that traffic from Cloudflare to Azure is unlikely to be attacked.
  4. Finally, the toggle set in Step #1 was reversed so the Proxy status in Cloudflare DNS for the CNAME record was set back Proxied from DNS Only.

At this point the following URLs were tested. Chrome was used with a new Incognito instance with the browner DNS cache cleared for good measure at chrome://net-internals/#dns.

All requests worked and used HTTPS regardless whether it was specified or not.

At this point, the website could still be reached using the Azure static website URL (https://staticwebsitecloudflare.z13.web.core.windows.net). With the use of this URL, traffic bypassed Cloudflare thereby defeating its purpose. Fortunately in Azure, on the Firewalls and virtual network tab under the Networking blade for the blob service, a whitelist of accepted IP addresses can be specified. Cloudflare publishes their IP addresses which were used in this configuration. Once the Cloudflare IP address restrictions were in place, it was not possible to reach the website using the Azure static website URL of https://staticwebsitecloudflare.z13.web.core.windows.net. The URLs tested in the last section still still worked after these changes.

The final problem that needed to be fixed was the low security header score from securityheaders.io. Cloudflare's Transform rules allowed for the specification of HTTP headers to be returned given certain conditions. This graphic shows that, given an HTTP GET or HTTP POST as request method, the following HTTP response headers are configured to be returned as part of the HTTP response.

  • Content-Security-Policy = upgrade-insecure-requests
  • Permissions-Policy = geolocation=(self), microphone=()
  • Referrer-Policy = strict-origin-when-cross-origin
  • Strict-Transport-Security = max-age=2592000
  • X-Content-Type-Options = nosniff
  • X-Frame-Options = DENY

After setting these security header values, the score from securityheaders.io was acceptable.

In the Overview, the original requirements were as follows.

  • No public access via API or directory browsing to website assets
  • Assets must be served over HTTPS
  • A custom domain is the only way to reach the site
  • The proper security headers will be put in place and tested to meet standards.
  • Assets can be cached and minified without the need for a complex build process.

All these were satisfied including caching which has not yet been discussed. Cloudflare has a caching configuration that optimizes delivery of website files to target clients all around the world. When debugging or deploying a site, however, it might be best to disable caching on the Overview blade to ensure updated assets are returned and not the cached versions.

In summary, the combination of Azure Static Websites and Cloudflare were a great choice meet the requirements for most static websites. Of course, DevOps can be put in place as well that will allow for assets to be deployed given a push to a Git repository, for example, but that was beyond the scope of this investigation.

azure-staticwebsite-behind-cloudflare's People

Contributors

strisys avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.