Setup page for the 802.1X WLAN "Renner UniFi" (cluster FreeRADIUS, EAP-TTLS/PAP, authentik credentials).
kubernetes/apps/authentik/wlan-setup.yaml: nginx (house image nginx-unprivileged:1.31-alpine, pinned digest), Service, Ingress wlan.renner.uno — public (Cloudflare → NetBird → Traefik) so a device can reach it before it is in the WLAN; Authentik gate, no group (the page holds no secrets).
kubernetes/apps/authentik/wlan-setup-config.yaml: nginx config, page, Windows file.
Apple: /renner-unifi.mobileconfig, com.apple.wifi.managed, TTLS (21) + inner PAP, outer identity anonymous, trusted server name radius.renner.uno, UserName from X-authentik-username. Fixed payload identifiers/UUIDs, so a reinstall replaces it.
Windows: /renner-unifi-wlan.cmd writes the WLAN profile after line 8 of itself to %TEMP%, imports it with netsh wlan add profile … user=current, then connects. EAP-TTLS with PAPAuthentication, anonymous, ServerNames radius.renner.uno, TrustedRootCAHash = ISRG Root X1 (the radius-tls chain is radius.renner.uno ← YR2 ← Root YR ← ISRG Root X1). CRLF line endings.
Linux: nmcli command with the username, 802-1x.system-ca-certs yes, domain-suffix-match radius.renner.uno, password agent-owned.
Android: not on the page — no native import path without Passpoint or an app.
Usernames outside [A-Za-z0-9._@+-]{1,64} are left blank rather than written into a generated file.
No file carries a password.
docs/radius/dot1x.md: client setup now for "Renner UniFi" with the page; obsolete renner-test.mobileconfig removed (SSID gone).
Checked: local run of the pinned image with the extracted ConfigMap files — /, /whoami (header, and a markup username → empty), /renner-unifi.mobileconfig (200, application/x-apple-aspen-config, well-formed, username filled), /renner-unifi-wlan.cmd (CRLF, embedded profile well-formed); nmcli --offline accepts the command; server-side dry-run of all objects.
Setup page for the 802.1X WLAN "Renner UniFi" (cluster FreeRADIUS, EAP-TTLS/PAP, authentik credentials).
- `kubernetes/apps/authentik/wlan-setup.yaml`: nginx (house image `nginx-unprivileged:1.31-alpine`, pinned digest), Service, Ingress `wlan.renner.uno` — public (Cloudflare → NetBird → Traefik) so a device can reach it before it is in the WLAN; Authentik gate, no group (the page holds no secrets).
- `kubernetes/apps/authentik/wlan-setup-config.yaml`: nginx config, page, Windows file.
- **Apple**: `/renner-unifi.mobileconfig`, `com.apple.wifi.managed`, TTLS (21) + inner PAP, outer identity `anonymous`, trusted server name `radius.renner.uno`, `UserName` from `X-authentik-username`. Fixed payload identifiers/UUIDs, so a reinstall replaces it.
- **Windows**: `/renner-unifi-wlan.cmd` writes the WLAN profile after line 8 of itself to `%TEMP%`, imports it with `netsh wlan add profile … user=current`, then connects. EAP-TTLS with `PAPAuthentication`, `anonymous`, `ServerNames radius.renner.uno`, `TrustedRootCAHash` = ISRG Root X1 (the `radius-tls` chain is radius.renner.uno ← YR2 ← Root YR ← ISRG Root X1). CRLF line endings.
- **Linux**: `nmcli` command with the username, `802-1x.system-ca-certs yes`, `domain-suffix-match radius.renner.uno`, password agent-owned.
- **Android**: not on the page — no native import path without Passpoint or an app.
- Usernames outside `[A-Za-z0-9._@+-]{1,64}` are left blank rather than written into a generated file.
- No file carries a password.
- `docs/radius/dot1x.md`: client setup now for "Renner UniFi" with the page; obsolete `renner-test.mobileconfig` removed (SSID gone).
Checked: local run of the pinned image with the extracted ConfigMap files — `/`, `/whoami` (header, and a markup username → empty), `/renner-unifi.mobileconfig` (200, `application/x-apple-aspen-config`, well-formed, username filled), `/renner-unifi-wlan.cmd` (CRLF, embedded profile well-formed); `nmcli --offline` accepts the command; server-side dry-run of all objects.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
nginx behind the Authentik gate (any user, public) serving:
- Apple profile (TTLS/PAP, outer identity anonymous, trusted server name
radius.renner.uno) with the caller's username from X-authentik-username,
- a Windows .cmd that imports the WLAN profile via netsh (TTLS/PAP, server
name radius.renner.uno, trust anchor ISRG Root X1),
- the Linux nmcli command.
No file carries a password. Usernames outside [A-Za-z0-9._@+-] are left
blank instead of being put into a generated file.
The Renner Test profile is removed; that SSID no longer exists.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
k.renner
requested review from review-bot 2026-11-05 08:57:58 +00:00
🤖Automated review — model claude-opus-5-5, commit 1e66d793d5945e547d39be144b0adb4a12334e60.
Automated review by the review-bot: it approves only when it found nothing red or yellow, and a human still merges. Request a review from review-bot again for a fresh one.
Summary
This PR adds the wlan-setup nginx Deployment, Service and gated public Ingress at wlan.renner.uno. The page serves an Apple profile with the caller's username filled in, a Windows netsh import file and an nmcli command for "Renner UniFi". It also points dot1x.md at the page and removes the old renner-test.mobileconfig. I found no blocking issues:
The gate controller (ci/images/authentik-gate-sync/controller.py) builds an any-user provider and the Traefik→backend CNP from this Ingress as written.
The middleware strips X-authentik-* headers sent by the client, so $wifi_user cannot be spoofed.
The username regex keeps XML and shell metacharacters out of the generated files.
mergeable is true, no issue is linked, and no other open PR touches these files. I could not list base-branch commits per path because I have no commit-listing tool.
⚪ Unverified
Windows trust anchor:wlan-setup-config.yamlrenner-unifi-wlan.cmd pins TrustedRootCAHash to ISRG Root X1. That only works if Windows builds the radius-tls chain up to X1. The PR body describes the chain as ←YR2←Root YR←X1. If a Windows client already trusts Root YR as its own root, the chain stops there, the hash doesn't match, and the user gets a prompt or a failure (DisablePrompt is false). The PR's checks cover the XML being well-formed, not a real Windows join. I did not check how current Windows root stores handle the Gen-Y roots.
EapTtls element order: I could not confirm that netsh accepts the element order inside ServerValidation (ServerNames, TrustedRootCAHash, DisablePrompt). I had no schema or Windows test to check against.
🟡 Suggestions
Reloader annotation is in the wrong place:kubernetes/apps/authentik/wlan-setup.yaml:22-23 puts configmap.reloader.stakater.com/reload: wlan-setup on the pod template. The repo convention (freeradius.yaml:9-11) puts it on the Deployment's metadata.annotations, which is where Reloader looks.
index.html and the .cmd file are mounted without subPath, so they still update in place.
default.conf holds the whole mobileconfig and the map, and nginx only reads it at startup. Edits to the Apple profile or the username regex won't take effect until someone restarts the pod by hand.
Fix: move the annotation up to the Deployment metadata.
Image updates:wlan-setup.yaml:34 pins a digest but has no $imagepolicy marker. Other images in this directory (e.g. freeradius.yaml) use one. Unless something else (e.g. Renovate) updates digests here, this image won't get updated. Worth adding a policy or noting who bumps it.
🟢 Nits
docs/radius/dot1x.md:150-152 and :200-202: the reflowed paragraphs have lines much longer than the surrounding ~78-column wrap.
docs/radius/dot1x.md Apple section: it says "Install it via Settings (Profile Downloaded)", which is the iOS flow. The page itself gives the macOS path as well.
Tests
There are no automated tests, which is normal for manifests in this repo. The PR describes a local run of the pinned image, an nmcli --offline check and a server-side dry-run. What's still missing is an actual Windows and Apple join against radius.renner.uno, which would also settle the trust-anchor question above.
Recommendation
Looks reasonable — no blocking issues; comments above are optional.
🤖 **Automated review** — model `claude-opus-5-5`, commit `1e66d793d5945e547d39be144b0adb4a12334e60`.
> Automated review by the `review-bot`: it approves only when it found nothing red or yellow, and a human still merges. Request a review from `review-bot` again for a fresh one.
---
## Summary
This PR adds the `wlan-setup` nginx Deployment, Service and gated public Ingress at `wlan.renner.uno`. The page serves an Apple profile with the caller's username filled in, a Windows `netsh` import file and an `nmcli` command for "Renner UniFi". It also points `dot1x.md` at the page and removes the old `renner-test.mobileconfig`. I found no blocking issues:
- The gate controller (`ci/images/authentik-gate-sync/controller.py`) builds an any-user provider and the Traefik→backend CNP from this Ingress as written.
- The middleware strips `X-authentik-*` headers sent by the client, so `$wifi_user` cannot be spoofed.
- The username regex keeps XML and shell metacharacters out of the generated files.
`mergeable` is true, no issue is linked, and no other open PR touches these files. I could not list base-branch commits per path because I have no commit-listing tool.
## ⚪ Unverified
- **Windows trust anchor:** `wlan-setup-config.yaml` `renner-unifi-wlan.cmd` pins `TrustedRootCAHash` to ISRG Root X1. That only works if Windows builds the `radius-tls` chain up to X1. The PR body describes the chain as ←YR2←Root YR←X1. If a Windows client already trusts Root YR as its own root, the chain stops there, the hash doesn't match, and the user gets a prompt or a failure (`DisablePrompt` is false). The PR's checks cover the XML being well-formed, not a real Windows join. I did not check how current Windows root stores handle the Gen-Y roots.
- **EapTtls element order:** I could not confirm that `netsh` accepts the element order inside `ServerValidation` (`ServerNames`, `TrustedRootCAHash`, `DisablePrompt`). I had no schema or Windows test to check against.
## 🟡 Suggestions
- **Reloader annotation is in the wrong place:** `kubernetes/apps/authentik/wlan-setup.yaml:22-23` puts `configmap.reloader.stakater.com/reload: wlan-setup` on the pod template. The repo convention (`freeradius.yaml:9-11`) puts it on the Deployment's `metadata.annotations`, which is where Reloader looks.
- `index.html` and the `.cmd` file are mounted without `subPath`, so they still update in place.
- `default.conf` holds the whole mobileconfig and the `map`, and nginx only reads it at startup. Edits to the Apple profile or the username regex won't take effect until someone restarts the pod by hand.
- Fix: move the annotation up to the Deployment metadata.
- **Image updates:** `wlan-setup.yaml:34` pins a digest but has no `$imagepolicy` marker. Other images in this directory (e.g. `freeradius.yaml`) use one. Unless something else (e.g. Renovate) updates digests here, this image won't get updated. Worth adding a policy or noting who bumps it.
## 🟢 Nits
- `docs/radius/dot1x.md:150-152` and `:200-202`: the reflowed paragraphs have lines much longer than the surrounding ~78-column wrap.
- `docs/radius/dot1x.md` Apple section: it says "Install it via Settings (Profile Downloaded)", which is the iOS flow. The page itself gives the macOS path as well.
## Tests
There are no automated tests, which is normal for manifests in this repo. The PR describes a local run of the pinned image, an `nmcli --offline` check and a server-side dry-run. What's still missing is an actual Windows and Apple join against `radius.renner.uno`, which would also settle the trust-anchor question above.
## Recommendation
Looks reasonable — no blocking issues; comments above are optional.
<!-- pr-review:sha=1e66d793d5945e547d39be144b0adb4a12334e60 -->
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.
Setup page for the 802.1X WLAN "Renner UniFi" (cluster FreeRADIUS, EAP-TTLS/PAP, authentik credentials).
kubernetes/apps/authentik/wlan-setup.yaml: nginx (house imagenginx-unprivileged:1.31-alpine, pinned digest), Service, Ingresswlan.renner.uno— public (Cloudflare → NetBird → Traefik) so a device can reach it before it is in the WLAN; Authentik gate, no group (the page holds no secrets).kubernetes/apps/authentik/wlan-setup-config.yaml: nginx config, page, Windows file./renner-unifi.mobileconfig,com.apple.wifi.managed, TTLS (21) + inner PAP, outer identityanonymous, trusted server nameradius.renner.uno,UserNamefromX-authentik-username. Fixed payload identifiers/UUIDs, so a reinstall replaces it./renner-unifi-wlan.cmdwrites the WLAN profile after line 8 of itself to%TEMP%, imports it withnetsh wlan add profile … user=current, then connects. EAP-TTLS withPAPAuthentication,anonymous,ServerNames radius.renner.uno,TrustedRootCAHash= ISRG Root X1 (theradius-tlschain is radius.renner.uno ← YR2 ← Root YR ← ISRG Root X1). CRLF line endings.nmclicommand with the username,802-1x.system-ca-certs yes,domain-suffix-match radius.renner.uno, password agent-owned.[A-Za-z0-9._@+-]{1,64}are left blank rather than written into a generated file.docs/radius/dot1x.md: client setup now for "Renner UniFi" with the page; obsoleterenner-test.mobileconfigremoved (SSID gone).Checked: local run of the pinned image with the extracted ConfigMap files —
/,/whoami(header, and a markup username → empty),/renner-unifi.mobileconfig(200,application/x-apple-aspen-config, well-formed, username filled),/renner-unifi-wlan.cmd(CRLF, embedded profile well-formed);nmcli --offlineaccepts the command; server-side dry-run of all objects.🤖 Generated with Claude Code
🤖 Automated review — model
claude-opus-5-5, commit1e66d793d5945e547d39be144b0adb4a12334e60.Summary
This PR adds the
wlan-setupnginx Deployment, Service and gated public Ingress atwlan.renner.uno. The page serves an Apple profile with the caller's username filled in, a Windowsnetshimport file and annmclicommand for "Renner UniFi". It also pointsdot1x.mdat the page and removes the oldrenner-test.mobileconfig. I found no blocking issues:ci/images/authentik-gate-sync/controller.py) builds an any-user provider and the Traefik→backend CNP from this Ingress as written.X-authentik-*headers sent by the client, so$wifi_usercannot be spoofed.mergeableis true, no issue is linked, and no other open PR touches these files. I could not list base-branch commits per path because I have no commit-listing tool.⚪ Unverified
wlan-setup-config.yamlrenner-unifi-wlan.cmdpinsTrustedRootCAHashto ISRG Root X1. That only works if Windows builds theradius-tlschain up to X1. The PR body describes the chain as ←YR2←Root YR←X1. If a Windows client already trusts Root YR as its own root, the chain stops there, the hash doesn't match, and the user gets a prompt or a failure (DisablePromptis false). The PR's checks cover the XML being well-formed, not a real Windows join. I did not check how current Windows root stores handle the Gen-Y roots.netshaccepts the element order insideServerValidation(ServerNames,TrustedRootCAHash,DisablePrompt). I had no schema or Windows test to check against.🟡 Suggestions
kubernetes/apps/authentik/wlan-setup.yaml:22-23putsconfigmap.reloader.stakater.com/reload: wlan-setupon the pod template. The repo convention (freeradius.yaml:9-11) puts it on the Deployment'smetadata.annotations, which is where Reloader looks.index.htmland the.cmdfile are mounted withoutsubPath, so they still update in place.default.confholds the whole mobileconfig and themap, and nginx only reads it at startup. Edits to the Apple profile or the username regex won't take effect until someone restarts the pod by hand.wlan-setup.yaml:34pins a digest but has no$imagepolicymarker. Other images in this directory (e.g.freeradius.yaml) use one. Unless something else (e.g. Renovate) updates digests here, this image won't get updated. Worth adding a policy or noting who bumps it.🟢 Nits
docs/radius/dot1x.md:150-152and:200-202: the reflowed paragraphs have lines much longer than the surrounding ~78-column wrap.docs/radius/dot1x.mdApple section: it says "Install it via Settings (Profile Downloaded)", which is the iOS flow. The page itself gives the macOS path as well.Tests
There are no automated tests, which is normal for manifests in this repo. The PR describes a local run of the pinned image, an
nmcli --offlinecheck and a server-side dry-run. What's still missing is an actual Windows and Apple join againstradius.renner.uno, which would also settle the trust-anchor question above.Recommendation
Looks reasonable — no blocking issues; comments above are optional.