Exposes the Z2M web UI behind the same passkey-gated Authentik proxy-outpost pattern as esphome/shelly-manager/vscode. The frontend has no auth of its own, so Traefik only routes the hostname to a dedicated outpost that validates the session first.
apps/home-assistant/zigbee2mqtt-ingress.yaml — zigbee2mqtt.home.renner.uno → outpost; zigbee2mqtt-tls auto-issued by cert-manager
apps/authentik/zigbee2mqtt-gate-egress.yaml — CNP: outpost → app.kubernetes.io/name: zigbee2mqtt on :8080
Edits
apps/authentik/blueprints-configmap.yaml — 5-entry blueprint block (group / proxy provider / application / policy binding / outpost) named zigbee2mqtt-gate. internal_host includes the explicit :8080 (Service listens on 8080, not esphome's :80). Authentik spawns the ak-outpost-zigbee2mqtt-gate Deployment+Service from this.
infrastructure/network-policies/home-assistant-ns.yaml — fromEndpoints rule admitting the outpost to :8080. Note: shared :8080 with vscode/shelly-manager — the fromEndpoints selector + the authentik-side egress scope it to the zigbee2mqtt pod.
both kustomizations register the new files.
Automatic / no action
DNS (k8s-gateway watches Ingress → creates the record), TLS (cert-manager ingress-shim). Access limited to the Zigbee2MQTT Managers group (k.renner).
Verified
kubectl kustomize builds all 3 dirs; --dry-run=server clean; the embedded blueprint YAML parses with the new 5-entry block.
After merge: Authentik reconciles the blueprint (~minutes) and spawns the outpost; then https://zigbee2mqtt.home.renner.uno prompts the passkey step-up and proxies the frontend.
Exposes the Z2M web UI behind the same passkey-gated Authentik proxy-outpost pattern as `esphome`/`shelly-manager`/`vscode`. The frontend has no auth of its own, so Traefik only routes the hostname to a dedicated outpost that validates the session first.
## New files
- `apps/home-assistant/zigbee2mqtt-gate-service.yaml` — ExternalName → `ak-outpost-zigbee2mqtt-gate` (authentik ns, :9000)
- `apps/home-assistant/zigbee2mqtt-ingress.yaml` — `zigbee2mqtt.home.renner.uno` → outpost; `zigbee2mqtt-tls` auto-issued by cert-manager
- `apps/authentik/zigbee2mqtt-gate-egress.yaml` — CNP: outpost → `app.kubernetes.io/name: zigbee2mqtt` on :8080
## Edits
- `apps/authentik/blueprints-configmap.yaml` — 5-entry blueprint block (group / proxy provider / application / policy binding / outpost) named `zigbee2mqtt-gate`. `internal_host` includes the explicit **:8080** (Service listens on 8080, not esphome's :80). Authentik spawns the `ak-outpost-zigbee2mqtt-gate` Deployment+Service from this.
- `infrastructure/network-policies/home-assistant-ns.yaml` — `fromEndpoints` rule admitting the outpost to :8080. **Note:** shared :8080 with vscode/shelly-manager — the `fromEndpoints` selector + the authentik-side egress scope it to the zigbee2mqtt pod.
- both kustomizations register the new files.
## Automatic / no action
DNS (`k8s-gateway` watches Ingress → creates the record), TLS (cert-manager ingress-shim). Access limited to the **Zigbee2MQTT Managers** group (`k.renner`).
## Verified
`kubectl kustomize` builds all 3 dirs; `--dry-run=server` clean; the embedded blueprint YAML parses with the new 5-entry block.
After merge: Authentik reconciles the blueprint (~minutes) and spawns the outpost; then `https://zigbee2mqtt.home.renner.uno` prompts the passkey step-up and proxies the frontend.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Gate zigbee2mqtt.home.renner.uno behind the same passkey-step-up Authentik
proxy-outpost pattern used for esphome/shelly-manager/vscode. The Z2M frontend
has no auth of its own (anyone on :8080 controls the whole Zigbee network), so
Traefik only ever routes the hostname to a dedicated outpost that validates the
session before forwarding.
New:
- apps/home-assistant/zigbee2mqtt-gate-service.yaml — ExternalName mirror to
ak-outpost-zigbee2mqtt-gate in the authentik ns (:9000).
- apps/home-assistant/zigbee2mqtt-ingress.yaml — zigbee2mqtt.home.renner.uno →
the outpost; cert-manager ingress-shim issues zigbee2mqtt-tls.
- apps/authentik/zigbee2mqtt-gate-egress.yaml — CNP letting the outpost egress
to the zigbee2mqtt pod on :8080.
Edited:
- apps/authentik/blueprints-configmap.yaml — 5-entry blueprint block (group /
proxyprovider / application / policybinding / outpost) named zigbee2mqtt-gate;
internal_host carries the explicit :8080 (Service listens on 8080, unlike
esphome's :80). Authentik spawns the ak-outpost-zigbee2mqtt-gate Deployment
+Service from the outpost entry.
- infrastructure/network-policies/home-assistant-ns.yaml — fromEndpoints rule
admitting the zigbee2mqtt-gate outpost to :8080 (shared 8080 with vscode/
shelly-manager; the fromEndpoints selector + the authentik-side egress scope
it to the zigbee2mqtt pod).
- the two kustomizations registering the new files.
DNS (k8s-gateway watches Ingress) and TLS (cert-manager) are automatic. Access
limited to the "Zigbee2MQTT Managers" group (k.renner). Verified: kustomize
builds, dry-run OK, blueprint YAML parses with the new block.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🤖Automated review — model claude-opus-4-8 (complexity: complex), commit de402ba531ffe2e34f213e89f3344b730e689acf.
Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.
Summary
This PR exposes the Zigbee2MQTT frontend at zigbee2mqtt.home.renner.uno behind
a dedicated Authentik proxy-outpost, faithfully reproducing the existing esphome-gate / shelly-manager-gate / vscode-gate pattern (ExternalName
mirror Service → outpost, Ingress, blueprint block, and paired Cilium
ingress/egress rules). I cross-checked every changed file against the
established patterns and the live Z2M Deployment/Service, and it is correct and
internally consistent. No blocking issues.
🟡 Suggestions
Shared :8080 blast radius (documented, but worth flagging). The new fromEndpoints grant in home-assistant-ns.yaml:84-91 sits on the endpointSelector: {} default-deny, so it admits the zigbee2mqtt-gate
outpost to every:8080 pod in the namespace — that now includes
code-server and shelly-manager, not just Z2M. The real scoping lives on the
authentik side in zigbee2mqtt-gate-egress.yaml:14-22, which correctly
restricts egress to app.kubernetes.io/name: zigbee2mqtt. This is the same
acknowledged trade-off the file already carries for vscode/shelly, and the
comment explains it well, so nothing is wrong — but the security guarantee
rests entirely on the egress CNP staying in place. If you ever want
defense-in-depth, the ingress side could be tightened with an app.kubernetes.io/name: zigbee2mqtt selector on a dedicated
(non-{}) policy, the way home-assistant-rotator-ingress does at home-assistant-ns.yaml:356-373. Optional.
Outpost → Z2M :8080 reachability depends on the baseline authentik CNP for
DNS/authentik-server egress.zigbee2mqtt-gate-egress.yaml only adds the
home-assistant :8080 egress rule (mirroring esphome), relying on a baseline
authentik-namespace policy to permit DNS resolution of zigbee2mqtt.home-assistant.svc.cluster.local and the callback to authentik-server. Since the identical esphome outpost works with this exact
shape, this is almost certainly fine — noting it only as the one thing to
confirm if the outpost 302-loops or can't resolve its internal_host
post-deploy.
🟢 Nits
internal_host correctly carries the explicit :8080
(blueprints-configmap.yaml:45) — matching the Z2M Service port
(zigbee2mqtt-service.yaml:11), unlike esphome's implicit :80. The inline
comment already calls this out; good catch by the author, since dropping the
port would have silently sent the outpost to :80 and failed.
Tests
No automated tests accompany this change, which is consistent with the rest of
this GitOps repo (declarative Kubernetes manifests; no test harness in-tree).
The PR body states kubectl kustomize builds all three dirs and --dry-run=server is clean. The meaningful verification here is runtime and
manual: after Authentik reconciles the blueprint, confirm (1) the ak-outpost-zigbee2mqtt-gate Deployment/Service spawn in the authentik ns,
(2) https://zigbee2mqtt.home.renner.uno prompts the passkey step-up and
proxies the frontend, and (3) the live-state websocket survives the gate (the credentials:'omit' service-worker 302-loop failure mode the author already
notes at blueprints-configmap.yaml:52-57).
Recommendation
Looks reasonable — no blocking issues; comments above are optional.
🤖 **Automated review** — model `claude-opus-4-8` (complexity: complex), commit `de402ba531ffe2e34f213e89f3344b730e689acf`.
> Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review.
---
## Summary
This PR exposes the Zigbee2MQTT frontend at `zigbee2mqtt.home.renner.uno` behind
a dedicated Authentik proxy-outpost, faithfully reproducing the existing
`esphome-gate` / `shelly-manager-gate` / `vscode-gate` pattern (ExternalName
mirror Service → outpost, Ingress, blueprint block, and paired Cilium
ingress/egress rules). I cross-checked every changed file against the
established patterns and the live Z2M Deployment/Service, and it is correct and
internally consistent. No blocking issues.
## 🟡 Suggestions
- **Shared `:8080` blast radius (documented, but worth flagging).** The new
`fromEndpoints` grant in `home-assistant-ns.yaml:84-91` sits on the
`endpointSelector: {}` default-deny, so it admits the `zigbee2mqtt-gate`
outpost to *every* `:8080` pod in the namespace — that now includes
code-server and shelly-manager, not just Z2M. The real scoping lives on the
authentik side in `zigbee2mqtt-gate-egress.yaml:14-22`, which correctly
restricts egress to `app.kubernetes.io/name: zigbee2mqtt`. This is the same
acknowledged trade-off the file already carries for vscode/shelly, and the
comment explains it well, so nothing is *wrong* — but the security guarantee
rests entirely on the egress CNP staying in place. If you ever want
defense-in-depth, the ingress side could be tightened with an
`app.kubernetes.io/name: zigbee2mqtt` selector on a dedicated
(non-`{}`) policy, the way `home-assistant-rotator-ingress` does at
`home-assistant-ns.yaml:356-373`. Optional.
- **Outpost → Z2M `:8080` reachability depends on the baseline authentik CNP for
DNS/authentik-server egress.** `zigbee2mqtt-gate-egress.yaml` only adds the
home-assistant `:8080` egress rule (mirroring esphome), relying on a baseline
authentik-namespace policy to permit DNS resolution of
`zigbee2mqtt.home-assistant.svc.cluster.local` and the callback to
`authentik-server`. Since the identical esphome outpost works with this exact
shape, this is almost certainly fine — noting it only as the one thing to
confirm if the outpost 302-loops or can't resolve its `internal_host`
post-deploy.
## 🟢 Nits
- `internal_host` correctly carries the explicit `:8080`
(`blueprints-configmap.yaml:45`) — matching the Z2M Service port
(`zigbee2mqtt-service.yaml:11`), unlike esphome's implicit `:80`. The inline
comment already calls this out; good catch by the author, since dropping the
port would have silently sent the outpost to `:80` and failed.
## Tests
No automated tests accompany this change, which is consistent with the rest of
this GitOps repo (declarative Kubernetes manifests; no test harness in-tree).
The PR body states `kubectl kustomize` builds all three dirs and
`--dry-run=server` is clean. The meaningful verification here is runtime and
manual: after Authentik reconciles the blueprint, confirm (1) the
`ak-outpost-zigbee2mqtt-gate` Deployment/Service spawn in the authentik ns,
(2) `https://zigbee2mqtt.home.renner.uno` prompts the passkey step-up and
proxies the frontend, and (3) the live-state websocket survives the gate (the
`credentials:'omit'` service-worker 302-loop failure mode the author already
notes at `blueprints-configmap.yaml:52-57`).
## Recommendation
Looks reasonable — no blocking issues; comments above are optional.
<!-- pr-review:sha=de402ba531ffe2e34f213e89f3344b730e689acf -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Exposes the Z2M web UI behind the same passkey-gated Authentik proxy-outpost pattern as
esphome/shelly-manager/vscode. The frontend has no auth of its own, so Traefik only routes the hostname to a dedicated outpost that validates the session first.New files
apps/home-assistant/zigbee2mqtt-gate-service.yaml— ExternalName →ak-outpost-zigbee2mqtt-gate(authentik ns, :9000)apps/home-assistant/zigbee2mqtt-ingress.yaml—zigbee2mqtt.home.renner.uno→ outpost;zigbee2mqtt-tlsauto-issued by cert-managerapps/authentik/zigbee2mqtt-gate-egress.yaml— CNP: outpost →app.kubernetes.io/name: zigbee2mqtton :8080Edits
apps/authentik/blueprints-configmap.yaml— 5-entry blueprint block (group / proxy provider / application / policy binding / outpost) namedzigbee2mqtt-gate.internal_hostincludes the explicit :8080 (Service listens on 8080, not esphome's :80). Authentik spawns theak-outpost-zigbee2mqtt-gateDeployment+Service from this.infrastructure/network-policies/home-assistant-ns.yaml—fromEndpointsrule admitting the outpost to :8080. Note: shared :8080 with vscode/shelly-manager — thefromEndpointsselector + the authentik-side egress scope it to the zigbee2mqtt pod.Automatic / no action
DNS (
k8s-gatewaywatches Ingress → creates the record), TLS (cert-manager ingress-shim). Access limited to the Zigbee2MQTT Managers group (k.renner).Verified
kubectl kustomizebuilds all 3 dirs;--dry-run=serverclean; the embedded blueprint YAML parses with the new 5-entry block.After merge: Authentik reconciles the blueprint (~minutes) and spawns the outpost; then
https://zigbee2mqtt.home.renner.unoprompts the passkey step-up and proxies the frontend.🤖 Generated with Claude Code
Gate zigbee2mqtt.home.renner.uno behind the same passkey-step-up Authentik proxy-outpost pattern used for esphome/shelly-manager/vscode. The Z2M frontend has no auth of its own (anyone on :8080 controls the whole Zigbee network), so Traefik only ever routes the hostname to a dedicated outpost that validates the session before forwarding. New: - apps/home-assistant/zigbee2mqtt-gate-service.yaml — ExternalName mirror to ak-outpost-zigbee2mqtt-gate in the authentik ns (:9000). - apps/home-assistant/zigbee2mqtt-ingress.yaml — zigbee2mqtt.home.renner.uno → the outpost; cert-manager ingress-shim issues zigbee2mqtt-tls. - apps/authentik/zigbee2mqtt-gate-egress.yaml — CNP letting the outpost egress to the zigbee2mqtt pod on :8080. Edited: - apps/authentik/blueprints-configmap.yaml — 5-entry blueprint block (group / proxyprovider / application / policybinding / outpost) named zigbee2mqtt-gate; internal_host carries the explicit :8080 (Service listens on 8080, unlike esphome's :80). Authentik spawns the ak-outpost-zigbee2mqtt-gate Deployment +Service from the outpost entry. - infrastructure/network-policies/home-assistant-ns.yaml — fromEndpoints rule admitting the zigbee2mqtt-gate outpost to :8080 (shared 8080 with vscode/ shelly-manager; the fromEndpoints selector + the authentik-side egress scope it to the zigbee2mqtt pod). - the two kustomizations registering the new files. DNS (k8s-gateway watches Ingress) and TLS (cert-manager) are automatic. Access limited to the "Zigbee2MQTT Managers" group (k.renner). Verified: kustomize builds, dry-run OK, blueprint YAML parses with the new block. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>🤖 Automated review — model
claude-opus-4-8(complexity: complex), commitde402ba531ffe2e34f213e89f3344b730e689acf.Summary
This PR exposes the Zigbee2MQTT frontend at
zigbee2mqtt.home.renner.unobehinda dedicated Authentik proxy-outpost, faithfully reproducing the existing
esphome-gate/shelly-manager-gate/vscode-gatepattern (ExternalNamemirror Service → outpost, Ingress, blueprint block, and paired Cilium
ingress/egress rules). I cross-checked every changed file against the
established patterns and the live Z2M Deployment/Service, and it is correct and
internally consistent. No blocking issues.
🟡 Suggestions
Shared
:8080blast radius (documented, but worth flagging). The newfromEndpointsgrant inhome-assistant-ns.yaml:84-91sits on theendpointSelector: {}default-deny, so it admits thezigbee2mqtt-gateoutpost to every
:8080pod in the namespace — that now includescode-server and shelly-manager, not just Z2M. The real scoping lives on the
authentik side in
zigbee2mqtt-gate-egress.yaml:14-22, which correctlyrestricts egress to
app.kubernetes.io/name: zigbee2mqtt. This is the sameacknowledged trade-off the file already carries for vscode/shelly, and the
comment explains it well, so nothing is wrong — but the security guarantee
rests entirely on the egress CNP staying in place. If you ever want
defense-in-depth, the ingress side could be tightened with an
app.kubernetes.io/name: zigbee2mqttselector on a dedicated(non-
{}) policy, the wayhome-assistant-rotator-ingressdoes athome-assistant-ns.yaml:356-373. Optional.Outpost → Z2M
:8080reachability depends on the baseline authentik CNP forDNS/authentik-server egress.
zigbee2mqtt-gate-egress.yamlonly adds thehome-assistant
:8080egress rule (mirroring esphome), relying on a baselineauthentik-namespace policy to permit DNS resolution of
zigbee2mqtt.home-assistant.svc.cluster.localand the callback toauthentik-server. Since the identical esphome outpost works with this exactshape, this is almost certainly fine — noting it only as the one thing to
confirm if the outpost 302-loops or can't resolve its
internal_hostpost-deploy.
🟢 Nits
internal_hostcorrectly carries the explicit:8080(
blueprints-configmap.yaml:45) — matching the Z2M Service port(
zigbee2mqtt-service.yaml:11), unlike esphome's implicit:80. The inlinecomment already calls this out; good catch by the author, since dropping the
port would have silently sent the outpost to
:80and failed.Tests
No automated tests accompany this change, which is consistent with the rest of
this GitOps repo (declarative Kubernetes manifests; no test harness in-tree).
The PR body states
kubectl kustomizebuilds all three dirs and--dry-run=serveris clean. The meaningful verification here is runtime andmanual: after Authentik reconciles the blueprint, confirm (1) the
ak-outpost-zigbee2mqtt-gateDeployment/Service spawn in the authentik ns,(2)
https://zigbee2mqtt.home.renner.unoprompts the passkey step-up andproxies the frontend, and (3) the live-state websocket survives the gate (the
credentials:'omit'service-worker 302-loop failure mode the author alreadynotes at
blueprints-configmap.yaml:52-57).Recommendation
Looks reasonable — no blocking issues; comments above are optional.