[freeradius] 1.1.0 modernization (Gateway API, modules, Keycloak, metrics)#122
Merged
Conversation
End-to-end rework matching the adminer 1.0.0 playbook, adapted for RADIUS
traffic. See charts/freeradius/CHANGELOG.md and README §Upgrading for the
full diff and migration steps.
Highlights:
- values.yaml restructured with section banners; template subdirs lowercased
(Istio/→istio/, ConfigMap/→configmap/, Secret/→secret/); _helpers/
consolidated into a single _helpers.tpl with dotted-namespace helpers
(freeradius.tls.*, freeradius.sql.tls.*, freeradius.gateway.*,
freeradius.mariadb.*, freeradius.metrics.*).
- TLS architecture unified under tls.certManager.* + a shared self-signed CA
helper (lookup-or-generate, persists across upgrades and across in-pod ↔
gateway path migrations); gateway.tls.{enabled,existingSecret,selfSigned,
secrets} for gateway-side TLS.
- Gateway API stack adapted for RADIUS: UDPRoute for auth/acct/coa, TLSRoute
for RADSEC passthrough, plus ReferenceGrant and ListenerSet. Istio path
(Gateway + VirtualService) reworked off ingress.* into gateway.hostnames.
- HorizontalPodAutoscaler.yaml, ServiceMonitor, PrometheusRule, NOTES.txt,
extraDeploy.yaml added. PSS "restricted" container security context
defaults. Apache-2.0 LICENSE file.
- Database schema bootstrap (#67): a db-bootstrap init container loads
files/schema/<dialect>.sql via mysql/psql, gated on
modsEnabled.sql.enabled + database.bootstrap.enabled; idempotent.
- configurations ConfigMap rendering (#97): templates/configmap/configuration.yaml
materialises the dangling ConfigMap reference the Deployment was mounting.
Renamed configuration→configurations / configurationConfigMap→configurationsConfigMap.
- FreeRADIUS exporter as a separate Deployment under templates/metrics/
(bvantagelimited/freeradius_exporter), with its own Service + NetworkPolicy.
Scrapes the in-cluster status virtual server (sitesEnabled.status.listen
default changed to 0.0.0.0; status now published on the main Service).
- Hard validation via freeradius.validateValues aggregator: metrics.enabled
requires sitesEnabled.status.enabled; tls.enabled requires a configured
cert source. helm install / upgrade / template now fail rather than render
a non-functional release.
- Many template fixes: .Values.resources typo, replicas vs HPA, lowercase
subdir checksum paths, commonAnnotations propagation to pods, individual
checksum gating, ingress.* references purged, st-common.labels.standard
signature standardised across all templates.
- Chart bumped to 1.0.0; appVersion 3.2.7; st-common dep to 0.1.21.
…reshape Builds on the prior 1.0.0 modernization commit (0bd862c). Still unreleased, so this is a single follow-up cut with no backward-compat shims. Backend support: - Bundled PostgreSQL subchart (Bitnami 16.x.x) alongside MariaDB. Picks dialect from modules.sql.dialect; new freeradius.sql.backend.validate rejects two-subchart setups, dialect/subchart mismatches, sqlite+subchart, and no-backend-at-all. - Helpers freeradius.mariadb.{host,port,name,user,secretName,secretKey} renamed to freeradius.sql.* with three-way branching (mariadb -> postgresql -> externalDatabase). externalDatabase.port now defaults to "" and the helper picks 3306/5432 from dialect. New modules (via files/modules/<name> + envvars + helpers/validator where needed): - rest (rlm_rest): connect URI, per-section URI/method/body, HTTP auth (none/basic/digest/bearer), TLS material at /opt/.../certs-rest signed by the chart's shared CA. New freeradius.rest.{tls.*,secretName, secretKey,validate} helpers; mods-rest-password auto-generated when auth != none. - json (rlm_json): stub config, xlat-only. - pam (rlm_pam): one knob (modules.pam.pamAuth, default radiusd). SQL knobs newly piped via env vars: - modules.sql.readGroups and readProfiles (both default true; uncomments the matching directives in files/modules/sql). Top-level key reshape (no shims): - modsEnabled: -> modules: (Helm key); files/mods-available/ -> files/modules/; templates/configmap/mods-enabled.yaml -> modules.yaml; ConfigMap name <release>-mods -> <release>-modules; volume freeradius-mods -> freeradius-modules. - sitesEnabled: -> sites:; files/sites-available/ -> files/sites/; templates/configmap/sites-enabled.yaml -> sites.yaml. K8s resource names (<release>-sites etc.) were already short and unchanged. - database.bootstrap.* -> bootstrap.database.*; helpers freeradius.database.* -> freeradius.bootstrap.database.*. Lets future bootstrap kinds (TLS, users, ...) slot in alongside. Layout: - Exporter NetworkPolicy moved to templates/metrics/NetworkPolicy.yaml, next to the rest of the metrics resources. The complementary ingress rule on the FreeRADIUS pods (allow metrics -> status port) stays in templates/NetworkPolicy.yaml — it's a rule about the FreeRADIUS pod. In-container paths (/etc/freeradius/{mods,sites}-enabled/<name>) and env var names (FREERADIUS_MODS_*) are FreeRADIUS daemon conventions and unchanged. CHANGELOG + README §Upgrading updated with before/after migration snippets for each break (#8 modules rename, #9 sites rename, #10 PostgreSQL + backend selection).
…sql,_validate}.tpl
Refactor only — no values shape changes, no functional changes beyond a
small bootstrap-image-default tweak (see below).
- templates/_helpers.tpl → templates/helpers/_helpers.tpl (move).
Helm globs *.tpl under templates/ so all helpers still load.
- Validation pipeline extracted to templates/helpers/_validate.tpl with a
renamed namespace: freeradius.<area>.validate → freeradius.validate.<area>,
aggregator freeradius.validateValues → freeradius.validate. NOTES.txt
include updated. _helpers.tpl carries a one-line pointer comment.
- SQL backend helpers extracted to templates/helpers/_sql.tpl:
freeradius.{mariadb,postgresql}.fullname + freeradius.sql.{tls.*,host,
port,name,user,secretName,secretKey}. _helpers.tpl carries a one-line
pointer comment in their place.
- bootstrap.database image defaults moved INTO the helper as a per-dialect
dict literal (mysql → mariadb image, postgresql → postgresql image).
values.yaml ships with empty registry/repository/tag so each empty
field falls through to the dialect default at render time. Drops the
repo-string-match auto-swap. Bumped registry to public.ecr.aws/bitnami
and pinned tags to 12.2.2 (mariadb) / 18.4.0 (postgresql) so the images
ship the matching CLI binary required by the bootstrap init container.
- CHANGELOG + README references swept to the new helper names.
- CHANGELOG.md: top section `## 1.0.0 (2026-05-27)` → `## 1.1.0 (2026-05-27)`; intro paragraph rewritten to reflect the actual release body (postgresql subchart, REST/JSON/PAM modules, top-level key cleanups) instead of "matching the adminer playbook". Three other adminer mentions in scattered bullets dropped or reworded. 1.0.3 paragraph at the bottom now points at 1.1.0 as the authoritative release notes. - README.md: §Upgrading heading `### To 1.0.0 (breaking)` → `### To 1.1.0 (breaking)`; every `# After (1.0.0)` snippet marker bumped to 1.1.0. The "matches adminer chart" hint in the gateway-shape migration section is removed. - Chart.yaml: `artifacthub.io/changes` description bumped to "1.1.0 major release" with the actually-shipped feature list (REST/JSON/PAM, key cleanups) instead of just postgresql + UDPRoute.
… preset tweak
- files/sites/tls: comment out `dh_file = ${certdir}/dh` — the chart
doesn't ship a DH params file, so loading it aborts RADSEC startup.
`random_file` stays; operators who want explicit DH params can mount
one and uncomment.
- values.yaml: default `networkPolicy.enabled` to true; change
`resourcesPreset` default to `g-2xsmall`; reflow the
`modules.sql.dialect` doc comment.
Wires rlm_eap into the modules ConfigMap behind `modules.eap.enabled`, sharing one `tls-config tls-common` server cert across the TLS-based methods. Adds a fourth chart-managed TLS context (eap-tls.yaml, signed off the shared internal CA), an auto-generated key passphrase, and a `freeradius.validate.eap` aggregator that rejects incoherent method / defaultType / cert-source combinations.
…; split helpers
- Module files (json/pam/eap) now render through Helm `tpl`: each values map
becomes `key = value` directives via `freeradius.tplvalues.renderConfig`.
json gains a fixed `encode {}` block bound to `modules.json.encode.*`; eap
is reworked to a `modules.eap.methods` list (each `modules.eap.<method>` map
is its block body, inner methods render empty) and adds `peap`; pam drops
the now-redundant `FREERADIUS_MODS_PAM_AUTH` env var.
- snake_case migration of config-shaped values so the renderer emits valid
FreeRADIUS directives: clients (`nas_type`, `virtual_server`, `coa_server`,
`max_connections`, `idle_timeout`) and eap `tlsConfig`
(`random_file`, `cipher_list`, `cipher_server_preference`, `min_version`,
`max_version`, `certificates_secret`, `cert_*`, `private_key_password`).
EAP validator and credentials Secret updated to match.
- extraModules / extraSites passthrough: one ConfigMap + volume per entry,
mounted at mods-enabled/<name> / sites-enabled/<name> (verbatim, no tpl).
- Split templates/helpers/_helpers.tpl into _images.tpl (image + pullSecrets),
_tls.tpl (RADSEC/REST/EAP/gateway/CA), and _utils.tpl (renderConfig). Rename
`freeradius.imagePullSecrets` -> `freeradius.image.pullSecrets`; inline the
metrics exporter image via `st-common.images.image`.
…d ConfigMaps
- Fix `helm template` failure: literal `{{ ... }}` in the eap/json module
header comments was parsed by `tpl` and aborted rendering. Rewrote the
comments in prose (a tpl-rendered file must not contain literal `{{`).
- eap and pam now render into their own ConfigMaps (`<release>-mods-eap`,
`<release>-mods-pam` under templates/modules/) and are mounted directly at
mods-enabled/{eap,pam}, rather than aggregated into `<release>-modules`
where they were rendered but never actually mounted. Adds the matching
Deployment volume/volumeMount/checksum wiring for both.
- Inline the eap config into templates/modules/eap.yaml and delete the now
redundant files/modules/eap (single source of truth).
- Drop the redundant `with` guards around `freeradius.tplvalues.renderConfig`
in eap.yaml — the recursive helper already returns "" for an empty/nil map.
…irectly (snake_case)
- Move sql/rest/json into their own ConfigMaps (templates/modules/<name>.yaml,
mounted at mods-enabled/<name>); delete files/modules/* and the aggregated
configmap/modules.yaml. Deployment now has a per-module volume/mount/checksum
for all five modules and no longer declares the freeradius-modules volume.
- rest: render `.Values.modules.rest.*` directly into the module file, dropping
the FREERADIUS_MODS_REST_* `$ENV{}` indirection — only the password stays as
`$ENV{}` (a secret injected via the Deployment's secretKeyRef). Config keys
renamed to snake_case (connect_uri/connect_timeout/post_auth and
tls.{auto_generated,certificates_secret,cert_*,check_cert,check_cert_cn});
envvars/_tls.tpl/_validate.tpl references updated to match (fixes the
already-broken connectUri/connectTimeout refs). Pool sizing is now tunable via
`modules.rest.pool`, rendered through freeradius.tplvalues.renderConfig.
- eap: top-level timer/session knobs moved to values (timerExpire,
ignoreUnknownEapTypes, ciscoAccountingUsernameBug, maxSessions); cache/verify/
ocsp and the method blocks pass values straight to renderConfig (dropped the
redundant `with` guards now that the helper returns "" for empty maps).
- pam: wrap the renderConfig value under the `pam` block name so it emits a
valid `pam { }` block rather than a bare directive.
- Docs (CHANGELOG/README/values comments/sqlite.sql) updated for the per-module
layout.
…directly
- Add `modules.<name>.existingConfigMap` to all five modules: when set, the
module's ConfigMap template skips rendering and the Deployment volume mounts
the external ConfigMap instead (its checksum annotation is also gated off).
New `freeradius.module.configMapName` helper resolves BYO-or-chart-rendered.
- sql module: render `.Values.modules.sql.*` and the `freeradius.sql.*`
connection helpers directly into templates/modules/sql.yaml, dropping the
FREERADIUS_MODS_SQL_* `$ENV{}` indirection. Only the password stays `$ENV{}`
(a secret, injected by the Deployment via secretKeyRef whenever sql is
enabled). The entire SQL block is removed from the envvars ConfigMap.
- Docs (values comments, _sql.tpl helper doc, CHANGELOG, README upgrade notes)
updated: module config is rendered directly from values; only secrets
(sql/rest passwords, eap private-key passphrase) remain as `$ENV{}`.
Mirror the per-module split for virtual servers: each site renders into its
own `<fullname>-sites-<name>` ConfigMap (templates/sites/<name>.yaml) with a
`sites.<name>.existingConfigMap` BYO override (new `freeradius.site.configMapName`
helper), its own pod volume/mount and per-site checksum annotation. Replaces the
single bundled `configmap/sites.yaml`; `files/sites/` is removed (content inlined).
`default` + `inner-tunnel` always render; `coa`/`status`/`dhcp`/`tls` are gated.
Adds the `sites.dhcp` toggle, wires the inner-tunnel mount, and gates the status
mount on `sites.status.enabled`.
Site config (listen ports/addresses, RADSEC cert/key/CA paths, cipher) now renders
directly from `.Values` into each site ConfigMap; only secrets (status secret,
RADSEC key passphrase, client secret) stay as `$ENV{}` injected via secretKeyRef.
Drops the orphaned `FREERADIUS_SITES_*` env vars from configmap/envvars.yaml
(keeps `STATUS_PORT`, still referenced by the radclient probes).
Also adds the pap module (rlm_pap) following the same per-module ConfigMap pattern.
Remove the inner `pap` EAP method (methods list, the `modules.eap.pap` subsection, and the `default_eap_type: pap` refs in ttls/peap, now commented). Move the `tlsConfig.ocsp.enable` @param next to the `ocsp` block and add commented `verify` examples (tmpdir/client).
…nabled
Wrap every `sql`/`-sql` invocation in the default virtual server (authorize,
accounting, session, post-auth logging, Post-Auth-Type REJECT) in
`{{- if .Values.modules.sql.enabled }}` so the SQL module is only referenced
when it is actually enabled.
…tion
The radclient liveness/readiness/startup probes now render the status port
directly from `.Values.containerPorts.status` instead of
`${FREERADIUS_SITES_STATUS_PORT}`; the status secret stays as `${...}` (injected
via secretKeyRef). Removes the now-unused `FREERADIUS_SITES_STATUS_PORT` entry
from configmap/envvars.yaml.
Replace the condensed default virtual-server body with the upstream 3.2.8
`sites-available/default` (restores the full comments and the commented `dpsk` /
Active-Directory-PAP example blocks). Functional chart customizations preserved:
templated auth/acct listen ports (ipv4 + ipv6) and the sql/eap module-call gates
on `modules.{sql,eap}.enabled`.
Adopts upstream defaults: `idle_timeout = 900` on the first auth listener, and
the `unix` (authorize), `sql` (session/Simultaneous-Use) and `eap` (pre-proxy)
calls revert to commented-out as upstream ships them.
Also reorder `sites.{status,tls}.existingConfigMap` to sit right after `enabled`.
…xisting CMs
Sites:
- Mount all virtual servers from a single `projected` volume (chart sites +
extraSites) at sites-enabled/, replacing the per-site configMap volumes and
subPath mounts. Chart site ConfigMaps are single-key so they project whole;
extraSites keep `items` since their data key may differ from the on-disk path.
- Add `sites.default.enabled` / `sites.innerTunnel.enabled` toggles (default
true) gating each site's ConfigMap, projected source, mount and checksum.
Probes:
- Move the radclient status-check scripts into a `<release>-scripts` ConfigMap
(templates/configmap/scripts.yaml) mounted at `healthCheck.mountPath` (/health);
the default startup/liveness/readiness probes now run `sh <mountPath>/<script>`.
- New `healthCheck.{mountPath,startupScript,livenessScript}` values drive the
mount path, the probe command paths, and the ConfigMap data keys.
extraModules / extraSites:
- Now mount existing ConfigMaps you provide (`{name, existingConfigMap, key?}`)
instead of rendering inline `config`. Removed templates/configmap/extra-modules.yaml
and extra-sites.yaml and their checksum annotations.
…onf; sites at /opt - db-bootstrap: replace the helper-rendered schema command with an in-container `case "$DB_DIALECT"` (mysql/postgresql/skip) and a new DB_DIALECT env; gate the init container and db-schema volume on the dialect directly. Remove the unused freeradius.bootstrap.database.cmd helper (and its stale _images.tpl reference). - Bundle a stock 3.2.8 files/radiusd.conf (rendered into the configurations ConfigMap, mounted at /etc/freeradius/radiusd.conf) and add a sites.configurations inline draft. - Mount the projected sites volume at /opt/startechnica/freeradius/sites-enabled.
…nclude sites from /opt Move the inline radiusd.conf from the unwired `sites.configurations` to the top-level `configurations` key that the configurations ConfigMap actually reads, so the rendered radiusd.conf `$INCLUDE /opt/startechnica/freeradius/sites-enabled/` now matches where the projected sites volume is mounted.
…rap.sh in scripts CM - relocate volumePermissions config + init container under bootstrap.* - bundle db-bootstrap.sh into the scripts ConfigMap, mounted via subPath - drop healthCheck.* indirection; fixed script names under /scripts - add sites.includeDir; probes invoke scripts from /scripts
…t; chmod 0711 - add prepare-sites init container that copies the read-only projected virtual servers into a writable emptyDir and sets sites-enabled to 0711 - rename projected volume to freeradius-sites-tmp; freeradius-sites is now the emptyDir backing sites.includeDir in the main container - drop the unreachable chmod of sites.includeDir from volume-permissions
The $needsDbBootstrap assignment kept a trailing -}} that trimmed the
newline before `initContainers:`, gluing it onto the serviceAccountName
value after the wrapping `{{- if }}` was removed. Use }} so the newline
is preserved.
…m names - mount freeradius-sql-tls at /opt/startechnica/freeradius/certs-sql (readOnly), resolving the path collision with the RADSEC freeradius-tls mount at .../certs - point sql TLS cert path helpers at certs-sql with native tls.crt/tls.key/ca.crt filenames, dropping the bespoke sql-*.crt secret item renaming - align hardcoded mongo ca_dir / ca_path to /opt/startechnica/freeradius/certs-sql
…ad sqlite/shared-certs volumes
- keycloak.* integration with two modes: `lua` (self-contained rlm_lua doing
ROPC + introspection -> control:Class, with unlang keycloak_authorize /
keycloak_roles for role->reply mapping) and `rest` (auth-only rlm_rest ROPC).
Gated by keycloak.mode and wired into the default site's authorize section
via wireDefaultSite. Client secret injected via $ENV{KC_CLIENT_SECRET}.
- modsConfig: per-subdir mods-config ConfigMaps projected at
/etc/freeradius/mods-config/<subdir>/.
- sites.includeDir / policies.includeDir values.
- remove the redundant freeradius-sqlite emptyDir (the SQLite db lives on the
data volume) and the dead read-only shared-certs emptyDir.
…3 history, fix breaking-change baseline - document keycloak / modsConfig / prepare-sites / certs-sql / volume removals under the unreleased 1.1.0 section - backlink GitHub issues #84 and #96 (already-fixed, previously unlinked) - backfill per-version history for 1.0.3 down to 0.1.0, reconstructed from the freeradius-<version> git tags - baseline the breaking-change notes against 1.0.3 (the latest pre-1.1.0 release, which still used modsEnabled/sitesEnabled/ingress/configuration), not solely 0.x
- add a `lint` job using helm/chart-testing-action (`ct lint`), linting only charts changed vs the default branch - trigger the workflow on push to any branch; gate the `release` job with `if: github.ref == 'refs/heads/main'` so publishing still only happens on main
chart-testing 3.12.0 bundles a yamale that references ast.Num (removed in Python 3.12); setup-python with "3.x" pulled 3.14, crashing Chart.yaml schema validation with `AttributeError: module 'ast' has no attribute 'Num'`.
Add .github/workflows/** to the push paths so CI changes re-run the lint job (the charts/** filter previously skipped workflow-only commits).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Major 1.1.0 release for the
freeradiuschart — end-to-end modernization.Breaking: see
charts/freeradius/CHANGELOG.mdand README → "Upgrading → To1.1.0". These migrations apply to any pre-1.1.0 release (1.0.3 still used the old
keys).
Highlights:
modsEnabled:→modules:,sitesEnabled:→sites:,ingress:removed,tls.autoGenerator→tls.certManager.*,database.bootstrap.*→bootstrap.database.*,configuration(s)rename./ ReferenceGrant / ListenerSet) plus the istio path; chart-internal shared
self-signed CA persisted via
lookup.(EAP-TLS / EAP-TTLS) — each its own ConfigMap mounted at
mods-enabled/<name>.keycloak.mode: lua | rest) + genericmodsConfigfor custom
mods-configdata.freeradius_exporterDeployment + Service +ServiceMonitor + PrometheusRule (not a sidecar).
prepare-sitesinit (0711 sites dir);SQL TLS moved to
certs-sql; removed deadfreeradius-sqlite/shared-certsvolumes.
ct linton every branch;releasejob gated tomain.Closes #67
Closes #96
Closes #97
(#84 — initContainers from values — already closed; fixed here too.)
Test plan
helm lintpasses;ct lintgreen on the branch (CI).helm templaterenders: default; SQL mysql/postgresql/sqlite; RADSEC TLS;EAP; REST; metrics; Keycloak
mode=luaandmode=rest.image with
rlm_lua+lua-cjson+luasec).