HOWTO: Secure Cloudflare Tunnels remote access

If I setup tunnels with zero trust so it asks to verify by email, does this work with the app remotely?

No, the app doesn’t know how to work with that. It needs to be transparent.

1 Like

To connect Alexa, using Service Auth
https://www.reddit.com/r/homeassistant/comments/w6hnhz/help_with_alexa_and_cloudflare_tunnel/

I can’t 100% guarantee this works as I still haven’t got GA to work completely, but I have been using a workaround which allows me to have HA publicly available as a webpage using GitHub auth via Cloudflare Tunnels and also have HA Android app working remotely as well. I mostly followed the steps described here, though they’re somewhat short.

The basic idea is to set up a second hostname on your Cloudflare tunnel, don’t set up a Cloudflare Access application for it (which would enable a GitHub login page, or whatever) but block access to the second hostname via WAF rules (which are outside the Cloudflare Access section, don’t know why both exist) unless a valid client mTLS certificate is presented.

The mTLS certificate is a bit annoying to set up but once done, it has been working well. I found that I couldn’t test the hostname using Chrome on Android even after installing the certificate, so I had to install the Brave browser, which asked me to choose a certificate.

One detail he doesn’t mention in the guide: when setting up the certificate, you have to “Choose which host(s) you wish to enable mTLS”.

But maybe you’ve already worked out some other way of doing it. Just sharing in case it’s still an issue for someone, sorry for going off topic!

If anyone has any opinions on the security of this approach, I’d also be interested.

5 Likes

Hey I have setup remote managed tunnel and it works perfectly, now I also want to have it so I need to have ssl when I login to my home assistant page, so I need to Ute https:// and not http:// so how do I set up that?

Thank you! Works also for EU-Servers.

2 Likes

So yesterday i ditched OpenVPN via my router as it too was killing my phone - 100% down to 5% (or 0%) in 16-18 hours (sometimes less) with light usage (<20 minutes phone use, etc.), in favor of Wireguard, which I found very easy to configure and change. Today my phone battery only went from 100% to 48% in 14 hours.

1 Like

That does seem like it would get the android app working securely remotely without any sort of VPN. Clever solution!

I don’t see how it would work in iOS though.

Also it isn’t a solution for Google Assistant.

Are EU-servers included in the list of ip ranges?

Nice work around. Just wondering if anyone got it to work with iOS?

I’ve just managed to get this method working successfully in lieu of the Wireguard VPN. I now have my cloudflared tunnel with two public domain names: one for browser access via CF email OTP authentication and the second for use by the HA Companion App on my Samsung phone using an mTLS certificate installed on the phone as per Alex Silcock’s ariticle. The last phase to complete now is to convert the Alexa and Alexa Actionable Notifications to use a Cloudflare service token injected into the headers as per comments #7, 9 & 10 by btoconnor on Reddit.

I spent days on this trying all sorts of configs with cloudflare & caddy and in the end (only hours ago) my problems were due to a simple setting in cloudflare (or lack thereof)…

It had been turned off 2 months ago (why I don’t know) but turning it on enabled the cloudflared tunnel to “just work”, plus without any caddy reverse proxying on the external connections. I had narrowed it down to websockets as there were numerous posts about NPM requiring websocket header upgrade but in caddy2 that’s enabled by default now. Doesn’t work though if an external entity has websockets turned off before it even gets to Caddy! After that, the mTLS cert method on my phone was easy…

1 Like

@dbrunt are you able to provide some details about how you configured the mTLS cert method in Cloudflare?

I followed Alex Silcock’s ariticle with the exception of modifying the pfx file generation to use a different encryption method to allow my Android phone to import the key:
openssl pkcs12 -keypbe PBE-SAH1-3DES -certpbe PBE-SAH1-3DES -export -out cf.pfx -inkey cf.key -in cf.pem

For the Cloudflare configuration:

  1. Under my domain → Security → WAF I created an mTLS rule

  2. Then in Zero Trust → Access → Applications I created a new Application to allow access for Any valid certificate will be matched

When I test access via the HA App I get the following forbidden access screen

and when I try to debug using the Brave browser I get a slightly more informative error

When I went back to check my Zero Trust → Access → Applications settings I can see that under the Authentication tab it has automatically enabled the other Identity providers that I have setup for domain.


If disable/deselect all these identity providers they are automatically re-enabled.

Any pointers on where I’ve made a mistake would be greatfully received.

I am still troubleshooting all of this. I’m trying to enable mTLS for my Alexa skill and am slowly pulling my hair out! I am deep into the WAF rules but it seems there is a substantial lag in changes being deployed. I created a rule to block USA but the skill linking can still get to HA even after 30 minutes. Stay tuned…

There not does not appear to be a way to de-select indentity providers. If you de-select Accept all available identity providers, it appears that at least one has to be manually selected.

Try selecting Service Auth rather than Allow for the Action.

Were you prompted to select the local android certificate when you first connected the app via ha-mtls?

Is the Valid Certificate policy the only policy in application ha-mtls?

I am back-ending three different public subdomains through my Home Assistant application into HA and I have two separate policies - 1. Service Auth for certificate and 2. Allow for Email OTP:

From my laptop remotely without a certificate to the general subdomain I get the CF login window.
From my phone to the subdomain for it to use i was prompted for a certificate and now it just works.

I can all get extremely confusing pretty quickly and trying to figure out CF’s order of processing and what goes where and when is not easy. I still don’t have the Alexa or Alexa Media Player working yet…

1 Like

Thanks for your suggestions. I changed my policy to Service Auth and it still didn’t work.

After reading around some more I found that the step I was missing adding my domain to the hosts lists SSL/TLS → Client Certificates

1 Like

That’s fabulous news! I just checked my Client Certificates and all 4 of my hosts are listed.

Hello, a security question that I don’t understand… I have the tunnel set up with Cloudflare and from outside I can access my home assistant fine with https://xxxx but from within the network I have to access via ip or http://local.name:8123 What am I wrong about? I would be interested if it also worked with a certificate from within. Thank you

Something with your internal routing and DNS; I can access my external URL from inside my network just fine.

True, it doesn’t fix Google Assistant. I ended up creating a separate endpoint with limited access to the token and api endpoints required for GA, only allowed access to that using a service token, and created an overly complex Cloudflare worker which checks incoming connections. It doesn’t add much security, but at least it’s another layer…

May not help but I also got IOS app working alongside web UI with CF Access and JumpCloud (Insert any IDP here).

Tested using two approaches:

Approach 1 was Client → CF Access → HA Proxy (Parse JWT and set validated email to X-Auth-Header) → Header Auth to Home Assistant

Approach 2 was Client → CF Access → Cloudflared Tunnel → HomeAssistant Header Auth using cf-access-authenticated-user-email header.

Approach 2 is far less moving parts - and because you are using a Clouflared Warp Tunnel which is secured privately, there is no need to validate the JWT because the cf-authenticated header can be trusted.

To get the IOS app to work was a little painful, annoying but you can exclude /api from cf access and then it works fine. Unfortunately reduces the level of reverse proxy protection but still better than having the whole lot exposed. When custom headers are supported in the IOS or Android App service tokens will be able to secure the API endpoint.

Stating the obvious - if you go with either option, you need to ensure you either parse the JWT correctly or you only allow cloudflared, mutual TLS to validate the cf-authenticated email header came from cf correctly. Otherwise you can just send the header to HA if your implementation is on the internet via other means it may be accessible with a forged header.