Outer identity anonymous[@realm] (any case) keeps the local EAP-TTLS -> authentik path. Any other outer identity is a UniFi Endpoint account: the outer server proxies every EAP round to new home server udm (10.2.47.1:1812, UDM_RADIUS_SECRET) without local EAP processing; post-proxy/post-auth leave UDM replies untouched. Endpoint account names look like ordinary usernames, so routing keys on the anonymous identity, not a name pattern. home_server udm: response_window 5 < proxy_dedup_window 10, require_message_authenticator yes (RFC 3579, EAP replies), status_check request with a user name that cannot exist. CNP freeradius-udm-egress allows only 10.2.47.1/32 UDP 1812. Harness: mock_udm.py on a second internal bridge at the udm address from proxy.conf. Asserts both EAP rounds (State included) reach it, its Accept reaches the NAS with Tunnel-* VLAN 200 and MS-MPPE keys intact, its Reject passes, and anonymous logins and accounting never reach it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FreeRADIUS functional test
tests/radius/run.sh
Runs the production FreeRADIUS config from
kubernetes/apps/authentik/freeradius-config.yaml (rendered through the
projected volume in freeradius.yaml, same image, args and secret env names)
in Docker against a mock authentik outpost and a mock UDM RADIUS, and drives
it with eapol_test (EAP-TTLS, inner PAP) as a NAS in the test client ranges
10.2.50.0/24 and fd02:50::/64. The v6 cases (v6-*) hit the IPv6
listeners and client test6. Cases use outer identity anonymous unless
noted.
| Case | Expected |
|---|---|
vlan-tunnel (outpost sends Tunnel-* and Cisco-AV-Pair) |
SUCCESS, Tunnel-* VLAN 50, no Cisco-AV-Pair |
vlan-avpair (outpost sends only Cisco-AV-Pair = "dot1x-vlan=50") |
SUCCESS, Tunnel-* VLAN 50, no Cisco-AV-Pair |
novlan (Accept without VLAN) |
FAILURE (Access-Reject) |
| wrong password / unknown user (Reject without Message-Authenticator) | FAILURE (Access-Reject) within 1 s |
| Accounting-Request | answered locally, nothing sent to the outpost or the UDM |
anon-realm (outer identity Anonymous@Example.Org) |
local TTLS, as vlan-tunnel |
udm-accept, v6-udm-accept (outer identity = account name) |
both EAP rounds reach the mock UDM (second with its State); its Access-Accept reaches the NAS with Tunnel-* VLAN 200 and MS-MPPE keys unchanged |
udm-reject |
the mock UDM's Access-Reject reaches the NAS within 1 s |
all anonymous cases |
never reach the mock UDM |
recovery |
outpost stalls until marked dead, then returns: login succeeds within 20 s |
Pieces:
mock_outpost.py: stand-in outpost on UDP 1812, reachable under the outpost Service FQDN through a Docker network alias.mock_udm.py: stand-in UDM RADIUS at theudmhome server address fromproxy.conf, on a second internal bridgeradtest-udm(that address's /24, no host address). Answers round 1 with Challenge +State+ EAP-TTLS Start (or Reject forendpoint-reject), round 2 with Accept + EAP-Success; terminates no EAP.eapol.Dockerfile:eapol_testfrom Debianeapoltest.- Docker network
radtest: internal bridge on10.2.50.0/24andfd02:50::/64with no host address (inhibit_ipv4,gateway_mode_ipv6=isolated), so the workstation LAN routes are untouched.
Requires Docker, openssl and yq (the jq wrapper). Secrets, password and
certificates are generated dummies. RADTEST_DEBUG=1 runs radiusd with -xx
and prints all logs. Containers, network and temp files are removed on exit.