VPS: Cloudflare Zero Trust access to Web Applications (Rev: 07/15)

Linux host setup for cloudflared to allow Zero Trust access to a running web application, using one-time OTP to email, and alternative rules such as country blocking.

Jul 13, 2024
👉
Linux host setup for cloudflared to allow Zero Trust access to a running web application, using one-time OTP to email, and alternative rules such as country blocking.
 
Revision: 20240721-0 (init: 20240713)
 
This content, an extension of the VPS hardening post, introduces a method for granting conditional access to web services enabled on this VPS without the need to open any additional ports through the VPS firewall.
 
 
We will discuss using Cloudflare Zero Trust to access resources running on a VPS without opening any of the new service ports through the VPS firewall.
We will use cloudflared, a command-line tool and daemon that connects our infrastructure to Cloudflare's global network, enabling secure tunnels (with HTTP to HTTPS upgrades) for accessing resources behind firewalls.
Most self-hosted web applications should be compatible with the tool. We will use Dockge, a Docker compose service manager, to enable straightforward web app deployments. We will demonstrate accessing it with Cloudflare Zero Trust (using cloudflared).

Service setup: Docker and Dockge

Our VPS is an Ubuntu 24.04 host, and we configured it following the steps in “Ubuntu 24.04 VPS Hardening”, where only ssh is accessible remotely on this host; every other port is blocked by the ufw firewall (we also covered changing the ssh port to an alternate port and setting up fail2ban).
For this additional setup, we propose Dockge using Docker to support installing a subset of applications (stacks) using docker compose. To add those on our Ubuntu 24.04 VPS:
  1. Follow the “Docker setup (from docker.io)” section from the “Setting up NVIDIA docker & podman (Ubuntu 24.04)” post (this section provides only the steps to install Docker).
  1. Follow the “Setup (with Docker)” section from the “Dockge” post. In the following, we will not install additional stacks, but the tools will enable us to add many should we decide to.
After following those instructions, the Dockge service will be available on localhost only. It will not be remotely accessible since our VPS firewall configuration limits access to any port other than the modified SSH port.
To confirm that the service is working, we can connect to the remote host’s localhost interface on Dockge’s port (5001) and forward it locally to a port, for example, 4001 (here vps is a Hostentry in our .ssh/config):
ssh vps -L 4001:127.0.0.1:5001 -N
With this command, there will be no shell prompt (-N); the tunnel will be active until we Ctrl+C the command. While the tunnel is active, we can open Firefox to http://127.0.0.1:4001/ which will open the Dockge setup interface.

Cloudflare

👉
Cloudflare will require you to have a credit card on file with your account. We note that given our limited usage, the free tier offered by Cloudflare have been sufficient for our use of their tools.

DNS Provider setup

For the next steps to be functional, we need to own a domain name with a registar, and to have its DNS servers pointed to Cloudflare’s resolvers. For this document, we will use example.com
Please see https://developers.cloudflare.com/dns/zone-setups/full-setup/setup/ for detailed instructions on how to get a domain’s DNS handled by Cloudflare.
Moving your domain’s DNS to Cloudflare involves:
  • Sign up for a Cloudflare account (if you don't already have one), make sure to set Multi-Factor Authentication.
  • Once logged in, add your domain to Cloudflare’s dashboard.
    • Cloudflare will attempt to scan your existing DNS records and import them automatically.
    • Review these records carefully to ensure all your current DNS settings are accurately captured. It is possible you will need to refer to your original registar to fill in any missing details.
  • When all records are ccurrent, update your domain's name servers at your current registrar to point to Cloudflare's nameservers (provided to you by Cloudflare).
    • This change can take up to 24 hours to propagate globally (generally it is done in minutes).
  • Once the name server change is complete, you will receive a confirmation email and your domain will be active on Cloudflare's DNS.
Note that the process only moves your DNS management to Cloudflare and your domain registration remains with your current registrar.

Additional security recommendations

Here are a few recommended settings for a more secure configuration; adapt according to your preferences.
On the main Dashboard, select example.com in “Websites”
  • select “SSL/TLS” and set the “encryption mode” to “Full (strict)” (or at least “Full”)
    • In “Edge Certificates”, make sure “Always Use HTTPS” is enabled
  • In “Security” (in order of options)
    • for “WAF” select “Custom Rules” and “Create Rule”
      • this rule will block anything that Cloudflare considers threatening; we will name it Zero Threat
      • “When incoming requests match…” Threat Score ”Field”, greater than ”Operator”, 0 ”value”
      • “Then take action …” Block
      • select “Deploy”
    • for “Bots”
      • enable “Bot Fight Mode”
      • decide on “Block AI Scrapers and Crawlers”
    • Cloudflare enables “DDos” protection by default, so nothing should need to be changed there
    • Review Cloudflare’s proposed defaults for “Security”
Also on the main dashboard for our site (in the “Overview” section, under “Quick Actions”), it is possible to “Activate” some “Basic Features”; the list of those features can be found at https://developers.cloudflare.com/fundamentals/basic-tasks/basic-features/. Given that some of those (”WebSockets”, “Onion Routing”, “Hotlink Protection”) might not be part of the settings needed for your host, we leave the decision to enable all of those to the end user. If all are desired, “Activate” will enable those on your site; otherwise Cloudflare’s documentation detail how to enable those on a per feature basis.

cloudflared: Cloudflare tunnels

Once our example.com domain’s DNS is hosted at Cloudflare, the next step is to set up a Cloudflare tunnel. To better understand the idea of what used to be called “Argo”, please see https://blog.cloudflare.com/argo-tunnel/ (from 2018). The modern “Cloudflare tunnels” is described in https://www.cloudflare.com/products/tunnel/:
From the moment an application is deployed, developers and IT spend time locking it down — configuring ACLs, rotating IP addresses […] Your origin IP addresses and open ports are exposed and vulnerable to advanced attackers, even when they’re behind your cloud-based security services. […] Cloudflare Tunnel is tunneling software that lets you quickly secure and encrypt application traffic to any type of infrastructure, so you can hide your web server IP addresses, block direct attacks […] The Tunnel daemon creates an encrypted tunnel between your origin web server and Cloudflare’s nearest data center, all without opening any public inbound ports.
We will use it with “Zero Trust Web Access” which provides “Secure access to internal web applications without a device client”. Cloudflare has a well written “learning path” on their site and we encourage readers to review https://developers.cloudflare.com/learning-paths/zero-trust-web-access/. The ideas are:
“Zero Trust is a security approach built on the assumption that threats are already present within an organization. In a Zero Trust approach, no user, device, or application is automatically trusted — instead, strict identity verification is applied to every request anywhere in a corporate network, even for users and devices already connected to that network. […] Zero Trust only grants access to a specific application and denies access to all other resources by default”
“Zero Trust Web Access (ZTWA), also known as Zero Trust Application Access (ZTAA), provides users with secure access to internal applications using Zero Trust principles. ZTWA authenticates users to applications by integrating with identity providers, encrypting connections, considering each access request for an application individually, and blocking or allowing on a request-by-request basis.”
🚧
Note: the following steps follows the Dashboard available as of July 2024; components on Cloudflare’s WebUI have changed from time to time.
For our purpose, we have added our example.com domain (a “Zone” following Cloudflare’s terminology) to our Dashboard.
  • Once on our dashboard, select the “Zero Trust” entry on the left side.
  • If this is our first time setting it up:
    • On the onboarding screen, choose a team name. The team name is a unique, internal identifier for your Zero Trust organization […] it will be the subdomain for your App Launcher […] Complete your onboarding by selecting a subscription plan and entering your payment details. If you chose the Zero Trust Free plan, this step is still needed but you will not be charged.
  • Configure an identity provider (if preferred); in our setup we will use the One-time PIN login method (free up to 50 users); when end users go the the application’s url (for our setup we will name it dockge.example.com):
    • end users will be challenged with an “Access login” page, where they will enter an authorized email address, and select “Send me a code”
    • if the email is allowed (and only then), they will receive a One-time PIN at that email, which expires 10 minutes after the request to enter on the challenge page.
    • Valid users with valid pins will be allowed access to the web application.
  • Connecting the web application is done by using cloudflared which connects an host and port to Cloudflare’s global network.
    • The steps to follow are:
    • from the Zero Trust Dashboard, select “Network -> Tunnels -> Create a Tunnel”.
    • select “cloudflared”.
    • name the tunnel; here we will name it vps-cloudflared when in general we would name it the same as the host or its ssh alias.
    • on the “Install and run a connector” page, we will be prompted with options to download cloudflared. Our VPS host is an x86 Ubuntu 24.04, so we follow the “Debian” “64-bit” instructions which includes that tunnel’s token. This token is a secret, similar to an API key, and should not be shared.
      • if your VPS was configured with DNS-over-HTTPS with cloudflared (as in our VPS hardening post), you already have the tool installed and can use the sudo cloudflared service ... entry
      • otherwise, the curl ... command line will install and configure the service on the VPS
    • Once the connection is established, it will show up in the “Connectors” section.
    • The “Route” tab allows us to connect our application; let’s add a “Public Hostname”
      • for subdomain, we will use dockge
      • for domain, we will use example.com
      • we will not provide any path
      • service type should match the protocol used by the application, here http
      • service url is 127.0.0.1:5001, the service is accessible only on localhost and is running on port 5001
      • under “Additional application settings”, we will not alter “HTTP Settings”, “Connection” or “Access”; we will configure the One-time PIN shortly.
      • make sure to save
    • from the Zero Trust Dashboard, select “Access -> Applications -> Add an Application”.
      • select the “Self-hosted” type
      • for “Configure application”
        • we will use the dockge name
        • the duration is the time before the access is challenged again for a given browser session, select an option that matches the expected policy.
        • the subdomain, domain and path must match our configured “Route”, so we will use dockge, example.com, and no value
        • we will not modify “Tags”, “Block pages” or enable “WARP”.
        • Unless you have added alternate ones, the “Identity providers” section should have “One-time PIN”
      • on the “Add policies” page, we will configure the users allowed to access the dockge.example.com URL with authorized emails. We note that you can prepare lists of “Access Groups” to add more than one person to that list, but for this setup, we will only add one authorize user.
        • name the policy, we will use email
        • we will set what the email policy allows for the a “Session duration” of Same as application session timeout
        • In the “Create additional rules”, we can add multiple options (please see the zero trust learning path for additional details). We will only “Add include” the email ”Selector” and set an [email protected] ”Value”
        • we will not alter the “Additional settings” section, or the values of the “Setup” page
    • After adding the application, we will be returned to the “Applications” page where the newly configured tunnel, protected by an access policy, is now active.
 
Heading over to https://dockge.example.com/ is now possible. Note that the access is now using HTTPS and we have not open any additional ports on our VPS. After answering the ZeroTrust challenge, we are presented with the admin account creation page for Dockge.
notion image
Because this is an internet accessible site (protected by Cloudflare’s Zero Trust) with a defined url, when creating the username and password, we have the ability to store the details in a password manager and expect no collision of URL with other self-hosted components.

Other options for limiting access to a web application

Beyond the ability to create a one-time OTP, it is also possible to allow access with alternate limitations. In the following we will use an access policy, following the list detailed at https://developers.cloudflare.com/cloudflare-one/policies/access/
We have a web application that we want only people in the United States to be able access. Since we are testing this from the USA, we will first set the access to only Canada to confirm the block works:
  • From “Zero Trust Dashboard → Networks → Tunnels”, we select the “…” at the far right end of the matching tunnel and use “Configure”. We then create a new “Public Hostname” such as “web.example.com”
    • Note that if this is not done first, the next step will show “Warning: No DNS record found for this domain. The policy may not execute as expected.”, but it is possible to set the access policy before creating the matching “Public Hostname”
  • As before, from “Zero Trust Dashboard → Access → Applications”, select “Add an Application” of type “Self Hosted”. We name it usa access web and match the application to the web subdomain and the example.com domain.
  • in the “Add policies” tab, name it “usa only”, and select the Bypass type, then deselect any email option, instead in “Configure rules” “Include” the Country ”Selector” and set its value to Canada
    • Bypass policies set a path that Access will not protect. You can configure IP or group-based rules, or set the policy to permit all requests with “Everyone”. Bypassed requests will still use HTTPS if it is turned on in the SSL/TLS dashboard. […]
      notion image
      notion image
  • After completing the “Setup” tab, when trying to access our web.example.com we will be facing a “Forbidden” (403) page since our request is made from the USA.
notion image
  • to make it work as expected, go back to “Zero Trust Dashboard → Access → Applications”, use the “…” on the right side of “usa access web” to “edit” it. This will show us a list of policies. Select the “…” on the right next to the policy to alter to “Configure” it, modifying it for United States
notion image
After saving, going to the url allows us to see the web application without being blocked by the geolocation filter.
 
There are many other options such as “Emails ending in” or “IP ranges”, as can be seen in the “Selectors” section of https://developers.cloudflare.com/cloudflare-one/policies/access/#selectors (please see the “Order of Execution” right below to set more complex rules).

Revision History

  • 20240721-0: Added note about “basic features”
  • 20240716-0: Restructured Cloudflare section
  • 20240715-0: Added a few recommended security settings when using a domain with Cloudflare.
  • 20240713-0: Initial release