Home Assistant, Kubernetes, and Traefik

I’ve hosted my Home Assistant install on Kubernetes for quite a while, using a basic network setup of Kube Router, MetalLB, and Traefik. As part of a upgrade cycle I decided to build out a new cluster making use of a CSI plugin for iSCSI provisioning on FreeNAS, and also HAProxy hosted on a pfSense instance.

I copied my configs over to the new cluster, and Home Assistant got in a bit of a tizz. Not matter what I did I couldn’t login to the UI. All that was coming up was the prompt of “Login aborted: Your computer is not allowed”

My Home Assistant config was correct, as far as I knew:

homeassistant:
  ...
  auth_providers:
    - type: trusted_networks
      trusted_networks:
        - 10.101.0.0/16

http:
  server_host: 0.0.0.0
  ip_ban_enabled: false
  login_attempts_threshold: 100
  use_x_forwarded_for: true
  trusted_proxies:
    - 10.85.0.0/16
    - 10.101.10.0/24

The nodes are on 10.101.10.0/24, the Pod network is 10.85.0.0/16, and the clients are in 10.101.0.0/16. !?!?

Using the good ol' inspector within Safari I was able to pull out the response from the request, login_flow returned:

{
    "type": "abort",
    "flow_id": "4c8575ddc18b4d5b83565c08420d3093",
    "handler": [
        "trusted_networks",
        null
    ],
    "reason": "not_allowed",
    "description_placeholders": null
}

Not a massively useful error. Digging into the code shows that its catching an exception and throwing an error. I adjusted the code in the container to throw a bit more details of what is going on, by passing through the exception itself.

        except InvalidAuthError as exc:                                                                                      
            return self.async_abort(reason=str(exc))    

Now, it was complaining of “Can’t allow access from a proxy server”, huh? X-Forwarded-For is switched on in the Home Assistant, but the client IP address was showing as one of the node’s IPs, not the end user IP. Then it suddenly dawned on me.

On my previous cluster, Traefik had been the edge taking connections directly from client systems, but now it was getting requests from HAproxy that knew what the client IPs are. Traefik by default will not trust certain headers it receives from the client and will re-write them to what it understands is the correct value.

The fix? Allowing Traefik to trust the headers. This can be done with the following additions onto the Helm chart:

    additionalArguments:
      - "--entryPoints.web.proxyProtocol.insecure"
      - "--entryPoints.web.forwardedHeaders.insecure"

Further information can be found on the Traefik documentation site