Radius Database¶
One database per environment (radius-<env>) on the shared RDB instance. It holds the stock FreeRADIUS schema plus the tables the control plane adds for tenancy, admin authorization, and PKI. The schema is applied by the ordered scripts in db/radius/ (01…09) on a fresh database.
| Script | Adds |
|---|---|
01-schema.sql |
Stock FreeRADIUS tables: radcheck, radreply, radgroupcheck, radgroupreply, radusergroup, radacct, radpostauth, nas, nasreload. |
02-tenancy.sql |
organizations (the tenant table) + a nullable org_id column on the FreeRADIUS tables. |
03-seed.sql |
A seed org acme, a test user (bob/hello) and a loopback NAS — the radtest smoke-test fixture. Optional. |
04-auth.sql |
org_memberships (admin authorization). Grants are keyed by the Zitadel sub; there is no local account table. |
05-radacct-org-trigger.sql |
Trigger that stamps org_id onto radacct rows from the NAS, so accounting tenancy can't be spoofed. |
06-drop-nas-ports.sql |
Drops the unused nas.ports column. |
07-pki.sql |
certificate_authorities, client_certificates. |
08-users.sql |
radius_users — first-class per-org end-user identities — and a user_id FK on client_certificates. |
09-drop-local-auth.sql |
Drops local_users. Admin identity is Zitadel only: a membership is a sub and nothing else. |
Ownership¶
- FreeRADIUS reads
radcheck/radreply/nas(auth) and writesradacct/radpostauth(accounting). It only ever sees rows for the requesting NAS'sorg_id. - The control-plane API owns everything else: it creates orgs, manages NAS clients and
radius_users, sets passwords (asradcheckCleartext-Passwordrows), records admin grants inorg_memberships, and runs the PKI tables.
Tenancy columns¶
org_id uuid (nullable, REFERENCES organizations(id)) on the shared FreeRADIUS tables. Nullable so the stock schema still works, but the org-scoped auth queries treat a non-matching or NULL org_id as no match (fail-closed). org_memberships.org_id is instead nullable-as-platform-scope: NULL there means a platform-wide admin grant.
End users vs. admins¶
Two distinct populations, never mixed:
radius_users— the WPA/captive-portal end users, per org (UNIQUE (org_id, username)), withsource=local | ldap | oidc | …. Auth methods attach to them: a password (radcheck) and/or a client certificate (client_certificates.user_id).org_memberships— the humans who administer an org through the control plane, keyed by their Zitadelsub.