Cloudflare ZeroTrust + Cloudflared Add-On + Companion Apps === Better Security

I don’t use Windows, so I’m not quite sure of how or where to import store custom certificates and trust them.

However, the browser should be requesting a certificate on page load. (At least, that’s how it worked for me on MacOS for either Chrome or Safari.)

And come to think of it, this is only when loading the HA webUI through the Cloudflare tunnel. It’s actually Cloudflare that wants the certificate, to validate according to the WAF rule.

But I would suggest, it’s all somewhat irrelevant if accessing HA locally. I mean, if you trust yourself, there isn’t much need to get too secure?

For my setup, I do use internal and external FQDNs ( + subdomain for external, domain.tld for internal).

Through DNS rewrites, I manage local device connections to route to the local LAN IP, regardless of the domain in the request.

Doing this bypasses the CF Tunnel, which is ok, because I trust myself.

after some playing around on zerotrust I was able to add a rule by country to bypass policy:

I then had to change the access rule on the tunnel to turn off “Protect with Access”

This is even with a WAF rule, I can see the rule being hit but the skip step seams to get missed.

Would be good to have the WAF rule working for iOS so I can have the network, country, user agent rules (access has less of these options)

Hi @Lewis , does this also block ipv6 addresses? Or only ipv4?

Would it be better to have this rule (inspired by your original “in Country” AND “not in Country” rule):

(ip.src in {0.0.0.0/0} and not ip.src in {0.0.0.0/0})

I tried your rule 5 using my Android phone, but since the IP address that appears in the Request Details is IPv6, your “Lock Down rule” did not block it.

Instead, what I needed to do was capture any requests with IPv4 and IPv6, like this:

(ip.src in {0.0.0.0/0}) or (ip.src in {::/0})

  1. Created a block IP source of 0.0.0.0/1 theoretically blocking the entire internet
  2. Created a skip all following rules for the hostname of my website & client certificate verified and put it above the former rule
  3. Generated a client certificate which gave me a certificate and private key
  4. Saved both individually as client.crt and client.key individually
  5. Downloaded OpenSSL and used the following command to turn it into a p12 file: openssl pkcs12 -export -in correct-client.crt -inkey correct-client.key -out client.p12 -name “Hostname”
  6. Uploaded the P12 file to Chrome. Checked if I could access it, I got a blocked error
  7. Checked the certificate and it was one provided from my anti virus, disabled the antivirus and cleared the browser cache. Tried accessing it again still blocked from google trust services.

Where have i gone wrong?

Your “all internet” CIDR mask should be 0.

0.0.0.0/0

Using /1 only captures half of the IPv4 space.

Is your Block rule AFTER your Skip rule in the Cloudflare WAF rules list? The CF WAF rules are processed in order, so if the block is first, or before the skip, your skip rule won’t be applied because the Block rule was true.

The block rule is indeed after the skip rule. I think its a certificate issue.

Check the Events in the Security of Cloudflare (same sub menu as the WAF).

Filter the view so that it only displays your certificate rule.

There will be detailed information about the pass/fail outcome.

I’ve used the Events extensively to troubleshoot blocks and skips. And to fine tune my rules to ensure only I can get through.

The process can become quite nuanced. I am still prevented from Saving passwords in VaultWarden when using the CF Tunnel for ingress because my rules are too tight, and the Save process must be using a URL scheme which I have yet to determine and define. But that’s a low priority for me.

Just noticed its generating a ceriticate for home.myhomeassistantexternalurl rather than just the home assistant external url.

Thanks @Lewis for the tutorial and post. I am just trying to work out how I am going to tackle this, as I have previously been using the initial authentication, but that is a pain for certain apps (Bitwarden, etc), as well as the annoyed wife factor for having to do anything extra… So I do need a method to get it all going when away from the house. However, it will need to be on multiple devices and applications.

@kzaoaai, I do like the idea of your method as well, which I did try to get going with adding my mobile phone IP dynamic address, then I ran into the complications of multiple phones / IP’s etc. Are you able to share your redacted iOS shortcut & IP update script?

I do have Tailscale setup but as you noticed, it sometimes causes problems with my connection, so would prefer not to have that on all the time…

Thank you for the thanks!!

So many times when I am trying to make something work, using parts of others’ tuts and posts, I wonder if my contributions ever get noticed.

I have likely modified my security flow since I wrote this.

A major discovery I made recently is that iOS http POST can be sent to a NodeRed HTTP-in node, and then that flow can handle more authentication, like insisting on a token in the header to validate.

I have found this useful in trying to make automations more… automated.

I try to have iOS do as little as possible, and process triggers and actions and data and responses within HA.

My most recent is an elaborate alarm system which integrates / syncs iPhone alarms to HA, and HA uses the alarms to trigger things like turning on light and opening covers and playing wake-up music.

Sure. All of that could be accomplished with Shortcuts and Automations on iPhone. But the iPhone lives to give up in a kernel panic when something isn’t exactly correct.

Anyway, I’ve digressed.

If you are at some point and you’ve hit a block, send me a DM, I would be glad to provide whatever assistance I can muster.

Just to say thanks a lot this was very helpful.

After the posts from @Lewis and @final_blueberry, I finally got stuck into getting my version of Cloudflare working for Home Assistant, Frigate, Immich, and all of my self-hosted things. Instead of some of the methods used in this thread and others, I took parts from each and then added some extra myself.

Now I have my services ie. sub.domain.com protected by email login code but if you are in the ‘safe ip’ or whitelist, then you skip that all together. This is achieved by CF Zero Trust, Cloudflare tunnel, IP list via iOS shortcut.

I have created my own post

You should mention your solution is for IOS users as I got to reading, and nearly setting it up until i re-read it and noticed its really only useful for IOS far as I can see?

I am not sure how many times iOS & Shortcuts are mentioned in my post. Sometimes you really wonder why you bother putting up posts to help people…

The updating the IP part in my guide is iOS centric. But, the rest of the guide would apply to Android or even laptop, etc. You just need to update that part to suit Android, which I am sure it wouldn’t be very hard…

This is an excellent security posture guide, really underrated. Adding one practical footnote from someone who’s been running this exact stack for a while: the Cloudflare Access session will eventually expire, and when it does, browser tabs on HA show “Unable to connect to Home Assistant” and can’t self-recover (Service Worker + CORS + WebSocket combine to hide the Cloudflare login redirect from the frontend).

The Companion app handles its own re-auth fine (covered already in this thread). For the browser side, I published a small JS module that detects the expired-cookie state and forces a reload through the Cloudflare wall: GitHub - mayerwin/HA-Cloudflare-Access-Recovery: Self-healing Cloudflare Access auth for Home Assistant - recovers the HA web frontend in any browser (desktop or mobile) when the CF_Authorization cookie expires. · GitHub

I have had a tunnel running in my network, not the HA add on, from which I have had access to my HA by zero trust email verification.
Based on this I tried to get the app to work (when not on VPN).

I created a certificate uploaded it. When starting the companion app it asked for the cert to use.

And the created rule gets hit with the certificated connection:
rule:

Hits:

But HA stays blank and it keeps it keeps opening the broswer to display Cloudflare is refusing access:

Witin zero trust I tried adding additional policies allowing wth validated certificate but it makes no difference, and it won’t let me create a bypass rule based on a certificate…

I know I can still use the app when my VPN is on as it used the local addressbut it would be nice to get it working and I am running out of ideas…

I am trying to set it up. But I have several issues:

  1. Created a client certificate; converted it to P12 (also PFX); imported this cert on my android phone. It says imported succesfully, but I do not see it as a user cert. So I am not sure if it is OK correctly. ChatGPT says it can happen when a Private Key is available and therefor it is not shown. Also; how and when does the Companion app sees the cert? Because when starting it does not show me any notifications and I do not see any option… Also, as far as I see the client certificate is self signed. So wherefor do I need a Root certitcate? The domain itself is protected by Cloudfare using a Lets Encrypt certificate. How to proceed with this?
  2. I tried allot with the Security Rules. My first test was to block all the traffic; but the Secuity rule with this in the expression “(cf.tls_client_auth.cert_verified)” is not hit at all. I can always succesfully browse to HA. So what do you need to do to activate it succesfully and it will evaluate this. As test I deleted the Hostname within this expression, so it should always hit. But it does not.

Thanks Help would really be appreciated!

I was able to get it working. But I did allot of additional testing; but I find it very unstable…
Mostly a client does not detect or ask for the certificate to connect, that is the main problem. The App by itself seems to work, but mostly browser sessions do not. If the Certificate is seen, it works OK. But if you try open HA through the browser e.g. Windows, the certificate detect does not work. The windows App is based on a browser session, so that one does not work and
So sometimes it sees it, asks for the certificate or still detect it Ok and everything is working ok but only restarting the browser is enough to get a dead connection and I get a block because this is the last security rule.

I created a rule for the Home Assistant App where I detect the User Agent with my mobile phone type and Home assistant in the rule; so basically for the app you can still securely workaround it. But this is not working for browser sessions with Home Assistant.

Is anyone experiencing the same issues? Or are there any other solutions around with Cloudfare?

I just wish I could add custom headers and just use a token to bypass Zerotrust.

The immich photo server does it this way and it works brilliant.