Cloudflare Access

As I have mentioned in a previous post, I truly believe we are on the edge of some pretty radical changes in corporate networking. The buzzword for the concept is SASE (Pronounced “sassy” and stands for Secure Access Service Edge). The buzzword is pretty cringeworthy in my opinion, but the idea is solid. It’s important to note that it’s just a marketing term (similar to “Zero Trust”). It represents a concept, not a specific “thing”, and therefore different vendors offer different functions in the space.

As I’ve been testing out different offerings out there (including this article I wrote about TailScale), Cloudflare’s offering has been the most interesting to me. The naming is a little confusing, but I really like what they have been doing. In general, their SASE offering is called Cloudflare One. This is really a platform with several products within it. I will go into detail in other posts, but for this one I’m working with Cloudflare Access, which is part of their Zero Trust platform, which in turn is part of Cloudflare One.

I see lots of potential with Cloudflare Access. In general, I want to replace VPN’s. They are old, clunky, and don’t work well. They are a heavy-handed solution to specific problems and no one really likes using them. If employees hate to use them, then they typically try to get around using them. I think with modern technology, we should be able to increase security significantly while also actually making it a smoother better experience to actually use.

Cloudflare can create tunnels to specific resources, allowing you to use Access to directly and more securely connect directly to resources. For this post, I set up a direct connection to an RDP instance on a Windows server from my Mac. I then wanted to make sure that the tunnel was set up automatically for me whenever I booted my computer. The idea is based on this tutorial provided by Cloudflare - Connect through Cloudflare Access over RDP

If you follow that tutorial and have a Cloudflare tunnel running on both sides, you can run the following to create a direct tunnel, which allows you to connect RDP to localhost:3389

cloudflared access rdp --hostname {{subdomian}}.barnes.tech --url localhost:3389

My goal was to completely and silently deploy both cloudflared and the above command via MDM, but also have that maintain the connection in the background, and even start it back up after reboot.

The tutorial above walks you through creating the destination tunnel using the config.yml file, which you need to create and authenticate locally on that machine. This works fine, but Cloudflare has since added the ability to create these tunnels directly in the cloud Zero Trust dashboard, and give you one command to set up the tunnel, authenticate with a token, and set up everything you need for RDP. An example of how this looks is something like this -

Windows

\path\to\cloudflared.exe service install {{service token}}

Mac

cloudflared service install {{service token}}

Deploying this way, it is pretty easy to deploy through a script in an MDM. You can just create a script like this -

#!/bin/bash

mostCommonUser=$(/usr/bin/last -t console | awk '!/_mbsetupuser|root|wtmp/' | /usr/bin/cut -d" " -f1 | /usr/bin/uniq -c | /usr/bin/sort -nr | /usr/bin/head -n1 | /usr/bin/grep -o '[a-zA-Z].*')

# Install Cloudflare Tunnel
/usr/bin/su - "${mostCommonUser}" -c "/opt/homebrew/bin/brew install cloudflare/cloudflare/cloudflared"

/opt/homebrew/bin/cloudflared service install {{service token}}	

With that in place, you can create a LaunchDaemon to run the previous command to open an access tunnel and make it available at localhost

I just created one called com.barnes.cloudflare.plist. In Kandji, you can easily deploy this file by zipping it, and then creating a custom application that just unzips the file to /Library/LaunchDaemons. After it does that, you need to use a postinstall script to load the Launch Daemon. First the Launch Daemon -

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>KeepAlive</key>
	<dict>
		<key>SuccessfulExit</key>
		<false/>
	</dict>
	<key>Label</key>
	<string>local.job</string>
	<key>ProgramArguments</key>
	<array>
		<string>/opt/homebrew/bin/cloudflared</string>
		<string>access</string>
		<string>rdp</string>
		<string>--hostname</string>
		<string>{{subdomain}}.barnes.tech</string>
		<string>--url</string>
		<string>localhost:3389</string>
	</array>
	<key>RunAtLoad</key>
	<true/>
	<key>ThrottleInterval</key>
	<integer>5</integer>
</dict>
</plist>

These can be pretty complex to create these correctly and without any errors, and it will just not work if there are any errors, so I used Launch Control to create this.

For PostInstall I used this script -

#!/bin/bash

sudo /bin/launchctl load -w /Library/LaunchDaemons/com.barnes.cloudflare.plist

And that’s it! With this all in place, the tunnel is automatically deployed and the Launch Daemon makes sure it reconnects after reboot automatically!