PPSK via RADIUS — live validation runbook
Status: the subsystem is built and unit-tested; this runbook is the live-validation pass. Everything in PPSK via RADIUS — design is implemented: the sealed
ManagePpskUserpipeline, the agent’s encrypted PPSK store, the gateway key CRUD + REST, the web UI, and the FreeRADIUS provisioner. Two things can only be confirmed against real hardware + a real client, so they live here, not in CI:
- the end-to-end auth path (an AP forwards a Private PSK to FreeRADIUS, gets Access-Accept + the VLAN);
- the exact Aerohive user-profile VSA for returning a named user-profile on Accept (the design’s last open question — the RFC VLAN tunnel attributes are already emitted; the VSA is currently a documented comment in the generated authorize file).
Until this pass completes, PPSK Caminho B ships “untested”, exactly like firmware upgrade.
Prerequisites
- The lab AP230 (
192.168.1.101,admin/Aerohive1) on the same LAN as the agent host. - Podman on the agent host (the dev box has it;
dockerusers substitutedocker). - A throwaway security-object / SSID — never the production one. PPSK-via-RADIUS changes an SSID’s authentication path; a misconfig can lock out live clients. This mirrors the firmware-upgrade caution.
- A Wi-Fi client (phone/laptop) to associate with a per-user PSK.
1. Stand up FreeRADIUS co-located with the agent
powershell -File scripts/dev-radius.ps1 -Secret testing123# note the RadiusDir it prints, then run the agent pointed at it:$env:HIVEKEEPER_PPSK_STORE = "<RadiusDir>\ppsk.properties"$env:HIVEKEEPER_RADIUS_DIR = "<RadiusDir>"$env:HIVEKEEPER_VAULT_KEY = "<base64 AES-256>" # encrypts the PPSK store at restThe agent’s FilePpskUserStore writes <RadiusDir>\authorize (FreeRADIUS files module) on every
create/rotate/revoke; FreeRadiusFilesProvisioner renders it. On the Windows dev box re-sync after a mutation
with scripts/dev-radius.ps1 -Reload (re-copies the file and HUPs the server); on Linux bind-mount the dir and
just podman kill -s HUP hivekeeper-radius.
Confirmed live (server side): the
authorizeformatFreeRadiusFilesProvisioneremits was validated against FreeRADIUS 3.2 —radtest <user> <psk> 127.0.0.1 0 <secret>returns Access-Accept withTunnel-Type=VLAN/Tunnel-Medium-Type=IEEE-802/Tunnel-Private-Group-Id=<vlan>, and a wrong PSK returns Access-Reject. So PAP-match-of-the-PSK + the RFC-2868 VLAN reply work end-to-end on the RADIUS server; what step 4 still confirms is the AP↔RADIUS half and the Aerohive VSA.Gotchas the dev script already handles (don’t hand-roll the container): the daemon binary is
/usr/sbin/freeradius(notradiusd); FreeRADIUS refuses a globally-writable config (Windows bind-mounts are 0777 — the scriptcps +chmod o-ws instead); and config/authorize files must be written without a UTF-8 BOM (PowerShell’sSet-Content -Encoding utf8adds one and FreeRADIUS won’t parse it — the agent writes BOM-free).
Networking note (Windows + Podman): the AP must reach the host’s
1812/udp. Find the host’s LAN IP withFind-NetRoute -RemoteIPAddress <ap-ip>. With a WSL2-backed Podman, inbound LAN traffic to a published port is not reachable by default — allow1812/udpthrough Windows Firewall and confirm the port is forwarded into the Podman machine (or run FreeRADIUS where the AP can route to it).radtestfrom the host validates the server regardless of this.
2. Point the throwaway security-object at RADIUS (apply + revert, non-persistent)
All grammar below is already confirmed live (see the design doc). Apply against a test SO:
aaa ppsk-server radius-server primary <agent-ip> shared-secret testing123security-object HKB security private-psksecurity-object HKB security private-psk radius-auth papssid HKB user-group ppsk-usersDrive this from HiveKeeper’s PPSK via RADIUS block (Wi-Fi section) — it emits exactly these lines through
apply-config. Do not save; revert at the end with the no … forms.
3. Mint a user from HiveKeeper and connect a client
- In the device’s PPSK users tab, mint a user (security object
HKB, a username, VLAN if testing VLANs). Copy the one-time PSK shown. - Confirm the agent wrote it:
<RadiusDir>\authorizenow has<username> Cleartext-Password := "<psk>"(+ theTunnel-*block if a VLAN was set).podman kill -s HUP hivekeeper-radius. - Associate the client to the
HKBSSID using that PSK.
4. Capture the real exchange (this is what fills the last unknown)
With the client associating, watch FreeRADIUS and capture the Access-Request/Accept:
podman exec -it hivekeeper-radius radiusd -X # or: podman logs -f hivekeeper-radius# in another shell, a controlled check:podman exec -it hivekeeper-radius radtest <username> <psk> 127.0.0.1 0 testing123Record, for the design doc + the provisioner:
- Does PAP match? The AP should send the submitted PSK as the User-Password; FreeRADIUS matches
Cleartext-Passwordand returns Access-Accept. If the AP uses CHAP/MS-CHAP-v2 instead, switchradius-authto match and note it. - The VLAN reply — confirm the AP honours
Tunnel-Private-Group-Id(the client lands on the VLAN). - The Aerohive user-profile VSA — if returning a named user-profile (not just a VLAN) is required,
capture the exact VSA name/number the AP expects on Accept (e.g. from
radiusd -Xdecoding an Accept the AP accepts, or Aerohive/Extreme dictionary docs). This is the value to wire intoFreeRadiusFilesProvisioner— it is currently emitted only as a comment.
5. Rotate, revoke, and revert
- Rotate the user in the UI → confirm the client must re-key with the new PSK (old one rejected after HUP).
- Revoke → confirm the user disappears from
authorizeand the client is dropped / cannot re-auth. - Revert the AP:
no security-object HKB security private-psk radius-auth,no aaa ppsk-server radius-server primary, and remove the throwaway SO — non-persistent, nosave.
6. Promote out of “untested”
Once the Access-Accept + VLAN are confirmed and the Aerohive VSA is captured and wired in:
- update
FreeRadiusFilesProvisionerto emit the confirmed VSA (replacing the comment), with a unit test pinning the rendered line; - record the captured grammar in PPSK via RADIUS — design → Open questions;
- flip the capabilities/roadmap note from “untested” to “live-confirmed”.